SFINAE (Substitution Failure Is Not An Error) — ключевой механизм специализации шаблонов в C++. Если при выборе шаблона определение становится некорректным (например, когда подстановка типа приводит к ошибке на этапе выбора шаблона), то это не ошибка компиляции, а просто делает шаблон недоступным для выбора.
SFINAE лежит в основе инструментов типа std::enable_if, различных детекторов типа (type traits), реализует паттерн tag dispatching.
Корректный пример:
#include <type_traits> // Для целых template<typename T> typename std::enable_if<std::is_integral<T>::value, void>::type foo(T) { std::cout << "Integral "; } // Для остальных template<typename T> typename std::enable_if<!std::is_integral<T>::value, void>::type foo(T) { std::cout << "Not integral "; }
Некорректное использование: Можно случайно получить двусмысленность вызова (ambiguous overload) или вызвать ошибку компиляции, если неаккуратно описать условия для std::enable_if или специализации.
Можно ли использовать SFINAE для выбора между перегрузками обычных (не шаблонных) функций?
Ответ: Нет, SFINAE применяется только к шаблонам функций или классов. Для обычных перегруженных функций SFINAE не работает. Часто ошибочно пытаются написать std::enable_if в параметрах обычной функции, что не приводит к выбору, а просто делает сигнатуру неопределённой.
Пример ошибочного варианта:
void foo(int, typename std::enable_if<true, int>::type* = nullptr) {} // Ошибка: не шаблон
История
В библиотеке сериализации при реализации шаблонных функций с SFINAE ошибочно не учли пересечение условий для двух специализаций. Результат — ситуация ambiguous overload и неспособность собрать модуль при появлении нового типа данных.
История
В старем коде библиотеки boost::asio при ошибочной реализации SFINAE (через dependent false в static_assert) появлялись сообщения об ошибках, которые не читались: компилятор разворачивал все шаблоны вместо удаления некорректных вариантов. Исправили через отдельные enable_if на уровне сигнатур.
История
При портировании поиска алгоритмов по типам через SFINAE на старый компилятор (MSVC 2012) команда столкнулась с тем, что декомпозиция типов выполнялась некорректно, и выбранный шаблон принимал неверный тип. Проверку решали через type traits до компиляции, устранив подстановку в самом шаблоне.