Another question of type "who's right between g++ and clang++?" for C++ standard gurus.
Suppose we want apply SFINAE to a variable template to enable the variable only if the template type fulfill a certain condition.
By example: enable bar
if (and only if) the template type has a foo()
method with a given signature.
Using SFINAE through an additional template type with default value
template <typename T, typename = decltype(T::foo())>
static constexpr int bar = 1;
works for both g++ and clang++ but has a problem: can be hijacked explicating the second template type
So
int i = bar<int>;
gives a compilation error where
int i = bar<int, void>;
compile without problem.
So, from the bottom of my ignorance about SFINAE, I've tried enabling/disabling the type of the same variable:
template <typename T>
static constexpr decltype(T::foo(), int{}) bar = 2;
Surprise: this works (compile) for g++ but clang++ doesn't accept it and give the following error
tmp_003-14,gcc,clang.cpp:8:30: error: no member named 'foo' in 'without_foo'
static constexpr decltype(T::foo(), int{}) bar = 2;
~~~^
The question, as usual, is: who's right ? g++ or clang++ ?
In other words: according the C++14 standard, SFINAE can be used over the type of a variable template ?
The following is a full example to play with
#include <type_traits>
// works with both g++ and clang++
//template <typename T, typename = decltype(T::foo())>
//static constexpr int bar = 1;
// works with g++ but clang++ gives a compilation error
template <typename T>
static constexpr decltype(T::foo(), int{}) bar = 2;
struct with_foo
{ static constexpr int foo () { return 0; } };
struct without_foo
{ };
template <typename T>
constexpr auto exist_bar_helper (int) -> decltype(bar<T>, std::true_type{});
template <typename T>
constexpr std::false_type exist_bar_helper (...);
template <typename T>
constexpr auto exist_bar ()
{ return decltype(exist_bar_helper<T>(0)){}; }
int main ()
{
static_assert( true == exist_bar<with_foo>(), "!" );
static_assert( false == exist_bar<without_foo>(), "!" );
}
T::foo()
doesn't have a return typeR
with an overloadedoperator,(R,int)
... – Frailtemplate <class T, decltype(T::foo ()) * = nullptr>
would invoke sfinae this one I'm not so sure... – Violistbar
that is defined if (and only if) the first one isn't defined. – Sunglass