SFINAE
는 "Substitution Failure Is Not An Error"의 약어로, C++ 템플릿 메타프로그래밍에서 사용되는 원칙.
SFINAE
는 템플릿 인자 대입(substitution) 중에 실패(failure)하는 것이 오류(error)가 아니라는 것을 의미함. 따라서, 템플릿 인자 대입이 실패하면 해당 템플릿 함수나 클래스는 후보에서 제외된다.위 과정에서 함수 템플릿을 인스턴스화할 때, 인자나 결과가 유효하지 않다면 컴파일 에러를 뱉는 대신에 결과물에서 인스턴스화한 것을 지운다.
long multiplication(int i, int j) { return i * j; } template <class T> typename T::multiplication_result multiplication(T t1, T t2) { return t1 * t2; } int main(void) { multiply(4,5); }
위의 코드를 보면
multiplication
함수가 있고 템플릿화한multiplication
함수가 있다.
multiplicatio
함수를 main에서 호출하려하면 컴파일러는 첫번째 함수가 더 적합하더라도 템플릿화된 함수를 인스턴스화 하려고 시도한다.
이 과정에서int::multiplication_result
라는 유효하지않은 자료형이 생성되지만SFINAE
로 인해 유효하지않은 인스턴스화는 무시된다.
이 때SFINAE
는enable_if
를 사용하여 구현이 가능하다.
template<bool B, class T = void> struct enable_if {}; template<class T> struct enable_if<true, T> { typedef T type; };
enable_if
의 템플릿 첫 인자로true
가 오면,enable_if
의 구조체 안에는type
이라는 자료형이 생기고 그 외 다른것이 온다면 아무것도 생기지않는다.
이를 사용해 결과값에따라type
이 생겼냐 생기지 않았냐를 사용하여 유효성을 판별할 수 있다.template<typename T, std::enable_if<std::is_integral<T>::value, int>::type = 0> void foo(const T& bar) { isInt(); }
위는 사용예시이며
is_integral
은T
가integral
계열일때true
를, 아닐때는false
를 반환한다.
integral
계열일때만::type
을 호출할 수 있으므로integral
계열이 아니라면foo
함수는 적합하지 않은것으로 판별되어 인스턴스화되지 않는다.참고로 템플릿의 두번째 인자
std::enable_if<std::is_integral<T>::value, int>::type = 0
으로 디폴트 값이 정해져있다.
두번째 인자는 굳이 입력하지 않고foo< int >(1);
이런식으로 호출이 가능하다.
디폴트 값을 설정해놓지 않았더라면, 템플릿에서는 두개의 변수를 필요로 했을 것이다.
https://yechoi.tistory.com/93
https://stackoverflow.com/questions/25284499/how-does-stdenable-if-work
https://modoocode.com/295