2015-01-04 2 views
3

약간의 컴파일 타임 도우미에서 특정 서명이있는 함수 (현재는 : 네임 스페이스 또는 클래스 멤버 함수 없음)가 존재하는지 확인해 보겠습니다 (예 : __builtin_pop_count, 널리 확산되었지만 모든 플랫폼에서 사용할 수있는 것은 아닙니다.) 인수의 고정 된 수의 경우 함수의 컴파일 시간 감지

,이 쉽게 이루어집니다 :

template <typename ReturnType, typename ArgumentType, typename = void> 
struct Exists : std::false_type // Base case 
{ 
}; 

template <typename T> 
using void_t = void; 

template <typename T> 
using return_t = decltype(foo(std::declval<T>())); // here it is hidden: foo, although this symbol is never declared! 

// specialization (compiler has to pick this one if no substitution failure in return_t 
template <typename ReturnType, typename ArgumentType> 
struct Exists<ReturnType, ArgumentType, void_t<return_t<ArgumentType>>> 
    : std::is_same<return_t<ArgumentType>, ReturnType> // check the return type 
{ 
}; 

static_assert(!Exists<void, int>::value, ""); 
static_assert(!Exists<void, void>::value, ""); 
static_assert(!Exists<void, char*>::value, ""); 
static_assert(!Exists<int, void>::value, ""); 
static_assert(!Exists<int, int>::value, ""); 
static_assert(!Exists<int, char*>::value, ""); 

이 잘 컴파일합니다. 함수를 추가하면 void foo(int)은 첫 번째 어설 션을 무효화하지만 나머지는 그대로 유지합니다.

이제 임의의 수의 인수 유형을 지원하도록이 도우미를 확장하고자합니다. 그러나

, 반면에

template <typename ReturnType, typename... ArgumentTypes, typename = void> 

typename... 목록의 마지막에 있어야하기 때문에, 작동하지 않을 수

template <typename ReturnType, typename = void, typename... ArgumentTypes> 

는 또한 기본 유형이 다음 ArgumentTypes이 필요 불가능합니다.

어떻게이를 피할 수 있습니까? std::tuple<ArgumentTypes...> 어떤 식 으로든 도움이 될 수 있습니까?

답변

5

당신은 짐작했습니다.
pack 템플릿을 사용하여 약간의 "단순화"

template <typename...> struct pack {}; // To be potentially introduced in C++1Z 

template <typename, typename, typename=void> 
struct Exists_impl : std::false_type {}; 

template <typename R, typename... Args> 
struct Exists_impl<R, pack<Args...>, 
    std::enable_if_t<std::is_same<decltype(foo(std::declval<Args>()...)), R>::value>> 
    : std::true_type {}; 

template <typename R, typename... Args> 
using Exists = Exists_impl<R, pack<Args...>>; 

Demo합니다.
이 템플릿은 이러한 경우에 관련 네임 스페이스 집합이 비어 있으므로 ADL을 통해 void(int)과 같은 기능을 찾을 수 없습니다. 이러한 함수는 정의 지점에서 선언되어야합니다.
또한 유스 케이스에 따라 반환 유형을 확인하기 위해 is_same 대신 is_convertible을 사용할 수도 있습니다.

+0

형식 목록을 원한다면 정규 반복문에 대해 'pack'을 사용해야하는시기는 언제입니까? – 0x499602D2

+0

@ 0x499602D2 '튜플'은 무거운 템플리트입니다. 꼭 필요한 경우가 아니면 TMP에서 사용해서는 안됩니다. – Columbo

+1

'is_convertible'을 사용한다면'int foo();'가'void()'와 호환되지 않는 한, 아마도'void' 리턴 타입을 전문으로하고 싶을 것입니다. 아니면, 차단하려는 경우! – Yakk