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

时间:2018-06-06 11:07:34

标签: c++ enums initialization c++17

我在编程时发现了一些有趣的东西,其中一个是:

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中创建初始化机制的原因吗?

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

3 个答案:

答案 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没有classstruct)有不同的规则;它们的有效值基本上是枚举器值的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存储未指定的值。