template<typename T> bool func( typename std::enable_if< std::is_enum<T>::value, T >::type &t, int x )
T used above in an irreducible context. This means that he will not subtract T , since he (in the general case) requires a permutation of the arbitrary turing-complete transformation, which is impossible.
What func has is that the first argument is enum class Bar and the second is int . From this, you expect it to infer T
As long as setting T on the enum class Bar fixes the problem, C ++ does not guess. This pattern matches.
Suppose we had:
template<class T> struct blah { using type=int; }; template<> struct blah<int> { using type=double; };
then
template<class T> bool func( typename blah<T>::type );
If someone goes from int to func , what type should be inferred for T ? This is an example of a toy: foo<T>::type can execute the Turing-complete algorithm to match T with the type in question. Inverting this, or even determining whether the converse is ambiguous, is generally not possible. Therefore, C ++ does not even try even in simple cases, since the edge between simple and complex quickly becomes fuzzy.
To fix the problem:
template<class T,class=typename std::enable_if< std::is_enum<T>::value >::type> bool func( T &t, int x ) { }
now T used in the deduced context. SFINAE still occurs, but does not block the deduction of the pattern type.
Or you can wait for C ++ 1z concepts that automate the design described above (mostly).
Considering a related question, an easy way to solve your problem is to send tags.
template<typename T> bool func(T &t, int x) {
However, I would like to have three different bodies of functions:
We have 3 cases:
T - listing
T unsigned char
All the rest
so send:
namespace details { template<class T> bool func( T& t, int x, std::true_type , std::false_type ) { } template<class T> bool func( T& t, int x, std::false_type, std::true_type ) { } template<class T> bool func( T& t, int x, std::false_type, std::false_type ) {
normal overload rules are now used to choose between three functions. If you somehow have an enum type and an unsigned char (impossible), you will get a compile-time error.