I was just using SFINAE to select function templates when I had the glorious idea to encapsulate std::enable_if
in a struct like this
template<typename T, typename U>
struct EnableWhenEqual
{
typedef typename std::enable_if<std::is_same<T, U>::value>::type type;
};
and then use it, for example, like this
template<typename T, typename U, typename Enable = EnableWhenEqual<T,U>::type >
void foo(T&& t, U&& u)
{
if (std::is_same<T,U>::value)
std::cout << "OK, overload allowed." << std::endl;
else
std::cout << "Bad. Should not compile!" << std::endl;
}
However, this doesn't work, as one sees by invoking
foo(1,1); //prints "OK, overload allowed"
foo(1,2.0); //prints "Bad, should not compile", but obviously does
On the other hand, by trying to create
EnableWhenEqual<int,int>(); //compiles
EnableWhenEqual<int,double>(); //does not compile because type does not exist
one obtains a compiler error ("type is not a member of std::enable_if").
What is the reason for this behaviour? I'm asking because from my little SFINAE knowledge I would have thought that an error in the type-deduction leads to exclusion of the overload ... ?
For completeness, the above problem can be solved using template aliasing
template <typename T, typename U>
using EnableWhenEqual = typename std::enable_if<std::is_same<T,U>::value>::type;
Is there also an alternative using a struct instead of a template alias?
EDIT: Here I mean an implementation which solves the general problem. For example, this here
template<typename T, typename U, bool B, typename C=void>
struct EnableWhenEqual {};
template<typename T, typename U, typename C>
struct EnableWhenEqual<T,U,std::is_same<T,U>::value>
{
typedef typename C type;
};
don't works for me because the partial specialization needs a simple identifier. If it would, one could replace std::is_same
by general structs Condition<T,U>
. Any alternatives?
This should do the trick:
template<typename T, typename U>
struct EnableWhenEqual : std::enable_if<std::is_same<T, U>::value>
{
};