枚举类型(enumeration)使我们可以将一组整形常量组织在一起。和类一样,每个枚举类型定义了一种新的类型。枚举属于字面值常量类型。
C++包括两种枚举:限定作用域的和不限定作用域的。C++11新标准引入了限定作用域的枚举类型(scoped enumeration)。定义限定作用域的枚举类型的一般形式是:首先是关键字enum class(或者等价地使用enum struct),随后是枚举类型名字以及用花括号括起来的以逗号分隔的枚举成员(enumerator)列表,最后是一个分号:
enum class open_modes {input, output, append};
我们定义了一个名为open_modes的枚举类型,它包含三个枚举成员:input、output和append。
定义不限定作用域的枚举类型(unscoped enumeration)时省略关键字class(或struct),枚举类型的名字是可选的:
enum color {red, yellow, green}; //不限定作用域的枚举类型 //未命名的、不限定作用域的枚举类型 enum {floatPrec = 6, doublePrec = 10, double_doublePrec = 10};
如果enum是未命名的,则我们只能在定义该enum时定义它的对象。和类的定义类似,我们需要在enum定义的右侧花括号和最后的分号之间提供逗号分隔的声明列表。
枚举成员
在限定作用的枚举类型中,枚举类型的名字遵循常规的作用域准则,并且在枚举类型的作用域之外是不可访问的。与之相反,在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同:
enum color {red, yellow, green}; //不限定作用域的枚举类型 enum stoplight {red, yellow, green}; //错误:重复定义了枚举成员 enum class peppers {red, yellow, green}; //正确:枚举成员被隐藏了 color eyes = green; //正确:不限定作用域的枚举类型的枚举成员位于有效的作用域中 peppers p = green; //错误:peppers的枚举成员不在有效的作用域中 //color::green在有效的作用域中,但是类型错误 color hair = color::red; //正确:允许显示地访问枚举成员 peppers p2 = peppers::red; //正确:使用peppers的red
默认情况下,枚举值从0开始,依次加1。不过我们也能一个或几个枚举成员指定专门的值:
enum class intTypes { charTyp = 8, shortTyp = 16, intTyp = 16, longTyp = 32, long_longTyp = 64 };
由枚举成员intTyp和shortTyp可知,枚举值不一定唯一。如果我们没有显示地提供初始值,则当前枚举成员的值等于之前枚举成员的值加1。
枚举成员是const,因此在初始化枚举成员时提供的初始值必须是常量表达式。也就是说,每个枚举成员本身就是一条常量表达式,我们可以在任何需要常量表达式的地方使用枚举成员。例如,我们可以定义枚举类型的constexpr变量:
constexpr intTypes charbits = intTypes::charTyp;
类似的,我们也可以将一个enum作为switch语句的表达式,而将枚举值作为case标签。出于同样的原因,我们还能将枚举类型作为一个非类型模板形参使用:或者在类的定义中初始化枚举类型的静态数据成员。
和类一样,枚举也定义新的类型
只要enum有名字,我们就能定义并初始化该类型的成员。要想初始化enum对象或者为enum对象赋值,必须使用该类型的一个枚举成员或者该类型的另一个对象:
open_modes om = 2; //错误:2不属于open_modes om = open_modes::input; //正确:input是open_modes的一个枚举成员
一个不限定作用域的枚举类型的对象或枚举成员自动地转换成整形。因此我们可以在任何需要整型值的地方使用它们:
int i = color::red; //正确:不限定作用域的枚举类型的枚举成员隐式地转换成int int j = peppers::red; //错误:限定作用域的枚举类型不会进行隐式转换
指定enum的大小
尽管enum都定义了唯一的类型