2017-03-25 10 views
0
#include <iostream> 
#include <type_traits> 

template<typename T> 
struct A 
{ 
    using m = std::remove_pointer_t<T>&; 
}; 

template 
< 
    typename T, 
    typename = std::void_t<> 
> 
struct Test 
{ 
    enum { value = 0 }; 
}; 

template<typename T> 
struct Test<T, typename A<T>::m> 
{ 
    enum { value = 1 }; 
}; 

int main() 
{ 
    std::cout << Test<void*&>::value; // ok, output 0 
    std::cout << Test<void*>::value; // error : cannot form a reference to 'void' 
} 

첫 번째 경우는 0을 출력합니다. 이는 기본 템플릿이 선택되었음을 의미합니다. 그래서 두 번째 경우는 전문 템플릿이 아닌 기본 템플릿을 선택해야한다고 생각합니다. 오류가 있어서는 안됩니다.SFINAE가 이러한 경우에 작동하지 않는 이유는 무엇입니까?

Test<void*&>은 정상입니다. 저를 놀라게 한 것은 Test<void*>가 좋지 않아야한다는 것입니다!

SFINAE은 왜 후자의 경우 작동하지 않습니까?

+0

케이스 될 수있다. – Pixelchemist

+0

그렇다면 왜 이전 사례는 괜찮습니까? – xmllmx

+0

참조 축소로 인해 효과가없는 'remove_pointer'가 발생했습니다. – Pixelchemist

답변

5

두 번째 경우는 심각한 오류입니다.

SFINAE @ cppreference.com는 말한다 : 함수 타입 또는 템플릿 매개 변수 유형의 즉각적인 맥락에서 유형과 표현의

만 실패 SFINAE 오류입니다. 대체 유형/표현식의 평가에서 일부 템플리트 특수화의 인스턴스 작성, 내재적으로 정의 된 구성원 함수의 생성 등과 같은 부작용이 발생하는 경우, 부작용의 오류는 하드 오류로 처리됩니다. Tm 때문에 참조 붕괴 및 보이드에 대한 참조는 아니지만 무효 포인터 참조 올바른 타입의 void*& 인 후, void*& 경우 remove_pointer 아무런 효과가 없으므로

첫번째 경우는 OK이다.

첫 번째 템플릿 인수 만 지정하기 때문에 첫 번째 경우의 형식은 여전히 ​​Test<void*&, void>이 아니라 Test<void*&, void*&>입니다.

두 번째 경우가 실패하지만 첫 번째가 실패하는 이유는 두 번째 매개 변수가 추론되지 않은 컨텍스트이기 때문에 컴파일러가 특수 템플릿을 인스턴스화해야하므로 컴파일러는 특수화가 더 적합한 일치인지 즉시 알 수 없습니다 . 그러나 두 번째 경우에는 인스턴스화가 어려운 오류를 생성하지만 첫 번째 경우에는 그렇지 않습니다.

기본 템플릿이 더 적합하므로 여전히 선택됩니다 (여전히 특수 템플릿이 인스턴스화되어 일치하는지 확인).

참고 : 전문화가 실제로 완전히 인스턴스화되었는지 또는이 전문화 기술이 더 적합한 지 여부를 확인하기 위해 컴파일러가 typename A<T>::m을 조회하는지 여부는 말할 수 없습니다. 그러나 결과는 동일합니다. void*의 경우에는 심각한 오류가 있습니다.

어쨌든 C++ 17을 사용하면 enum보다는 constexpr 멤버를 사용하게됩니다. :: m` 아닌 콘텍스트 추론 될 수있다`때문에

template<typename T> 
struct Test<T, typename A<T>::m> 
{ 
    static constexpr unsigned value = 1u; 
}; 
+0

첫 번째 경우는 '0'을 출력합니다. 즉, 오버로드 된 클래스가 특수 템플릿이 아닌 기본 템플릿입니다. – xmllmx

+0

귀하의 진술이 사실이라면, 첫 번째 경우는 특수한 템플릿을 사용하기 때문에 '1'을 출력합니다. – xmllmx

+0

첫 번째 경우는 '0'을 출력하고, 두 번째 경우는 '0'을 출력해야합니다. 그것은 내가 궁금해하는 것입니다. – xmllmx