대체 실패는 오류가 아닙니다.
Substitution failure is not an error치환 실패는 오류가 아닙니다(SFINAE). 템플릿파라미터의 비활성 치환 자체가 오류가 아닌 C++의 상황을 말합니다.David Vandevoorde는 관련 프로그래밍 [1]기술을 설명하기 위해 SFINAE라는 약어를 처음 도입했습니다.
특히 과부하 해결 후보 세트를 작성할 때 해당 세트의 일부(또는 모든) 후보는 대응하는 템플릿파라미터 대신 (잠재적으로 추론될 가능성이 있는) 템플릿 인수를 사용하여 인스턴스화된 템플릿의 결과일 수 있습니다.특정 템플릿에 대한 일련의 인수 치환 중에 오류가 발생하면 C++ 표준이 그러한 [2]처리를 허가하는 경우, 컴파일러는 컴파일 오류로 정지하는 대신 후보 집합에서 잠재적인 과부하를 제거합니다.1개 이상의 후보가 남아 과부하 해결에 성공하면 호출이 적절하게 이루어집니다.
예
다음으로 SFINAE의 기본 인스턴스를 나타냅니다.
구조 시험 { 유형화된 인트 후우; }; 템플릿 <>타이프네임 T> 무효 f(타이프네임 T::후우) {} // 정의 #1 템플릿 <>타이프네임 T> 무효 f(T) {} // 정의 #2 인트 주된() { f<>시험>(10); // 1번 콜 f<>인트>(10); // 2번 콜오류 없음(int::foo가 없는 경우에도) // SFINAE 덕분입니다. }
여기서 정규화된 이름에 클래스 이외의 유형을 사용하려고 합니다(T::foo
)는 다음 항목에 대한 차감 실패의 원인이 됩니다.f<int>
왜냐면int
이름이 붙은 중첩 유형이 없습니다.foo
그러나 유효한 함수가 후보 함수 집합에 남아 있기 때문에 프로그램은 잘 형성되어 있습니다.
SFINAE는 관련 없는 템플릿 선언이 표시될 때(예를 들어 헤더 파일 포함) 잘못된 형식의 프로그램을 만드는 것을 피하기 위해 처음 도입되었지만, 많은 개발자들은 나중에 컴파일 시간 인스펙션에 이 동작이 유용하다는 것을 알게 되었다.구체적으로는 템플릿이 인스턴스화 시 템플릿 인수의 특정 속성을 결정할 수 있습니다.
예를 들어 SFINAE를 사용하여 유형에 특정 typedef가 포함되어 있는지 여부를 확인할 수 있습니다.
#실패하다 <iostream> 템플릿 <>타이프네임 T> 구조 has_sysef_foobar { // 유형 "yes"와 "no"는 서로 다른 크기를 가집니다. // size of(yes) == 1 및 size of(no) == 2입니다. 유형화된 차 네.[1]; 유형화된 차 아니요.[2]; 템플릿 <>타이프네임 C> 정적인 네.& 시험(타이프네임 C::푸바*); 템플릿 <>타이프네임> 정적인 아니요.& 시험(...); // 호출 테스트 결과의 "sizeof"(nullptr)가 다음과 같은 경우 // size of(yes), 첫 번째 오버로드가 작동하며 T에는 다음과 같은 이름의 중첩 유형이 있습니다. // foobar. 정적인 컨스턴트 부울 가치 = 크기(시험<>T>(특수)) == 크기(네.); }; 구조 후우 { 유형화된 흘러가다 푸바; }; 인트 주된() { 표준::외치다 << > 표준::부루알파; 표준::외치다 << > has_sysef_foobar<>인트>::가치 << > 표준::끝; // false 출력 표준::외치다 << > has_sysef_foobar<>후우>::가치 << > 표준::끝; // true 출력 }
언제T
네스트된 유형이 있습니다.foobar
정의, 첫 번째의 인스턴스화test
동작하고 늘 포인터 상수가 정상적으로 전달됩니다.(그리고 그 결과의 표현 유형은 다음과 같습니다).yes
동작하지 않는 경우는, 2번째의 기능 밖에 사용할 수 없습니다.test
그 결과 나타나는 식의 유형은 다음과 같습니다.no
생략 부호는 임의의 인수를 받아들일 뿐만 아니라 변환 순위가 가장 낮기 때문에 사용할 수 있으면 첫 번째 함수에 대한 호출이 우선되므로 모호함이 해소됩니다.
C++11 심플화
C++11에서는 위의 코드를 다음과 같이 간략화할 수 있습니다.
#실패하다 <iostream> #실패하다 <type_timeouts> 템플릿 <>타이프네임... Ts> 사용. 무효 = 무효; 템플릿 <>타이프네임 T, 타이프네임 = 무효> 구조 has_sysef_foobar : 표준::false_type {}; 템플릿 <>타이프네임 T> 구조 has_sysef_foobar<>T, 무효<>타이프네임 T::푸바>> : 표준::true_type {}; 구조 후우 { 사용. 푸바 = 흘러가다; }; 인트 주된() { 표준::외치다 << > 표준::부루알파; 표준::외치다 << > has_sysef_foobar<>인트>::가치 << > 표준::끝; 표준::외치다 << > has_sysef_foobar<>후우>::가치 << > 표준::끝; }
라이브러리 기본 v2(n4562) 제안에서 검출 관용어를 표준화하면 위의 코드를 다음과 같이 다시 작성할 수 있습니다.
#실패하다 <iostream> #실패하다 <type_timeouts> 템플릿 <>타이프네임 T> 사용. has_sysef_foobar_t = 타이프네임 T::푸바; 구조 후우 { 사용. 푸바 = 흘러가다; }; 인트 주된() { 표준::외치다 << > 표준::부루알파; 표준::외치다 << > 표준::is_filename(이것들)<>has_sysef_foobar_t, 인트>::가치 << > 표준::끝; 표준::외치다 << > 표준::is_filename(이것들)<>has_sysef_foobar_t, 후우>::가치 << > 표준::끝; }
Boost 개발자는 SFINAE를 boost::enable_if[3] 등의 방법으로 사용했습니다.
레퍼런스
- ^ Vandevoorde, David; Nicolai M. Josuttis (2002). C++ Templates: The Complete Guide. Addison-Wesley Professional. ISBN 0-201-73484-2.
- ^ 국제 표준화 기구"ISO/IEC 14882:2003, 프로그래밍 언어 - C++", © 14.8.2.
- ^ Boost Enable If(부스트 유효화)