2017-09-07 148 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; 
} 

我用mingw64-GCC 7.2.0与-std = C++ 17,我得到了输出 “01” 为什么我有两个不同的输出?他们不是同一类型吗?

+3

您可能会使用类似'template struct Dummy; template struct Dummy ;'让编译器为您提供错误消息中的类型。 – Jarod42

回答

16

decltype(ItemTemplate::traits)const std::tuple<TraitBlock, TraitRock>

所以你必须在某处处理cv限定词。

+0

哦,constexpr意味着const,但是当我使用constexpr时,它是否也会使make_tuple的内部类型为const? –

+1

不确定你的意思,但你有'const std :: tuple ',而不是'const std :: tuple '。 – Jarod42

12

注意的ItemTemplate::traits的类型(即decltype(ItemTemplate::traits))是const std::tuple<TraitBlock, TraitRock>,其不匹配的is_tuple专业化指定类型(即std::tuple<Ts...>)。

您可以删除std::remove_const(例如,

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 :: remove_cv_t'而不是'std :: decay_t'吗? – Caleth

+3

这取决于'remove_cv_t'是'decay_t'的子集。后者也将删除通常所需特征的参考(r-和l-值)。除非你不想找到'std :: tuple <…>&'和'std :: tuple <…> &&'。 –

+0

通常,我们不认为'std :: tuple <>&'是一个元组。这是特质常用的方式。 – Barry

相关问题