Понимание SFINAE

Насколько я знаю, SFINAE означает, что ошибки замены не приводят к ошибкам компиляции, а просто удаляют прототип из списка возможных перегрузок.

Что я не понимаю: почему это SFINAE:

template <bool C, typename T = void> struct enable_if{};
template <typename T> struct enable_if<true, T> { typedef T type; };

Но это не так?

template <bool C> struct assert;
template <> struct assert<true>{};

По моему мнению, основная логика здесь идентична. Этот вопрос возник из комментариев к этому ответу.

Ответ 1

В С++ 98 SFINAE выполняется либо с типом возвращаемого значения, либо с аргументом функции dummy с параметром по умолчанию

// SFINAE on return type for functions with fixed arguments (e.g. operator overloading)
template<class T>
typename std::enable_if< std::is_integral<T>::value, void>::type
my_function(T const&);

// SFINAE on dummy argument with default parameter for functions with no return type (e.g. constructors)
template<class T>
void my_function(T const&, std::enable_if< std::is_integral<T>::value, void>::type* = nullptr);

В обоих случаях подстановка T, чтобы получить вложенный тип type, является сущностью SFINAE. В отличие от std::enable_if, ваш шаблон assert не имеет не имеет вложенного типа, который может использоваться в подстановочной части SFINAE.

Подробнее см. Джонатан Вакели презентация ACCU 2013, а также для выражения С++ 11 SFINAE. Среди других (как отмечено в комментариях @BartekBanachewicz в комментариях) теперь также можно использовать SFINAE в аргументах по умолчанию шаблона функции

// use C++11 default function arguments, no clutter in function signature!
template<class T, class dummy = typename std::enable_if< std::is_integral<T>::value, void>::type>
void my_function(T const&);