[C++] enable_if와 SFINAE

J_JEON·2023년 3월 10일
0

SFINAE란

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로 인해 유효하지않은 인스턴스화는 무시된다.
이 때 SFINAEenable_if를 사용하여 구현이 가능하다.

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_integralTintegral계열일때 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

profile
늅늅

0개의 댓글