Microsoft's documentation there is as clear as dirt. Use instead.
Providing a function template with an undefined form default parameter:
typename enable_if<your_condition, void **>::type = nullptr
(as the MS scribe suggests), it is useful in the case - and only in the case - you want to write several overloads of the function template with different behaviors that are controlled by one or more template arguments. Then by replacing your_condition condition expressing the corresponding requirement for the template argument (s), you can enroll SFINAE . to select the specific overload that you want to create for the given template arguments.
The SFINAE parameter — let this cause that — is an unused instantiated function; it exists solely to provoke SFINAE in the function overload resolution pattern. Therefore, it can be nameless, and therefore, it must be defaulted: this should not force you to provide an additional, useless argument when you call the function template.
For instance:
#include <type_traits> #include <iostream> template <typename T> T foo(T && t, typename std::enable_if<std::is_same<T,int>::value, void **>::type = nullptr) { std::cout << "Doubling " << t << " gives " << (t + t) << std::endl; return t + t; } template <typename T> T foo(T && t, typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr) { std::cout << "Squaring " << t << " gives " << (t * t) << std::endl; return t * t; } using namespace std; int main() { cout << foo(2) << endl; cout << foo(3.3) << endl; return 0; }
Exit:
Doubling 2 gives 4 4 Squaring 3.3 gives 10.89 10.89
In these two overloads of the foo function template, the first doubles enter the argument T , and the second doubles the square of its argument, and the SFINAE parameter is used to determine whether the doubling overload will repeat if T is int and that squaring will be chosen differently.
When T is int , the condition is:
!std::is_same<T,int>::value
which controls the SFINAE squaring overload parameter is false. as a result, a type specifier:
typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr
unable to compile. This is a replacement failure in pattern resolution. Substituting int for T in quadratic overload is not viable. Thus, it is excluded from work, and there is only a doubling reset to create an instance of a function call.
When T (say) is double , not int , the exact opposite happens and only the quadratic overload can withstand the resolution of the template. Call foo(2) and you get a double. Call foo(3.3) and you will get a square.
The MS MS of SFINAE is useless here.
template< bool B, class T = void > struct enable_if;
according to C ++ 11 Standard and later, the default is T - void . So for example:
typename std::enable_if<some_condition, void **>::type = nullptr
can also be shortened to:
typename std::enable_if<some_condition>::type * = nullptr
And with C ++ 14, the standard has:
template< bool B, class T = void > using enable_if_t = typename enable_if<B,T>::type
Thus, the same SFINAE parameter can be further reduced to:
std::enable_if_t<some_condition> * = nullptr
To apply the SFINAE function template parameter to the case that you indicated in your message, you should write:
enum ops { add, multiply }; template<ops Op> int op(int const & lhs, int const & rhs, std::enable_if_t<Op == add> * = nullptr) { return lhs + rhs; } template<ops Op> int op(int const & lhs, int const & rhs, std::enable_if_t<Op == multiply> * = nullptr) { return lhs * rhs; } ... auto i = op<add>(2,3); auto j = op<multiply>(2,3); ...