在 C++ 11 以前的标准中,枚举没有作用域的限制,可以这样定义:

enum { red, blue, green };

enum Color { red, blue, green };

引用的时候也无需加任何限制,不同的枚举不能有重名。

        在 C++ 11 及以后的版本中,枚举看成一个用户定义类型,在 enum 关键字后加 class struct 限制,表明其有作用域限制。例如:

enum class Color { red, blue, green };
enum class Traffic_light { green, yellow, red };
Color col = Color::red;
Traffic_light light = Traffic_light::red;

        请注意,枚举成员(例如 red位于其所属枚举类的作用域内,因此它们可以在不同的枚举类中重复使用而不会产生混淆。例如,Color::red 指的是 Color类中的 red ,这与 Traffic_light::red 是不同的。

        枚举用于表示小范围的整数值集合。使用枚举旨在提高代码的可读性,并减少出错的几率——若不采用这些具有象征意义(且易于记忆)的枚举成员名称,代码将难以达到这一效果。

        紧随在 enum 关键字之后的 class struct 关键字表明,该枚举类型是强类型的,且其枚举成员具有作用域。由于枚举类属于独立的类型,它们有助于防止对常量的意外误用。具体而言,我们无法将 Traffic_light 类型的值与 Color 类型的值混用:        

Color x1 = red; // 错订单号 : 哪一个 red?
Color y2 = Traffic_light::red; // 错误: 那个 red 不是一个 Color 类型
Color z3 = Color::red; // 可行
auto x4 = Color::red; // 可行: Color::red 是一个 Color 类型

        类似地,我们不能隐式地混合 Color 和整数值:

int i = Color::red; // 错误: Color::red 不是一个 int 值
Color c = 2; // 初始化错误: 2 不是一个 Color 类型

        捕获针对枚举类型的尝试转换是一种有效的防错手段;不过,我们往往需要利用枚举类型的底层类型值(默认为 int)来初始化枚举,因此这种操作是允许的——正如从底层类型进行的显式转换一样:

Color x = Color{5}; // 可行, 但冗余
Color y {6}; // 同样可行

        类似地,我们可以将 enum 值显式转换为其底层类型:

int x = int(Color::red);

        默认情况下,一个 enum class 已定义了赋值、初始化和比较(例如 == 和 <;§1.4)操作,且仅限于这些操作。不过,由于枚举是一种用户自定义类型,因此我们可以为其定义运算符:

Traffic_light& operator++(Traffic_light& t) // 前增: ++
{
switch (t) {
case Traffic_light::green: return t=Traffic_light::yellow;
case Traffic_light::yellow: return t=Traffic_light::red;
case Traffic_light::red: return t=Traffic_light::green;
}
}
auto signal = Traffic_light::red;
Traffic_light next = ++signal; // 下一个成为 Traffic_light::green

        如果重复书写枚举名称 Traffic_light 变得过于繁琐,我们可以在具体作用域内将其进行缩写:

Traffic_light& operator++(Traffic_light& t) // 前增: ++
{
using enum Traffic_light; // 在此, 我们正在使用的是 Traffic_light
switch (t) {
case green: return t=yellow;
case yellow: return t=red;
case red: return t=green;
}
}

        如果你不希望总是显式地限定枚举成员的名称,并且希望枚举成员的值为 int 类型(无需显式转换),可以将 enum class 中的 class 关键字移除,从而得到一个“普通”枚举。普通枚举中的成员会被引入到与其枚举类型名称相同的命名域中,并可隐式转换为其对应的整型值。例如:

enum Color { red, green, blue };
int col = green;

在此处,col 获取的值为 1。默认情况下,枚举成员的整型值从 0 开始,且每增加一个枚举成员,其值便递增 1 。这种“普通”枚举自 C++(以及 C)语言诞生之初便已存在;因此,尽管它们的行为规范性稍逊一筹,但在当下的代码中依然十分常见。

可以指定枚举的底层类型:

enum class Handle : std::uint32_t { Invalid = 0 };
Handle h{42}; // C++17

using enum   声明引入了指定枚举类型的枚举成员名称,其效果等同于为该枚举类型的每一个成员分别撰写了一条 using 声明。当处于类作用域内时,using enum 声明会将指定枚举类型的成员作为该作用域的成员添加进来,从而使其可参与成员查找。

enum class fruit { orange, apple };

class S
{
public:
	using enum fruit; // 可行: 引入 orange 和 apple 到 S
};

void f()
{
	S s;
	s.orange;  // 可行: 名称 fruit::orange
	S::orange; // 可行: 名称 fruit::orange
}

更多推荐