【问题标题】:std::is_same doesn't work through decltype of constexpr auto variablestd::is_same 不能通过 constexpr 自动变量的 decltype 工作
【发布时间】:2019-08-10 21:46:13
【问题描述】:

我试图 static_assert 表明某些元转换器算法有效,但它令人难以置信地无法与之比较,即使 typeid().name() 返回完全相同的字符串。

在 typedef 中重复类型表达式可以修复 is_same,但是 我无法理解在 typedef 中重复初始化表达式如何更改类型,而不是使用初始化的 auto 变量的 decltype同样的表达方式

对我在做什么的更具体的解释:
我做了一个元转换器,可以将元值列表(包含枚举器)转换为所有枚举器的 std::tuple。然后我检查了生成的元组是我期望的。

下面的所有代码,检查带有 cmets 的行 // 有效 // 无效
并且最后的测试已经结束了。

#include <type_traits>
#include <tuple>

template<typename T> struct ValueListAsTuple;  // master template
// destructurer of list:
template<template <auto...> class L, auto... Vs>
struct ValueListAsTuple<L<Vs...>>
{
    static constexpr auto value = std::make_tuple(Vs...);
    //using type = decltype(std::make_tuple(Vs...)); // works
    using type = decltype(value); // doesn't work
};

// template typedef
template<typename T> using ValueListAsTuple_t = typename ValueListAsTuple<T>::type;

struct Kind
{
    enum EnumType { E1, E2 };
    template <auto... Values> struct MetaVals{};  // meta value list
    using MetaValueList = MetaVals<
        E1,
        E2
    >;
};

int main(int argc, const char* argv[])
{
    auto tuple = ValueListAsTuple_t< Kind::MetaValueList > {};

    //std::cout << typeid(tuple).name() << '\n';
    // this prints: "class std::tuple<enum Kind::EnumType, enum Kind::EnumType>"

    // manual re-creation of the type, for testing:
    std::tuple< Kind::EnumType, Kind::EnumType > t2;

    //std::cout << typeid(t2).name() << '\n';
    // this prints the exact same thing.

    static_assert( std::is_same_v< std::tuple_element<0, decltype(tuple)>::type, Kind::EnumType > );
    static_assert( std::is_same_v< std::tuple_element<1, decltype(tuple)>::type, Kind::EnumType > );

    // WHAT ???
    static_assert( std::is_same_v< 
                        ValueListAsTuple_t< Kind::MetaValueList >,
                        std::tuple< Kind::EnumType, Kind::EnumType >
                                 > );
    // is_convertible_v works but I don't care ! wth ?
}

如您所见,type 通过value 声明时,is_same 无法推断出相同的类型,但如果我重复std::make_tuple(..,它会起作用。我看不出这两种形式有什么区别。

我什至逐个元素地检查元组的每个索引处的类型是否相同。

在 Godbolt 中检查实际情况:
https://godbolt.org/z/QUCXMB

在 gcc/clang/msvc 中的行为是相同的

【问题讨论】:

  • 不要粗鲁,但这真的是您可以编写的用于重现问题的最少代码吗?对于minimal reproducible example,这里有相当多的噪音。
  • @StoryTeller 不,你是对的,我试图从原始代码中删减很多。实际上花了一段时间才达到这个简洁。虽然我同意你的观点,但我相信第二次迭代可以让它变得更小:)
  • @StoryTeller 我把它修剪了 5 或 6 行 :)) 我希望它对未来的谷歌人有所帮助!

标签: c++ metaprogramming typetraits is-same


【解决方案1】:

确实,这是一个微不足道的错误,但不幸的是很难发现。您面临的问题是因为constexpr 意味着const。因此,在您的示例中,typeconst tuple&lt;...&gt;,这与您检查的非 cv 限定类型不同。对别名的简短修复应该会让您的测试通过:

using type = std::remove_const_t<decltype(value)>;

【讨论】:

  • omg 我明白了...不过,我尝试使用非常有限的编译时间调试工具进行检查:intellisense 提供了显示扩展类型的工具提示,而 const 没有出现。 typeid 也未能透露 const :'(
  • @v.oddou - 我喜欢这个技巧,这是我从 Scott Meyers 的书中学到的。您使用template&lt;typename&gt; struct wtf;(未定义)之类的模板。然后您尝试创建一个对象wtf&lt;type_to_check&gt; o;,编译器对不完整类型的抱怨将准确显示它作为类型参数放入的内容。
  • 天啊,我觉得template&lt;typename&gt; struct print; 是一个描述性名称。
  • @PasserBy - 是的,但如果我发现自己需要它,那么wtf_is&lt;T&gt; 感觉更合适。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多