【问题标题】:How to detect whether a type is std::tuple or not?如何检测类型是否为 std::tuple?
【发布时间】:2017-09-07 10:02:40
【问题描述】:

为什么这段代码有奇怪的输出?如何以正确的方式测试类型?

#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” 为什么我得到两个不同的输出?他们不是同一类型吗?

【问题讨论】:

  • 你可以使用类似template &lt;typename&gt; struct Dummy; template struct Dummy&lt;decltype(ItemTemplate::traits)&gt;;的东西让编译器给你错误信息的类型。

标签: c++ c++11 template-meta-programming sfinae


【解决方案1】:

decltype(ItemTemplate::traits)const std::tuple&lt;TraitBlock, TraitRock&gt;

所以你必须在某个地方处理 cv 限定符。

【讨论】:

  • 哦,constexpr隐含着const,但是当我使用constexpr时,会不会也让make_tuple的内部类型变成const?
  • 不确定你的意思,但你有const std::tuple&lt;TraitBlock, TraitRock&gt;,而不是const std::tuple&lt;const TraitBlock, const TraitRock&gt;
【解决方案2】:

注意ItemTemplate::traits的类型(即decltype(ItemTemplate::traits))是const std::tuple&lt;TraitBlock, TraitRock&gt;,与is_tuple特化中指定的类型(即std::tuple&lt;Ts...&gt;)不匹配。

您可以通过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 {};

【讨论】:

    【解决方案3】:

    您需要删除所有限定符。而不是自己做这一切,你应该使用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>> {}
    

    【讨论】:

    • 你的意思是std::remove_cv_t而不是std::decay_t吗?
    • 视情况而定,remove_cv_tdecay_t 的子集。后者还将删除特征通常也需要的引用(r 值和 l 值)。除非你不想找到std::tuple&lt;…&gt;&amp;std::tuple&lt;…&gt;&amp;&amp;
    • 通常,我们不认为std::tuple&lt;&gt;&amp; 是一个元组。这就是特征的通常工作方式。
    猜你喜欢
    • 1970-01-01
    • 2019-06-15
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    相关资源
    最近更新 更多