Lets have a look at the simple example of enable_if
usages
template <bool, typename T = void>
struct enable_if
{
};
template <typename T>
struct enable_if<true, T>
{
typedef T type;
};
y
would be int
, since T
is our "enabled" type.template <typename T, typename Y = typename std::enable_if<std::is_integral<T>::value, T>::type>
void do_stuff(T t)
{
(void)t;
Y y;
std::cout << typeid(y).name() << std::endl;
}
do_stuff(15); // int
y
will be deduced to whatever the type of the actual argument is going to betemplate <typename T, typename Y = typename std::enable_if<std::is_integral<T>::value, T>::type>
void do_stuff(T t, Y y)
{
(void)t;
std::cout << "do_stuff integral\n";
std::cout << typeid(y).name() << std::endl;
}
do_stuff(15, 14.3); // double
So my question is:
What could be the rules that forces compiler to prioritize deduction of y
from the actual argument passed and ignore the enabled type
from enable_if
?
Default template argument is used only when template argument isn't specified explicitly and template parameter can't be deduced. For this case, Y
could be deduced from 14.3
as double
, then default argument won't be used. Similarly, in the 1st sample you can also bypass the check of std::enable_if
by specifying template argument.
do_stuff<int, double>(15); // double
BTW you can add non-type template parameter using std::enable_if
in type declaration to make check taking effect all the time.
template <typename T, typename Y, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
void do_stuff(T t, Y y)