每周技巧 #86:用类枚举
本节阅读量:本文翻译自 Abseil 官网的 Tip of the Week #86: Enumerating with Class。
原文最初作为 totw/86 发布于 2015 年 1 月 5 日。
“展现 class,……并显示 character。”– Bear Bryant
枚举,或者简单说 enum,是一种可以保存一组指定整数之一的类型。这个集合中的某些值可以被赋予名字,称为枚举项。
非限定作用域枚举
C++ 程序员会熟悉这个概念,但在 C++11 之前,枚举有两个明显缺点:枚举项名称会:
- 与 enum 类型处于同一作用域;
- 隐式转换为某种整数类型的值。
所以,在 C++98 中……
|
|
但是……
|
|
C++11 以一种方式修改了非限定作用域 enum 的行为:枚举项现在局部属于 enum,但为了向后兼容,仍会导出到 enum 所在作用域。
所以,在 C++11 中……
|
|
但 PoliticalOrientation 的声明仍然会引发错误。
限定作用域枚举
隐式转换为整数已经被观察到是 bug 的常见来源,而枚举项与 enum 处于同一作用域造成的命名空间污染,也会在大型、多库项目中带来问题。为了解决这两个问题,C++11 引入了一个新概念:限定作用域 enum。
由关键字 enum class 引入的限定作用域 enum 中,枚举项:
- 只局部属于 enum(不会导出到 enum 所在作用域);
- 不会隐式转换为整数类型。
所以,(注意额外的 class 关键字)……
|
|
并且……
|
|
这些简单变化消除了普通枚举的问题,因此所有新代码都应优先使用 enum class。
使用限定作用域 enum 确实意味着,如果你仍然想要转换到整数类型,就必须显式转换(例如在记录枚举值日志时,或对类似 flag 的枚举项使用位运算时)。不过,用 std::hash 做哈希仍然会继续工作(例如 std::unordered_map<CursorDirection, int>)。
枚举底层类型
C++11 还引入了为两类枚举指定底层类型的能力。以前 enum 的底层整数类型由枚举项的符号和大小决定,但现在我们可以显式指定。例如:
|
|
因为这个枚举项范围很小,如果我们希望在存储 CursorDirection 值时避免浪费空间,也可以改为指定 char。
|
|
如果枚举项值超过底层类型的范围,编译器会报错。
结论
新代码中优先使用 enum class。这样可以减少命名空间污染,并且可能避免隐式转换中的 bug。
|
|