In response to .. some other question somewhere, I wrote this code.
struct no_type{};
template<typename T> struct has_apply {
static decltype(T().apply<0u>(double())) func( T* ptr );
static no_type func( ... );
static const bool result = !std::is_same<no_type, decltype(func(nullptr))>::value;
};
class A {
public:
template< unsigned n >
void apply( const double& );
};
class B {
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
std::cout << std::boolalpha << has_apply< B >::result << '\n';
std::cin.get();
return( 0 );
}
Now it seems to me that result should be true if T offers a non-static member function “apply” that accepts a double rvalue and a template parameter literal, and false otherwise. However, the example given actually fails to compile for class B, when compiling has_apply<B>. Shouldn’t the fact that the substitution of T failed in the decltype statement mean that it simply calls the other func? Isn’t that kind of the point of SFINAE?
Solved in the most ridiculous, pointless fashion ever:
struct no_type{};
template<typename T> struct has_apply {
template<typename U> static decltype(U().apply<0u>(double())) func( U* );
template<typename U> static no_type func( ... );
static const bool result = !std::is_same<no_type, decltype(func<T>(nullptr))>::value;
};
class A {
public:
template< unsigned n >
void apply( const double& );
};
class B {
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
std::cout << std::boolalpha << has_apply< B >::result << '\n';
std::cin.get();
return( 0 );
}
SFINAE applies when substitution fails for a function template’s template parameter, not for a class template’s template parameter that has the (non-template) function in question as a member, as is in your case.
After fixing that, you should at least change
decltype(T().apply<0u>(double()))todecltype(T().template apply<0u>(double()))becauseT()expression is of a dependent type. The reason for that is this: when the compiler first seesT().apply<0u>, it doesn’t know anything aboutTyet, so how should it parse the tokensapplyand<after.?applymight be a member template, and then<would start the argument list for it. OTOHapplymight instead be a non-template member (e.g. a data member), and then<would be parsed as ‘less-than’ operator. There is an ambiguity, and it’s still too early for the compiler to resolve that at this point. There is a need for a disambiguation mechanism a programmer could use to tell the compiler whatapplyis expected to be: a template or not. And here comes the.template(or->template, or::template) construct to the rescue: if it’s present, the compiler knows it should be a template member, otherwise if it’s not present then the compiler knows the member shouldn’t be a template.Finally here’s an example I created that works correctly and produces the desired results on g++ 4.5.0 with
-std=c++0x:Output is:
Now if you remove both
.templatefrom the firstf()definition, then the output becomes:Which is to indicate substitution failure for
class Aas it doesn’t have any non-template member namedapply. SFINAE in action!