【问题标题】:Detecting the types of individual enumeration constants检测单个枚举常量的类型
【发布时间】:2014-08-20 01:29:08
【问题描述】:

下面的代码将unsigned int打印为enum Test内所有常量的底层类型

#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>

struct Test 
{
    enum { a = true, b = 1 };    
};

static_assert(std::is_same<
    std::underlying_type_t<decltype(Test::a)>, 
    std::underlying_type_t<decltype(Test::b)>>::value, ""
);

int main()
{    
    int status;
    auto const& bi = typeid(std::underlying_type_t<decltype(Test::a)>);
    std::cout << abi::__cxa_demangle(bi.name(), 0, 0, &status); // unsigned int
}

Live Example。如果Test 包含两个单独的enums,ab 和以前一样,也会发生这种情况。

问题:是否可以检测到Test::a 是用bool 初始化的,而Test::b 是用int 初始化的?在反射研究组的 C++17 提案中是否有任何实验代码?

注意:我知道我可以将Test 替换为

struct Test
{
    static constexpr auto a = true;
    static constexpr auto b = 1;
};

但我发现enum 版本的用法稍微不那么冗长。

【问题讨论】:

  • 嗯。在枚举的}之后,所有枚举数的类型都是枚举的类型。在枚举中,枚举数的类型是初始化值 [dcl.enum]/5 的类型(如果基础类型不固定)。不知道反射。
  • @dyp 我什至会满足于区分boolint 常量的技巧。
  • @AndrewTomazos 我今天看到了你的 N4113 提案,它允许查询枚举常量values,但不能查询它们的初始化器types。你能评论一下那个设计决定吗?来自this Q&A 的赏金 :-)
  • 我认为这个问题可能用词不当,因为枚举中的所有变量都具有相同的类型。当您找到 a 的类型时,您已经回答了名义上的问题。
  • @dyp:这应该是答案,而不仅仅是评论。

标签: c++ c++11 enums c++14 type-deduction


【解决方案1】:

这是不可能,我认为这不太可能。

原因是ab 是(在您的情况下未命名)enum 的值。因此,根据定义,它们属于enum 的类型,意思是:属于同一类型。用于初始化它们的表达式和它们的各自类型仅用于“计算”enum 的基础类型,而不是任何单独的值。

考虑到这一事实,我认为即使是反射也无助于恢复信息,因为当您查看 enum 的值时,初始化表达式的类型已被抽象掉。

您需要进行更深层次的检查,您需要访问用于初始化值的表达式。这意味着编译器必须为每个变量、值等存储大量附加信息(因为这将是普遍的事情,而不仅仅是enums)。

考虑一下这意味着什么:

  • 编译时间增加
  • 编译时内存使用增加
  • 现在每个值实际上都有两种类型,它被声明为的类型和它被初始化的表达式的类型

最后一点是我认为该语言的真正灾难。一个值应该具有单一类型,用于初始化该值的表达式不应以任何方式访问。这就是抽象的意义所在,打破它可能会导致各种微妙的依赖关系和很多复杂性。

免责声明:这只是我的个人观点,我不能代表委员会或工作组中的任何人发言。

【讨论】:

  • Tnx,不错且令人信服的答案。我认为这意味着你不能轻易地将enumstatic constexpr auto 混合在类型特征内省中,比如Boost.TTI。我想编写一个宏TRAIT_STATIC_CONSTANT(name, value),它生成一个特征template&lt;class T&gt; get_constant_name&lt;T&gt;,它同时存储嵌套类型和值。这应该在 T 中查找 name 并在 name 不存在时回退到 value。但是,如果 name 是枚举常量,则 decltype(underlying_type_t&lt;T::name&gt;)decltype(value) 不兼容。无论如何,在任何地方使用static constexpr auto 都可以解决它。
【解决方案2】:

您可以将 int 枚举值与非 int 区分开来,如下所示:

struct Test
{
  enum : short { a = true };
  enum : int   { b = 1    };
  // enum : bool { c = false };
};

不幸的是,VC2010 未能将 bool 编译为底层类型,这可能不被视为整数类型。如果您的用例只需要将整数与非整数分开,这可能不是问题。

【讨论】:

  • 感谢您的回答。但是,这并不比使用static constexpr auto a = true; 更方便,其他两个也类似。
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 2013-03-20
  • 2014-07-28
相关资源
最近更新 更多