《Effective Modern C++》条款10:优先选用enum class,而非enum
简述
众所周知,使用C++98中的枚举型别定义的枚举量,会泄漏到枚举型别所在的作用域中,这也意味着在此作用域内不能再有其他实体取相同的名称。因此,C++98中的枚举型别又称之为:不限作用域的枚举型别。
C++11为了解决这一问题,引入了限定作用域的枚举型别。由于限定作用域的枚举型别是通过”enum class“声明的,所以有时它们也被称为枚举类。
三个优点
C++11中限定作用域的枚举型别相较于C++98中不限定作用域的枚举型别,有三个明显的优点,分别是:
解决名称冲突
使用C++11限定作用域的枚举型别定义的枚举量,会被限定在枚举型别内:
1
2
3
4
5
6
7// C++98
enum Color { red, green, blue }; // red、green、blue的作用域和Color相同
auto red = false; // 编译错误!red已在当前作用域内被声明过了
// C++11
enum class Color { red, green, blue }; // red、green、blue的作用域被限定在Color内
auto red = false; // 编译成功,当前作用域内无“red“声明拒绝隐式转换
使用C++11中限定作用域的枚举型别定义的枚举量,在于其他类型比较时不会被隐式转换,只能是同类型的比较。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// C++98
enum Color { red, green, blue };
Color c = red;
if (c < 2.5) { // 将Color型别与double型别比较时会发生隐式转换,结果为true
....
}
// C++11
enum enum Color { red, green, blue };
Color c = Color::red;
if (c < 2.5) { // 编译错误!不能将Color型别与double型别比较
....
}
// 可通过强制转换进行比较
if (static_cast<double>(c) < 2.5) { // 编译成功,结果为true
...
}可进行前置声明
C++11中限定作用域的枚举型别可以进行前置声明,即型别的名字可以比较其中枚举量先声明。
1
2enum Color; // 编译错误!
enum class Color; // 编译成功一切枚举型别在C++眼里都会由编译器来选择一个整数型别作为其底层型别。
因此,C++11中限定作用域的枚举型别之所以能进行前置声明,本质上是因为其底层型别是已知的,默认为int。
而C++98中不限定作用域的枚举型别处于空间优化的目的,并未为其指定底层型别。换言之,如果想让C++98中不限定作用域的枚举型别支持前置声明,只需要在前置声明时为其指定底层型别即可。
1
enum Color: uint8_t; // 指定不限定作用域的枚举型别的底层型别为uint8_t