C++11 新特性——强类型枚举

 
 

强类型枚举

  C++ 有一个奇怪的设定,有名字的 enum 类型的名字和 enum 成员的名字都是全局可见的。比如下面这种情况,就会导致编译错误。

enum Type { General, Light, Medium, Heavy };
enum Category { General, Pistol, MachineGun, Cannon }; // 无法通过编译

  如果能够提示错误,那非常好。但是如果其中一个被新的 namespace 所包围,就很容易出现错误。

namespace T { enum Type { General, Light }; }
namespace { enum Category { General = 1, Pistol }; }
int main() {
    T::Type t = T::Light;
    if(t == General)
        cout << "General Weapon" <<endl; // 输出 General Weapon
    return 0;
}

  上面的做法是明显错误的,不应该使用 Type::Light 来判断 Category::General 的数值。但是编译器并不会阻止编译(VC14 不会发出警告和错误),那么这就是一个非常难发现的 bug。
  非强类型作用域,允许隐式转换为整型,占用存储空间以及符号不确定性,都是枚举类的缺点。

强类型枚举对原有枚举类型的拓展

  声明强类型枚举,只需要在 enum 后面加上关键字 class。

enum class Type { General, Light };

  相对于普通枚举类型,强枚举类型几乎弥补了传统枚举类型的所有错误:

  • 强作用域,强类型枚举成员的名称不会被输出到其父作用域空间。
  • 转换限制,强类型枚举成员的值不可以与整型隐式转换,但可以进行强制转换。
  • 可以指定底层类型,比如 char,从而节省空间。强类型枚举可以继承除 wchar_t 外所有的整型。形式为:enum class Type : char { … }
  • 符号确定,不同类型的强类型枚举无法进行比较。

C++11 对原有枚举类型的拓展

  相比于原来的枚举,强类型枚举更像是一个属于 C++ 的枚举。但是为了配合新的枚举类型,C++ 11 对原有的枚举类型进行了拓展。
  首先,传统枚举类型也可以指定底层数据类型,从而节省空间。其指定方式跟强类型枚举一样。形式为 enum Type : char { … }
  第二个拓展是作用域的。在 C++ 11 中,枚举成员的名字除了会自动输出到父作用域,也可以在枚举类型定义的作用域有效。比如

enum Type { General, Light };
Type t1 = General;
Type t2 = Type::General;

  上述两种方法都是合法的形式。程序员也就不会因为不同的枚举类型采用不同的方法来访问。

额外补充

  在声明强类型枚举的时候,也可以使用关键字 enum struct。但是实际上,enum struct 和 enum class 没有任何区别。因为强类型枚举可以看做既不占用内存又是公开的 static 常量,它完全没有共有私有之分,也不能对 enum class 使用模板来生成。
  对于匿名 enum class,因为 enum class 是强类型作用域的,所以匿名的 enum class 没有任何作用。VC14 在试图定义匿名 enum class 时会报出错误。


转载请带上本文永久固定链接:http://www.gleam.graphics/class-enum.html

About the Author

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注