SFINAE only works if substitution in argument deduction of a template argument makes the construct ill-formed. There is no such substitution.
I thought of that too and tried to use
std::is_same< T, int >::value
and! std::is_same< T, int >::value
which gives the same result.
That’s because when the class template is instantiated (which happens when you create an object of type Y<int>
among other cases), it instantiates all its member declarations (not necessarily their definitions/bodies!). Among them are also its member templates. Note that T
is known then, and !std::is_same< T, int >::value
yields false. So it will create a class Y<int>
which contains
class Y<int> {
public:
/* instantiated from
template < typename = typename std::enable_if<
std::is_same< T, int >::value >::type >
T foo() {
return 10;
}
*/
template < typename = typename std::enable_if< true >::type >
int foo();
/* instantiated from
template < typename = typename std::enable_if<
! std::is_same< T, int >::value >::type >
T foo() {
return 10;
}
*/
template < typename = typename std::enable_if< false >::type >
int foo();
};
The std::enable_if<false>::type
accesses a non-existing type, so that declaration is ill-formed. And thus your program is invalid.
You need to make the member templates’ enable_if
depend on a parameter of the member template itself. Then the declarations are valid, because the whole type is still dependent. When you try to call one of them, argument deduction for their template arguments happen and SFINAE happens as expected. See this question and the corresponding answer on how to do that.