检测枚举类型中的各个枚举常量的类型

6
以下代码将enum Test中所有常量的基础类型打印为unsigned int
#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
}

实时示例。如果Test 包含两个独立的enum,其中包含与之前相同的ab,则也会发生这种情况。

问题:是否有可能检测到Test::a使用bool初始化,而Test::b使用int?在C++17的Reflection Study Group提案中是否有任何实验性代码可用于此?

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

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

但我发现在使用上enum版本稍微不那么冗长。


2
嗯,在枚举的 } 之后,所有枚举器的类型都是枚举的类型。在枚举中,如果底层类型没有固定,那么枚举器的类型是初始化值的类型 [dcl.enum]/5。我不知道反射相关的内容。 - dyp
@dyp 我甚至会满足于一种区分boolint常量的技巧。 - TemplateRex
@AndrewTomazos,我今天看到了你的N4113提案,它允许查询枚举常量,但不包括它们的初始化程序类型。你能否就这个设计决策发表评论?有一个来自这个Q&A的赏金 :-) - TemplateRex
我认为这个问题可能是一个错误的命名,因为枚举中的所有变量都具有相同的类型。当您找到a的类型时,您已经回答了标题中的问题。 - SplinterOfChaos
@dyp:那应该是答案,而不仅仅是评论。 - Jeffrey Yasskin
2个回答

4
这是不可能的,我认为甚至将来也不太可能实现。原因是a和b是枚举类型的值(在这种情况下未命名),因此它们根据定义属于枚举类型,意味着它们具有相同的类型。用于初始化它们的表达式及其各自的类型仅用于“计算”枚举的底层类型,而不是任何单个值的类型。 考虑到这一点,我认为即使使用反射也无法恢复信息,因为在查看枚举值时,初始化表达式的类型被抽象化了。你需要的是更深层次的检查,需要访问用于初始化值的表达式。这意味着编译器将不得不为每个变量、值等存储大量的附加信息(因为这将是一般性的,不仅适用于枚举)。考虑一下这意味着什么:
- 增加编译时间 - 编译时增加内存使用量 - 每个值现在实际上都有两个类型,一个是声明时的类型,另一个是它从中初始化的表达式的类型
我认为最后一点才是语言的真正灾难。一个值应该只有一个类型,初始化该值的表达式不应以任何方式访问。这就是抽象的含义,打破它可能会导致各种微妙的依赖关系和大量的复杂性。
免责声明:这只是我的个人意见,我不能代表委员会或工作组中的任何人。

谢谢,回答得很好,也很有说服力。我认为这意味着你不能轻易地在类型特征内省中混合使用 enumstatic constexpr auto,就像 Boost.TTI 那样。我想编写一个宏 TRAIT_STATIC_CONSTANT(name, value),它生成一个特征 template<class T> get_constant_name<T>,该特征存储嵌套类型和值。这应该查找 T 中的 name,如果不存在,则回退到 value。但是,如果 name 是枚举常量,则 decltype(underlying_type_t<T::name>)decltype(value) 不兼容。无论如何,到处使用 static constexpr auto 可以解决这个问题。 - TemplateRex

2
您可以按照以下方式将 int 枚举值与非 int 区分开来:
struct Test
{
  enum : short { a = true };
  enum : int   { b = 1    };
  // enum : bool { c = false };
};

不幸的是,VC2010无法将bool作为基础类型进行编译,这可能不被视为整数类型。如果您的使用情况仅需要将整数与非整数分开,则可能不是问题。


谢谢你的回答。然而,这比使用 static constexpr auto a = true; 不方便,其他两个也一样。 - TemplateRex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接