C++ 如果将无效值强制转换为枚举类,会发生什么情况?

C++ 如果将无效值强制转换为枚举类,会发生什么情况?,c++,c++11,C++,C++11,考虑以下C++11代码: enum class Color : char { red = 0x1, yellow = 0x2 } // ... char *data = ReadFile(); Color color = static_cast<Color>(data[0]); 《标准》是否保证违约会发生?如果不是,在这里检查错误的正确、最有效、最优雅的方法是什么 编辑: 作为奖励,标准是否对此做出了任何保证,但使用了普通枚举 根据标准设置的颜色是什么 引用C++11和C++14标

考虑以下C++11代码:

enum class Color : char { red = 0x1, yellow = 0x2 }
// ...
char *data = ReadFile();
Color color = static_cast<Color>(data[0]);
《标准》是否保证违约会发生?如果不是,在这里检查错误的正确、最有效、最优雅的方法是什么

编辑:

作为奖励,标准是否对此做出了任何保证,但使用了普通枚举

根据标准设置的颜色是什么

引用C++11和C++14标准:

[expr.static.cast]/10

整型或枚举类型的值可以显式转换为枚举类型。如果原始值在枚举值(7.2)的范围内,则该值不变。否则,结果值未指定(并且可能不在该范围内)

让我们查找枚举值的范围:[dcl.enum]/7

对于基础类型为固定的枚举,枚举的值是基础类型的值

在CWG1766之前(C++11,C++14) 因此,对于
数据[0]==100
,指定结果值(*),不涉及任何内容。更一般地说,当您从基础类型转换为枚举类型时,
数据[0]
中的任何值都不会导致
静态转换的UB

在CWG1766(C++17)之后 看见 [expr.static.cast]p10段落已得到加强,因此如果将枚举的可表示范围之外的值强制转换为枚举类型,则现在可以调用UB。这仍然不适用于问题中的场景,因为
data[0]
是枚举的基础类型(见上文)

请注意,CWG1766被认为是标准中的一个缺陷,因此编译器实现者可以将其应用于C++11和C++14编译模式

(*)
char
要求至少为8位宽,但不要求
无符号
。根据C99标准附录E,要求可存储的最大值至少为
127


与[expr]/4相比

如果在表达式求值期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义

在CWG1766之前,转换整数类型->枚举类型可以生成未指定的值。问题是:未指定的值是否可以超出其类型的可表示值?我相信答案是否定的——如果答案是肯定的,那么“此操作生成未指定的值”和“此操作具有未定义的行为”之间对有符号类型上的操作的保证不会有任何区别

因此,在CWG1766之前,即使
static_cast(10000)
也不会调用UB;但在CWG1766之后,它确实调用了UB


现在,
开关
语句:

[stmt.开关]/2

条件应为整型、枚举型或类型。[…]执行整体促销。

[conv.prom]/4

基础类型为固定(7.2)的非范围枚举类型的PR值可以转换为其基础类型的PR值。此外,如果可以对其基础类型应用整型提升,则基础类型为固定的非范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue

注意:没有枚举基的作用域枚举的基础类型是
int
。对于非范围枚举,基础类型由实现定义,但如果
int
可以包含所有枚举数的值,则基础类型不得大于
int

对于非范围枚举,这将导致/1

如果
int
可以表示源类型的所有值,则除
bool
char16\u t
char32\u t
wchar\u t
以外的整数类型的PR值(其整数转换秩(4.13)小于
int
可以转换为
int
类型的PR值;否则,可以将源prvalue转换为类型为
unsigned int
的prvalue

无范围枚举的情况下,我们将在这里处理
int
s。对于作用域的枚举(
枚举类
枚举结构
),不适用整体升级。无论如何,积分提升也不会导致UB,因为存储的值在基础类型的范围内,在
int
的范围内

[stmt.开关]/5

执行
switch
语句时,将评估其条件并与每个case常量进行比较。如果其中一个case常量等于条件的值,则控制权将传递给匹配的
case
标签后面的语句。如果没有与条件匹配的
case
常量,并且如果存在
default
标签,则控制传递到由
default
标签标记的语句

应点击
默认值
标签

注意:我们可以再看一看比较运算符,但在引用的“比较”中没有明确使用它。事实上,在我们的例子中,没有任何迹象表明它会为作用域或非作用域枚举引入UB


作为奖励,标准是否对此做出了任何保证,但使用了普通枚举

enum
是否有作用域在这里没有任何区别。但是,底层类型是否固定会有区别。完整的[decl.enum]/7是:

对于基础类型为固定的枚举,枚举的值是基础类型的值。否则,对于emin为最小枚举数且emax为最大枚举数的枚举,枚举的值为i
switch (color) {
    // ... red and yellow cases omitted
    default:
        // handle error
        break;
}
enum ColorUnfixed /* no fixed underlying type */
{
    red = 0x1,
    yellow = 0x2
}