是枚举 E { a } e = E(2);有效的?

Is enum E { a } e = E(2); valid?

最近有个有趣的C语言-律师提问:

此问答针对 C++ 的类似案例提出了相同的问题(*):这些有效吗?

enum EA { a } ea = EA(2);               // #1
enum EB { b } eb = static_cast<EB>(2);  // #2

我已经注意到变体 enum EC { c } ec = EC{2}; 在编译时被拒绝(“无法使用类型右值初始化类型 'E' 的值 [int'),而 #1#2 被接受,排除 #1#2 的格式错误但不是格式错误的 NDR 和 UB。


(*) 在被提示打破对原始 C 语言律师问题的过于急切和错位的以 C++ 为中心的答案后,作为自我回答的问答发布在这里。

C++14 之前的未指定行为;自 C++17

以来的未定义行为

虽然相应的构造在 C 中是合法的————由于更强的“兼容类型”要求,但 C++ 却不适用,其中“C 风格”无作用域枚举没有固定的底层类型与C有细微差别

首先,我们可能注意到原来的C例子

enum E { a } e = 1;

在 C++ 中是不合法的,因为 C++ 不允许隐式转换 整数类型 没有显式基础类型的无作用域枚举,因此 OP

的示例略有修改
// Syntactically legal -> compiles.
enum EA { a } ea = EA(2);               // #1
enum EB { b } eb = static_cast<EB>(2);  // #2

根据[dcl.enum]/7,

For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, the values of the enumeration are the values representable by a hypothetical integer type with minimal width M such that all enumerators can be represented. The width of the smallest bit-field large enough to hold all the values of the enumeration type is M. [...]

EAEB 的基础类型是 implementation-defined。

根据[expr.static.cast]/10

A value of integral or enumeration type can be explicitly converted to a complete enumeration type. [...] If the enumeration type does not have a fixed underlying type, the value is unchanged if the original value is within the range of the enumeration values ([dcl.enum]), and otherwise, the behavior is undefined. [...]

#2 以上可能(取决于 E 的 implementation-defined 基础类型)导致

  • C++17 及以后的未定义行为,通过 CWG 1766
  • 的解析
  • C++14 及更早版本中的未指定行为。

从概念上讲,转换可能会导致有符号整数溢出(即 UB)。

根据 [expr.type.conv],案例 #1 也是显式(类型)转换,与 #2 相同的参数也适用于此功能转换案例。