2
votes

According to the definition of enable_if struct :

template<bool B, class T = void>
struct enable_if {};

template<class T>
struct enable_if<true, T> { typedef T type; };

I am wondering how

template<class T>
T foo(T t, typename std::enable_if<std::is_integral<T>::value >::type* = 0) 
{
    return t;
}

particularly :

typename std::enable_if<std::is_integral<T>::value >::type

could be invoked without specified type T, in case std::is_integral<T>::value equal true. In this case the specialization of std::enable_if will be called and in this definition there is no default template parameter.

Is it due to deduce template parameter mechanism ? If yes why specified a default paramater for not specialization definition ?

2

2 Answers

2
votes

Your question is a bit cryptic, but as I understand it:

I am wondering how ... could be invoked without specified type T

  1. It won't; The foo and enable_if templates will only be instantiated when the user needs their instantiations (implicitly or explicitly) with specific values for T. So T is always specified.

  2. Default template parameters are only featured on "base" template definitions (ie. not specializations). That is why you only see it on the first declaration of enable_if. However, they affect all specializations (basically, if you instantiate enable_if<X>, the compiler sees you have not provided one of the arguments for the base template and tries to match all specializations with parameter list <X, void>).

BTW the second template argument is used to get a different type out of enable_if than void:

std:enable_if<1, int>::type f();

would be just int f().

1
votes

The purpose of the enable_if template is to remove function templates from the overload set. By itself, your example is not terribly useful, except that it will refuse instantiation for non-integral types with a compiler error. But if you also wrote a second overload, for example with the reverse condition, then foo(1) and foo(1.0) would both only find one single viable overload and there's no ambiguity.

In fact, think about this again: While deducing the arguments for foo(1.0), the first version (the one you wrote) will actually be erroneous, since there is no member type ::type. However, this is not a hard compiler error, but only a so-called "substitution failure" – and that is not an error. It simply removes the entire template from consideration.

As a side note, there's a related use for enable_if in class templates to help disambiguate speciali­za­tions, also using default arguments. It looks something like template <typename T, typename = typename std::enable_if<some_condition>::type> ...