2017-09-07 21 views
14

왜이 코드에 대해 이상한 결과가 나옵니까? 올바른 방식으로 유형을 테스트하는 방법은 무엇입니까? 유형이 std :: tuple인지 여부를 감지하는 방법은 무엇입니까?

#include <iostream> 
#include <tuple> 
#include <type_traits> 

template<typename T> struct is_tuple : std::false_type {}; 
template<typename... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type {}; 

struct TraitBlock { 
    using BlockLocation = struct { std::uint64_t x, y, z; }; 
}; 

struct TraitRock {}; 

struct ItemTemplate{ 
    static constexpr auto traits = std::make_tuple(
     TraitBlock{}, 
     TraitRock{} 
    ); 
}; 

int main(){ 
    using A = std::tuple<char, int,double,char>; 
    std::cout << is_tuple<decltype(ItemTemplate::traits)>::value 
    << is_tuple<decltype(std::make_tuple(
     TraitBlock{}, 
     TraitRock{} 
    ))>::value 
    << std::endl; 
} 

내가 -std와 mingw64-GCC 7.2.0을 사용 = C++ 17, 나는 내가 두 개의 서로 다른 출력을 가지고 왜 출력 "01" 있어? 그들은 같은 유형이 아닌가?

+3

'템플릿 더미 구조체; 템플릿 구조체 Dummy ;'컴파일러에서 오류 메시지 형식을 제공합니다. – Jarod42

답변

16

decltype(ItemTemplate::traits)const std::tuple<TraitBlock, TraitRock>입니다.

그래서 cv 한정자를 어딘가에 처리해야합니다. ItemTemplate::traits의 유형 (즉 decltype(ItemTemplate::traits))의 is_tuple의 특성화에 지정된 타입 (즉 std::tuple<Ts...>)과 일치하지 않는, const std::tuple<TraitBlock, TraitRock> 것을

+0

아, constexpr는 const를 의미하지만, constexpr을 사용할 때 make_tuple의 내부 유형도 const가됩니까? –

+1

당신이 무슨 뜻인지 모르겠지만'const std :: tuple '이 아닌'const std :: tuple '을 가지고 있습니다. – Jarod42

12

참고.

너는 std::remove_const에 의하여 const-ness를 제거 할 수있다.

std::cout << is_tuple<std::remove_const_t<decltype(ItemTemplate::traits)>>::value; 

또는 const 또 다른 전문화를 추가 (뿐만 아니라 수도 volatile) :

template<typename... Ts> struct is_tuple<std::tuple<Ts...>> : std::true_type {}; 
template<typename... Ts> struct is_tuple<const std::tuple<Ts...>> : std::true_type {}; 
template<typename... Ts> struct is_tuple<volatile std::tuple<Ts...>> : std::true_type {}; 
template<typename... Ts> struct is_tuple<const volatile std::tuple<Ts...>> : std::true_type {}; 
7

당신은 모든 한정자를 제거해야합니다. 이 모든 작업을 직접 수행하는 대신 std::decay_t을 사용하여 모든 한정자를 제거하고 특성에 파견해야합니다. 예를 들어

template<typename T> 
struct is_tuple_impl : std::false_type {}; 

template<typename... Ts> 
struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {}; 

template<typename T> 
struct is_tuple : is_tuple_impl<std::decay_t<T>> {} 
+1

'std :: decay_t' 대신에'std :: remove_cv_t'를 사용 하시겠습니까? – Caleth

+3

다릅니다.'remove_cv_t'는'decay_t'의 부분 집합입니다. 후자는 특성에 대해서도 일반적으로 필요한 참조 (r- 값 및 l- 값)를 제거합니다. 'std :: tuple <…> &'및'std :: tuple <…> && '를 찾고 싶지 않다면 말입니다. –

+0

일반적으로, 우리는'std :: tuple <> &'을 튜플이라고 생각하지 않습니다. 그것은 특성이 작동하는 일반적인 방법입니다. – Barry