language_sfinae

language_sfinae (대입 실패는 오류가 아니다, SFINAE)

"Substitution Failure Is Not An Error"의 약자예요. 함수 템플릿 오버로드 해석 중, 템플릿 매개변수에 명시적·추론된 타입을 대입(substitute)하다 실패하면 컴파일 오류를 내는 대신 그 특수화를 오버로드 집합에서 제외하는 규칙이에요. 템플릿 메타프로그래밍에서 널리 쓰여요.

출처: cppreference

본문

설명

함수 템플릿 매개변수의 대입(템플릿 인자로 치환)은 두 번 일어나요.

  • 명시적으로 지정된 템플릿 인자는 템플릿 인자 추론 전에 대입돼요.
  • 추론된 인자와 기본값으로 얻은 인자는 템플릿 인자 추론 후에 대입돼요.

대입은 다음 위치에서 일어나요.

  • 함수 타입에 사용된 모든 타입(반환 타입과 모든 매개변수 타입 포함)
  • 템플릿 매개변수 선언에 사용된 모든 타입
  • 부분 특수화의 템플릿 인자 목록에 사용된 모든 타입
  • 함수 타입에 사용된 모든 표현식
  • 템플릿 매개변수 선언에 사용된 모든 표현식
  • 부분 특수화의 템플릿 인자 목록에 사용된 모든 표현식

대입 중 어떤 것이 잘못된 타입·표현식을 만들면(예: 존재하지 않는 타입 멤버를 참조), 그 특수화는 오류 없이 오버로드 집합에서 제거돼요. 이 때문에 같은 이름의 대안 템플릿 중 하나만 유효한 경우에도 컴파일이 성공할 수 있어요.

전형적인 용도로는 std::enable_ifstd::void_t를 써서, 특정 조건이 만족될 때만 함수가 오버로드 해석에 참여하도록 하는 거예요.

template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type
foo(T) { /* 정수 타입 전용 */ }

template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type
foo(T) { /* 그 외 타입 전용 */ }

SFINAE는 템플릿 인자를 치환할 때 생기는 직접적인 실패에만 적용되고, 함수 본문의 오류에는 적용되지 않아요.

더 알아보기 (Learn more)

cppreference