我在编程时发现了一些有趣的东西,其中一个是:
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中创建初始化机制的原因吗?
据我所知,创建了枚举类,不允许用户以这种方式使用枚举。
答案 0 :(得分:4)
每个enum class
都有underlying type,必须至少有一个字节大。任何像'd'
这样的单字符常量都适合一个字节。
(C ++将字节定义为一个字符的存储量.8位在C ++术语中称为“八位字节”)
请注意,对于“旧”枚举,范围的定义更具限制性,但这会影响转换规则。你仍然有一个基础类型,但仍然必须是一个大字节。
答案 1 :(得分:3)
你能告诉我,为什么允许用超过的值初始化Foo 声明枚举类值?
正如其他一个答案所说 - 枚举是引擎盖下的整数。它是特定于实现的,其中整数类型用于特定的枚举。这就是为什么你可以将整数分配给枚举。
据我所知,枚举类已创建,不允许用户使用 以这种方式表达。
这实际上是不真实的 - 枚举类存在无法隐式地转换枚举 TO 整数,而不是其他方式。请注意,将int
隐式转换为clas enum
不会造成太大威胁。
请注意,显式强制转换是完全有效的,有时也很有用。
有时枚举可以用作位标志
enum class O{
NOTHING = 0,
VERBOSE = 1,
QUIET = 2,
LOG = 4
};
现在想象您想要传递您的选项,但您希望记录您的输出并且详细。所以你应该通过4 | 1 = 5.这超过了枚举值。对我而言,class enum
的使用超过最大值只是有效(在某种程度上,这个问题有更好的解决方案)。
答案 2 :(得分:2)
[dcl.enum] / 8:
对于其基础类型是固定的枚举,枚举的值是基础类型的值。
所有enum class
都有固定的基础类型;显式的,如果没有明确给出,则为int。
因此,他们保证能够存储其基础类型可以存储的任何内容。
无范围的枚举(enum
没有class
或struct
)有不同的规则;它们的有效值基本上是枚举器值的2s补码二进制立方体。如果您的枚举未展开,则将其值设置为3将无法移植。
我怀疑这个规范的范围是为了在某种意义上更容易检查正确性;它们保证是一些整体类型。检查无范围枚举使用的正确性 hard 。它确实意味着你不能像程序员那样假设枚举只处于枚举值的状态;但要确保这会破坏许多用于枚举的用例,并且难以实际保证。
你可以提出一个严格枚举的提议,如果你看到它的巨大优势,它只能在命名状态下。
对于非作用域枚举:[dcl.enum] 7.2 / 8
对于其基础类型是固定的枚举,枚举的值是的值 基础类型。否则,对于枚举在哪里 e_min 是最小的调查员和 e_max 是个 最大值,枚举值是范围内的值 b_min 至 b_max ,定义如下:让 ķ 对于二进制补码表示为1,对于一个补码或符号幅度表示为0。 b_max 是大于或等于的最小值 最大 ( | e_min | - K, | e_max | ) 等于 2 ^ M - 1 ,哪里 中号 是一个非负整数。 b_min 如果是,则为零 e_min 是非负面的 - ( b_max + ķ ) 除此以外。的大小 最小的位字段足以容纳枚举类型的所有值 最大 ( 男, 1) 如果 b_min 是 零和 中号 + 1 除此以外。可以定义具有未由其任何值定义的值的枚举 统计员。如果 枚举列表 为空,枚举的值就像枚举有一个 值为0的单个枚举器
[expr.static.cast] 5.2.8 / 10:
可以将整数或枚举类型的值显式转换为枚举类型。价值是 如果原始值在枚举值(7.2)的范围内,则不变。否则,结果 值未指定(可能不在该范围内)。
转换为枚举值的二进制闭包之外的非作用域枚举会导致未指定的值,即使它适合基础类型。
enum foo{zero, one};
foo
的基础类型将是某种整数类型,foo
与该整数类型布局兼容,并且该整数类型可能只保存2
文件,但将2转换为foo
会导致foo
存储未指定的值。