Это способ достижения SFINAE : функция может быть выбрана только в том случае, если все типы могут быть заменены должным образом.
Если std::is_integral<T>::value
равно false
(т. Е. T
не является целочисленным типом), std::enable_if<...>
не будет иметь члена type
, поэтому произойдет ошибка замены, и эта функция не будет вызываться (и может быть другая перегрузка).
Если T
является целочисленным типом, то typename std::enable_if<std::is_integral<T>::value >::type
будет void
, поэтому второй параметр будет иметь тип void*
. Это безымянный параметр со значением по умолчанию nullptr
, поэтому вам не нужно его указывать.
Итак, вы бы назвали его так:
foo2(0); // T is `int`, which is integral, so the function can be called
foo2(0, nullptr); // Same as above, but explicitly passing the parameter
// Can't call the function, because `double` is not integral,
// so second type is a substitution failure
// foo2(0.0);
Обратите внимание, что это обычно может быть достигнуто либо с помощью параметра шаблона по умолчанию:
// Same `void*` if integral, else substitution failure
template<class T, typename std::enable_if<std::is_integral<T>::value >::type* = nullptr>
T foo2(T t)
{
return t;
}
// Or alternatively with an `int` if integral, else substitution failure
template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
T foo2(T t)
{
return t;
}
, либо непосредственно в типе возвращаемого значения:
template<class T>
// Returns `T` if it's integral, else substitution failure
typename std::enable_if<std::is_integral<T>::value, T>::type foo2(T t)
{
return t;
}
А в C ++ 20 вы можете использовать requires
(или std::integral
концепция в данном случае)
template<class T> requires std::is_integral_v<T>
T foo2(T t)
{
return t;
}
template<std::integral T>
T foo2(T t)
{
return t;
}