什么是枚举类,我为什么要关心?

What's an enum class and why should I care?

提问人:sbi 提问时间:12/26/2012 最后编辑:Daniel Heilpersbi 更新时间:7/5/2017 访问量:3704

问:

对于一个从未写过 C++11 行,并且目前没有机会用 C++11 编程的人,你能用一小段话告诉我吗?

什么是“枚举类”,为什么我们需要它?

C++ C++11 举枚 举类

评论

1赞 user93353 12/26/2012
stackoverflow.com/questions/6936030/......
0赞 sbi 12/26/2012
@user:我不认为这能回答我的两个问题。
1赞 Potatoswatter 12/30/2012
这绝对是一个独特的问题。其他问题(有各种各样的)询问特定细节或与类似 C++03 结构的关系。这范围更广,将是一个很好的常见问题解答问题。
0赞 Lightness Races in Orbit 1/25/2013
我想说的是,这两个问题是截然不同的,但只是微不足道的;这个答案没有在另一个中,是“阅读你的C++11书”——没有进行任何研究。我会投票重新开放,但投了反对票。
0赞 Lightness Races in Orbit 1/25/2013
哦,如果它变成了一个 c++-faq 问题,我可能会投赞成票。因为这就是 c++-faq 标签的疯狂工作方式,宝贝。

答:

-1赞 happy coder 12/26/2012 #1

起初我对你的问题感到困惑,但我想你想知道 c++ 枚举和 c++11 中的枚举之间的区别。据我所知,在后面,你有强类型枚举,允许你确定它们的范围。我认为这很好地解释了它。干杯

评论

1赞 Abyx 12/26/2012
很多限制不是你所说的“自由”
0赞 happy coder 12/27/2012
阿比克斯,也许你说得有道理。我的措辞有点不准确,但我认为现在更符合现实。对于快乐的投票者,您可能想查看参考资料。我认为这是一个非常有用的链接。
0赞 Brandon 12/26/2012 #2
  1. 当数据大小很重要时,您可以显式指定存储类型(也许将其打包在结构中)。
  2. 枚举值的范围仅限于枚举的名称;在 C++11 之前,它们泄漏到封闭作用域中。
  3. 我似乎记得转换规则也发生了一些变化......

关于点 1,s 的存储大小将在 C++11 之前更改,具体取决于分配给枚举的最大值。通常这并不重要,但是当它发生时,您必须求助于丑陋的黑客来强制调整大小。enum

至于第 3 点,在 C++11 中,s 不能隐式转换或与 s 或其他类型类似:对于避免函数重载头痛和其他隐式转换陷阱很有用。enumintenum

评论

0赞 sbi 12/26/2012
经过鲁本的编辑,这真的很有希望。现在,如果你只能对#3给出一个明确的陈述,详细说明你所有的观点,而不仅仅是#1,我会很想投赞成票。:)
3赞 Potatoswatter 12/26/2012
enum class与使用 指定基础类型无关。:
0赞 Brandon 12/26/2012
@Potatoswatter对的,但指定基础类型而不使用 仅作为过渡语法 AFAIK 提供。enum class
0赞 Brandon 12/26/2012
@sbi 至于 3,在 C++11 中,s 不能隐含地转换为 s 或其他类型或可比性。enumintenum
2赞 Potatoswatter 12/26/2012
过渡到什么?附录 D(标准关于向后兼容性功能的部分)没有提到任何关于枚举的内容。
0赞 Stephane Rolland 12/26/2012 #3

就个人而言,我在基于 tcp 的消息传递协议中使用了它:许多字段是我只需要在一个字节内编码的枚举值,以便尊重消息传递接口。

我所有的枚举都是这样定义的:

enum class EnumFieldA : unsigned char { eValProperty1, eValProperty2};
enum class EnumFieldB : unsigned char { eValProperty1, eValProperty2, eValProperty3};
enum class EnumFieldC : unsigned char { eValProperty1, eValProperty2, eValProperty3, eValProperty4};
...

在这个 SO 问题中也有很多详尽的答案。

评论

1赞 sbi 12/26/2012
这如何回答什么是类?enum
1赞 Stephane Rolland 12/26/2012
它回答了你,我们为什么需要它?这就是我需要它的原因以及我如何使用它。
2赞 Potatoswatter 12/26/2012
class与指定无关,并且您不应该通过传输结构的字节进行序列化,尤其是在 TCP 上(尽管如果所有字段都是一个字节,这确实避免了字节序问题)。unsigned char
0赞 Stephane Rolland 12/26/2012
我使用了 1 的对齐方式。我认为,如果两个平台具有相同的操作系统,那么字节序是相同的,就像我所研究的系统一样。
1赞 Potatoswatter 12/26/2012
最佳做法:不要假设字节序。有一个 RFC 指定 big-endian(与 Intel 相反)是互联网二进制传输的官方字节序,因此它被用于 TCP 数据包标头等。您可能可以在维基百科关于字节序的页面上找到链接的 RFC。
15赞 Potatoswatter 12/26/2012 #4

enum class称为作用域枚举。它可以防止使用枚举器名称污染枚举出现的命名空间。

在 C++03 中,你可以通过将 内部的 .也许这就是语法的来源,这有点令人困惑。enumclass

另一个区别是,此类类型的枚举器不会隐式转换为 ( 是必需的)。这可能很少需要,但它可以安全地重载一个函数,该函数采用一个接受类型的参数。您可以确定不会意外调用。或者,您可以使用专用函数定义伪整型,并确保内置运算符不会干扰。intstatic_cast<int>intenumintoperator

这两个不相关的差异出现在同一个包中,并且您无法获得没有隐式转换的无作用域枚举,这有点烦人,但通常这两种更改都是好事,并且是 C++11 中的良好默认做法。enum class

编辑:作用域内枚举的定义如下:

enum class duck { huey, dewey, louie };

并且必须与范围解析运算符一起使用,如下所示:::

duck culprit = duck::huey; // or "auto culprit" to avoid redundancy

请注意,该运算符也适用于 C++03 无作用域枚举,因此即使缺少第一行,上面的第二行也有效。::class

这可能是过多的细节,但如果正向声明枚举类型,则不会进入 elaborated-type-specifier,如class

void quack( enum duck whom ); // not "enum class"

但是,C++11 中有一个新的构造,即 opaque-enum-declaration,它确实包含关键字并定义了一个完整的类型。class

enum duck; // duck is declared as incomplete type
enum class duck; // duck is now complete type; underlying type defaults to int

关键字可以替换,没有语义差异。structclass

评论

1赞 sbi 12/26/2012
啊,终于有了一个好答案。谢谢你,来自我。你能详细说明一下语法吗?你如何定义这样的野兽?我敢肯定我在几年前的某个地方见过它,但我忘记了。+1
0赞 Potatoswatter 12/26/2012
@sbi没有太多的详细说明,您只需将关键字添加到任何定义并获得这些语义更改即可。classenum
0赞 sbi 12/27/2012
不过,感谢您仍然添加它。我觉得这个答案现在是一个全面的解释,因此我会接受它。(虽然我不会保证以后有更好的事情出现时不会跳槽。:) )
1赞 bames53 1/4/2013
在 C++03 中添加枚举限定实际上并不合法。J.F. 在 C++03 中是非法的。但是,某些编译器(如 VC++)允许将其作为扩展。不过,C++11使此代码合法。enum E { V }; E e = E::V;
1赞 Potatoswatter 1/4/2013
@bames53 是的,我的意思是运算符使用从 C++03 继承的无作用域枚举。::