Eric Niebler의 std :: is_function 구현은 어떻게 작동합니까?
지난주 Eric Niebler 는 traits 클래스에 대한 매우 간결한 구현을 트윗 했습니다 std::is_function
.
#include <type_traits>
template<int I> struct priority_tag : priority_tag<I - 1> {};
template<> struct priority_tag<0> {};
// Function types here:
template<typename T>
char(&is_function_impl_(priority_tag<0>))[1];
// Array types here:
template<typename T, typename = decltype((*(T*)0)[0])>
char(&is_function_impl_(priority_tag<1>))[2];
// Anything that can be returned from a function here (including
// void and reference types):
template<typename T, typename = T(*)()>
char(&is_function_impl_(priority_tag<2>))[3];
// Classes and unions (including abstract types) here:
template<typename T, typename = int T::*>
char(&is_function_impl_(priority_tag<3>))[4];
template <typename T>
struct is_function
: std::integral_constant<bool, sizeof(is_function_impl_<T>(priority_tag<3>{})) == 1>
{};
하지만 어떻게 작동합니까?
일반적인 아이디어
cpprefereence.com 의 샘플 구현 과 같이 유효한 모든 함수 유형을 나열하는 대신 이 구현은 함수 가 아닌 모든 유형을 나열한 다음 true
일치 하는 유형이 없는 경우 에만 확인합니다 .
비 기능 유형 목록은 다음으로 구성됩니다 (아래에서 위로).
- 클래스 및 공용체 (추상 유형 포함)
- 함수에서 반환 할 수있는 모든 것 (
void
및 참조 유형 포함) - 배열 유형
이러한 비 함수 유형과 일치하지 않는 유형은 함수 유형입니다. 참고 std::is_function
명시 같은 함수 호출 연산자 람다 또는 클래스 등 호출 유형 고려 하지 기능을 주도한다.
is_function_impl_
is_function_impl
가능한 각 비 기능 유형에 대해 하나의 함수 오버로드를 제공 합니다. 함수 선언은 파싱하기가 약간 어려울 수 있으므로 클래스 및 공용체 사례 의 예를 들어 분석해 보겠습니다 .
template<typename T, typename = int T::*>
char(&is_function_impl_(priority_tag<3>))[4];
이 줄은 is_function_impl_
유형의 단일 인수를 사용 priority_tag<3>
하고 4 char
초 배열에 대한 참조를 반환 하는 함수 템플릿 을 선언합니다 . C의 고대 시대부터 관례 적으로 선언 구문은 배열 유형의 존재로 인해 끔찍하게 복잡해졌습니다.
이 함수 템플릿은 두 개의 템플릿 인수를 사용합니다. 첫 번째는 제한되지 T
않지만 두 번째는 T
유형 의 멤버에 대한 포인터 int
입니다. int
여기에 있는 부분은별로 중요하지 않습니다. 이것은 T
타입의 멤버가없는 에서도 작동 합니다 int
. 하지만 T
클래스 또는 공용체 유형이 아닌에 대해 구문 오류가 발생한다는 것입니다 . 다른 유형의 경우 함수 템플릿을 인스턴스화하려고하면 대체 실패가 발생합니다.
두 번째 템플릿 인수를 사용하여 각각 유효한 함수 반환 유형 또는 배열 유형에 대해서만 컴파일되는 표현식을 형성 하는 priority_tag<2>
및 priority_tag<1>
오버로드에도 유사한 트릭이 사용 T
됩니다. priority_tag<0>
오버로드 에만 이러한 제한적인 두 번째 템플릿 매개 변수가 없으므로 T
.
대체로 우리 is_function_impl_
는 입력 인수와 반환 유형에 따라 다른 네 가지 오버로드를에 대해 선언 합니다. 각각은 다른 priority_tag
유형을 인수로 취하고 다른 고유 크기의 char 배열에 대한 참조를 리턴합니다.
태그 발송 is_function
인스턴스화 할 때 지금 is_function
,이 인스턴스 is_function_impl
와 함께 T
. 이 함수에 대해 4 개의 서로 다른 과부하를 제공 했으므로 여기서 과부하 해결이 발생해야합니다. 그리고 이러한 모든 오버로드는 함수 템플릿 이므로 SFINAE 가 시작할 기회가 있음을 의미 합니다.
따라서 함수 (및 함수 만)의 경우 가장 일반적인 오버로드를 제외하고 모든 오버로드가 실패합니다 priority_tag<0>
. 그렇다면 인스턴스화가 가장 일반적인 과부하 인 경우 항상 해당 과부하로 해결되지 않는 이유는 무엇입니까? 오버로드 된 함수의 입력 인수 때문입니다.
Note that priority_tag
is constructed in such a way that priority_tag<N+1>
publicly inherits from priority_tag<N>
. Now, since is_function_impl
is invoked here with priority_tag<3>
, that overload is a better match than the others for overload resolution, so it will be tried first. Only if that fails due to a substitution error the next-best match is tried, which is the priority_tag<2>
overload. We continue in this way until we either find an overload that can be instantiated or we reach priority_tag<0>
, which is not constrained and will always work. Since all of the non-function types are covered by the higher prio overloads, this can only happen for function types.
Evaluating the result
We now inspect the size of the type returned by the call to is_function_impl_
to evaluate the result. Remember that each overload returns a reference to a char array of different size. We can therefore use sizeof
to check which overload was selected and only set the result to true
if we reached the priority_tag<0>
overload.
Known Bugs
Johannes Schaub found a bug in the implementation. An array of incomplete class type will be incorrectly classified as a function. This is because the current detection mechanism for array types does not work with incomplete types.
ReferenceURL : https://stackoverflow.com/questions/43470741/how-does-eric-nieblers-implementation-of-stdis-function-work
'programing' 카테고리의 다른 글
명령 줄 프롬프트의 현재 디렉터리를 줄이려면 어떻게해야합니까? (0) | 2021.01.16 |
---|---|
부울 속성으로 객체의 Javascript 정렬 배열 (0) | 2021.01.16 |
Docker 이미지-유형. (0) | 2021.01.15 |
분산 된 동시성 제어 (0) | 2021.01.15 |
단위 테스트 Scala (0) | 2021.01.15 |