根据标准设置什么颜色?
引用 C++11 和 C++14 标准来回答:
[expr.static.cast]/10
整数或枚举类型的值可以显式转换为枚举类型。如果原始值在枚举值 (7.2) 的范围内,则该值不变。否则,结果值是未指定的(并且可能不在该范围内)。
我们来看看枚举值的范围:[dcl.enum]/7
对于基础类型固定的枚举,枚举的值就是基础类型的值。
在 CWG 1766(C++11、C++14)之前
因此,对于data[0] == 100,结果值是指定的(*),不涉及Undefined Behaviour (UB)。更一般地说,当您从基础类型转换为枚举类型时,data[0] 中的任何值都不会导致 static_cast 的 UB。
CWG 1766 (C++17) 之后
见CWG defect 1766。
[expr.static.cast]p10 段落已得到加强,因此如果您将枚举的可表示范围之外的值转换为枚举类型,您现在可以调用 UB。这仍然不适用于问题中的场景,因为data[0] 是枚举的底层类型(见上文)。
请注意,CWG 1766 被认为是标准中的一个缺陷,因此编译器实现者可以将其应用于其 C++11 和 C++14 编译模式。
(*) char 要求至少为 8 位宽,但不要求为 unsigned。根据 C99 标准的附录 E,可存储的最大值至少为 127。
与 [expr]/4 比较
如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。
在 CWG 1766 之前,转换整数类型 -> 枚举类型可以产生未指定的值。问题是:未指定的值是否可以超出其类型的可表示值?我相信答案是否——如果答案是是,在“此操作产生未指定的值”和“此操作具有未定义的行为”之间,您对有符号类型的操作的保证不会有任何区别。
因此,在 CWG 1766 之前,即使 static_cast<Color>(10000) 也不会调用 UB;但在 CWG 1766 之后,它确实调用了 UB。
现在,switch 声明:
[stmt.switch]/2
条件应为整数类型、枚举类型或类类型。 [...] 进行整体促销。
[conv.prom]/4
unscoped 枚举类型(其基础类型是固定的(7.2))的纯右值可以转换为其基础类型的纯右值。此外,如果可以将整型提升应用于其基础类型,则其基础类型固定的无作用域枚举类型的纯右值也可以转换为提升的基础类型的纯右值。
注意:没有 enum-base 的作用域枚举的基础类型是 int。对于无作用域的枚举,底层类型是实现定义的,但如果int 可以包含所有枚举器的值,则不应大于int。
对于无范围的枚举,这将我们引向 /1
除bool、char16_t、char32_t 或 wchar_t 以外的整数类型的纯右值,其整数转换等级 (4.13) 小于 int 的等级可以转换为type int if int 可以表示源类型的所有值;否则,源纯右值可以转换为unsigned int 类型的纯右值。
在 unscoped 枚举的情况下,我们将在此处处理 ints。对于 作用域 枚举(enum class 和 enum struct),不适用整体提升。无论如何,整体提升也不会导致UB,因为存储的值在基础类型的范围内,并且在int的范围内。
[stmt.switch]/5
当switch 语句被执行时,它的条件被评估并与每个case 常量进行比较。如果其中一个 case 常量等于条件的值,则控制权将传递给匹配的 case 标签后面的语句。如果没有case 常量与条件匹配,并且如果有default 标签,则控制权传递给带有default 标签的语句。
default 标签应该被点击。
注意:可以再看一下比较运算符,但它没有明确地用于所提到的“比较”中。事实上,在我们的案例中,没有任何迹象表明它会为作用域或非作用域枚举引入 UB。
作为奖励,标准是否对此做出任何保证,但使用普通枚举?
enum 是否在此范围内没有任何区别。但是,底层类型是否固定确实会有所不同。完整的 [decl.enum]/7 是:
对于基础类型固定的枚举,枚举的值是基础类型的值。否则,对于 emin 是最小枚举数且 emax 是最大枚举数的枚举,枚举是 bmin 到 bmax 范围内的值,定义如下:设K 1 表示二进制补码表示,0 表示一个补码或符号幅度表示。 bmax是大于等于max(|emin|的最小值-K,|emax|) 并且等于 2M − 1,其中M 是一个非负整数。 bmin 如果 emin 是非负数且 -(bmax + K) 否则。
我们来看看下面的枚举:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
请注意,我们不能将其定义为范围枚举,因为所有范围枚举都有固定的基础类型。
还好ColorUnfixed的最小枚举数是red = 0x1,所以max(|emin| - K, |emax| ) 在任何情况下都等于 |emax|,即yellow = 0x2。大于或等于2 的最小值,对于正整数M 等于2M - 1 是3 (22 - 1)。 (我认为目的是允许范围以 1 位为单位扩展。)因此 bmax 是 3 和 bmin em> 是0。
因此,100 将超出 ColorUnfixed 的范围,static_cast 将在 CWG 1766 之前产生未指定的值,在 CWG 1766 之后产生未定义的行为。