为什么isocpp允许我们超过枚举类值

Why isocpp allows us to exceed enum class values?

本文关键字:枚举 我们 isocpp 许我们 为什么      更新时间:2023-10-16

我在编程时发现了许多有趣的东西,其中之一是:

enum class Foo {
FOO_THING,
FOO_TOO
};
int main() {
Foo foo {'d'};    // It is OK
Foo foo2 {3};    // and that one too
}

调试器说它的值是:

foo:  (unknown: 100)
foo2: (Foo::FOO_TOO | unknown: 2)

你能告诉我,为什么允许使用超过声明的枚举类值来初始化Foo吗?

编译器版本和命令:

Compiler GCC (g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0)
$ g++ -Wall -std=c++17 foo.cpp

我真的想知道在 C++17 中创建该初始化机制的原因吗?

据我所知,枚举类是创建的,不允许用户以这种方式使用枚举。

你能

告诉我,为什么允许用超过 声明的枚举类值?

正如其他答案之一所说 - 枚举是引擎盖下的整数。特定于实现的是,哪种整数类型用于特定的枚举。这就是为什么您可以将整数分配给枚举的原因。

据我所知,枚举类是创建的,不允许用户使用 以这种方式枚举。

这实际上是不正确的 - 枚举类的存在无法隐式地将枚举转换为整数,而不是相反。请注意,将int隐式强制转换为clas enum不会构成太大可能的威胁。

请注意,显式强制转换是完全有效的,有时很有用。

枚举作为位标志

有时枚举可以用作位标志

enum class O{
NOTHING = 0,
VERBOSE = 1,
QUIET = 2,
LOG = 4
};

现在假设你想要传递你的选项,但你希望你的输出被记录和详细。所以你应该通过 4 |1 = 5。这超出了枚举值。对我来说,它只有效(在某种程度上,这个问题有更好的解决方案)使用超过最大值的class enum

每个enum class都有一个基础类型,该类型必须至少有一个字节大。任何像'd'这样的单字符常量都适合一个字节。

(C++将字节定义为一个字符的存储量。 8位在C++行话中称为"八位组")

请注意,对于"旧"枚举,范围的定义更严格,但这会影响转换规则。你仍然有一个基础类型,它仍然必须是一个字节大。

[dcl.enum]/8:

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

所有enum class都有一个固定的基础类型;显式或 int(如果未显式给出)。

因此,他们保证能够存储其底层类型可以存储的任何内容。

无作用域枚举(enum没有classstruct)有不同的规则;它们的有效值基本上是枚举器值的2s补码二进制立方体。 如果枚举未限定范围,则将其值设置为 3 将无法移植。

我怀疑这个作用域枚举的规则是为了更容易地检查某种意义上的正确性;它们保证是某种整体类型。 检查无作用域枚举使用的正确性很困难。 这确实意味着作为程序员,您不能假设枚举仅处于其枚举值的状态;但是确保这样做既会破坏枚举的许多用例,又很难实际保证。

你可能会提出一个严格的枚举的建议,如果你从中看到它的巨大优势,它只能在命名状态中。

对于非作用域枚举:[dcl.enum] 7.2/8

对于基础类型为固定的枚举,枚举的值是 基础类型。 否则,对于其中的枚举 e_min 是最小的枚举器,并且 e_max 是 最大,枚举的值是范围内的值 b_min 自 b_max ,定义如下:让 K对于二的补码表示为 1,对于一的补码或符号大小表示为 0。 b_max 是大于或等于的最小值 .max ( | e_min |− K, | e_max | ) 并等于 2^M − 1 哪里 M 是一个非负整数。 b_min 为零,如果 e_min 是非负的,并且 − ( b_max + K ) 否则。的大小 足以容纳枚举类型的所有值的最小位字段是 .max ( M, 1) 如果 b_min 是 零和 M + 1 否则。可以定义一个枚举,该枚举的值未由其任何定义 统计员。如果 枚举器列表 为空,枚举的值就像枚举具有 值为 0 的单个枚举器

[expr.static.cast] 5.2.8/10:

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

转换为枚举值的二进制闭包之外的非作用域枚举会导致未指定的值,即使它适合基础类型也是如此。

enum foo{zero, one};

foo的基础类型将是某种整型类型,并且foo与该整型布局兼容,并且该整型类型可能只保存2文件,但将 2 转换为foo会导致foo存储未指定的值。