枚举

枚举 是由一组表示整数常量 (称为 枚举常量) 的指定值组成的数据类型。 枚举也称为 枚举类型 ,因为在为每个枚举类型创建名称时,必须列出 (枚举) 每个值。 除了提供定义和分组整数常量集的方法外,枚举对于具有少量可能值的变量也很有用。

您可以将枚举类型与该类型的变量定义分开声明,如 枚举类型定义枚举变量声明中所述; 也可以定义枚举数据类型以及在一个语句中具有该类型的所有变量,如 枚举类型和单个语句中的变量定义中所述。

枚举类型定义

枚举类型定义包含 enumC++11enum classenum structC++11 关键字 ,后跟可选标识符(枚举标记)、 可选基础类型说明符 C++11、可选基础类型说明符C++11以及用花括号括起来的枚举项列表。 C++11对于范围列举,标识符是必须的。C++11 逗号分隔枚举列表中的每个枚举项。 C99 允许在最后一个枚举符与右花括号之间使用尾部逗号。C++11 C++11 标准也采用了这一功能。C++11

枚举定义语法

读取语法图跳过可视语法图enum标记标识{ ,枚举符 };
C++11

未限定范围的枚举定义语法

读取语法图跳过可视语法图enum 标记标识:type_说明符nested_name_说明符::标记标识:type_说明符 { ,枚举符 };

限定范围的枚举定义语法

读取语法图跳过可视语法图 enum classenum struct nested_name_说明符::标记标识 :type_说明符{ ,枚举符 };

枚举正向声明语法

读取语法图跳过可视语法图enum标记标识:type_说明符enum classenum struct标记标识:type_说明符;

关键字 enum 声明未限定范围的枚举类型,其枚举是未限定范围的枚举。 关键字 enum classenum struct 声明作用域枚举类型,其枚举是作用域枚举。 关键字 enum classenum struct 在语义上等效。

对于未限定作用域的枚举,将同时在枚举说明符的作用域和立即包含枚举说明符的作用域中声明每个枚举符。

对于限定范围的枚举,将在枚举说明符的作用域中声明每个枚举符。 此外,作用域枚举不允许通过整数提升将枚举符 (或枚举类型的对象) 的值转换为整数,但允许显式强制转换为 intcharfloat或任何其他标量类型。 例如:
enum class Colour { orange, green, purple };
enum class Fruit { apple, pear, grape, orange };

void functionx(int) {}
void functionx(Colour) {}
void functionx(Fruit) {}

int main()
{
  functionx(green);            // error, green is not introduced into
                               // the global scope
  functionx(Colour::green);    // calls functionx(Colour)
  functionx(Fruit::apple);     // calls functionx(Fruit)
  int i = Colour::orange;      // error, no conversion from Colour to int
  int j = (int)Colour::green;  // valid, explicit cast to integer is allowed
}
C++11

tag_identifier 为枚举类型提供名称。 如果未提供标记名称,那么必须将所有引用枚举类型的变量定义放在该类型的声明中,如 枚举类型和变量定义在单个语句中中所述。 同样,不能将类型限定符与枚举定义配合使用; 放在 enum 关键字前面的类型限定符只能应用于在类型定义中声明的变量。

C++11type_specifier 明确指定枚举的底层类型。 每个枚举都具有底层类型。 type_说明符 可以是任何整数类型。 请注意,枚举类型不是整数类型。 通过指定枚举的底层类型,可以确保程序正确性并在结构中可靠地使用枚举。 如果未指定 type_说明符 ,那么将按如下所示确定枚举的底层类型:
  • 如果枚举具有作用域,那么底层类型具有固定类型 int
  • 如果枚举未限定范围,那么底层类型是可以表示枚举中定义的所有枚举符值的整数类型。
例如:
// the underlying type is "unsigned int"
enum Colour : unsigned int { orange = 0, green = 1, purple = 0x02U }; 

// the underlying type is "unsigned long"
enum class E : unsigned long { E1 = 0, E2 = 1, Emax = 0xFFFFFFF0U };

// if the type_specifier is not specified, the underlying type 
// is "int" for the scoped enumeration
enum class A { A1, A2, A3 = 100, A4 };

// the underlying type is an integer type enough to represent the given
// enumerator values, eg. [signed/unsigned] long long
enum A { A1, A2, A3 = 100000000000000000000, A4 };
nested_name_说明符 是指先前声明枚举的类或名称空间。 例如:
class C{

//Declaration of a scoped enumeration A. 
enum class A;            

};

// C is the nested_name_specifier that refers to the class where
// the enumeration A was declared.
enum class C::A { a, b };  

您可以在不提供枚举符列表的情况下转发声明枚举。 枚举的正向声明可以减少编译时间和依赖关系,因为它可以物理地分离枚举的实现细节及其用法。

枚举的正向声明是当前范围内枚举的重新声明或新枚举的声明。 同一枚举的重新声明必须与先前声明匹配。 重新声明枚举的规则如下:
  • 稍后不能将限定范围的枚举重新声明为未限定范围或具有其他底层类型。
  • 以后不能将未限定范围的枚举重新声明为限定范围的枚举,并且每个重新声明都必须包含指定相同底层类型的 type_说明符
例如:
enum E1 : unsigned long;        // valid, forward declaration of an unscoped 
                                // enumeration with the underlying type 
                                // "unsigned long"

enum class E2 : char;           // valid, forward declaration of a scoped 
                                // enumeration with the underlying type 
                                // "char"

enum class E3;                  // valid, forward declaration of a scoped 
                                // enumeration with the implied underlying
                                // type "int" 

enum E4;                        // error, you must specify the underlying type
                                // when you forward declare an unscoped 
                                // enumeration 

enum E1 : unsigned long;        // valid, the redeclaration of E1 matches the
                                // previous declaration of E1

enum class E2 : short;          // error, the previously declared enumeration
                                // E2 had the underlying type "char", and it 
                                // cannot be redeclared with a different 
                                // underlying type

enum E3 : int;                  // error, the previously declared enumeration
                                // E3 was a scoped enumeration, and it cannot
                                // be redeclared as an unscoped enumeration

enum class E3 : int { a, b, c };// valid, definition of E3

C++11

详细说明类型说明符

阐述的类型说明符语法

读取语法图跳过可视语法图enum 标记标识x

阐述的类型说明符引用先前声明的枚举。 x 是类型为 tag_identifier的变量。

enum 关键字可用于在变量声明或定义期间引用限定范围或未限定范围的枚举。 例如:
// a scoped enumeration
enum class color { red, white, black, yellow }; 

// an unscoped enumeration
enum letter {A, B, C, D};   

// valid, regular type name usage
color pic1 = color :: white;

// valid, elaborated type usage
enum color pic2 = color :: red; 

不能在阐述的类型说明符中使用 enum classenum struct 。 例如:
enum class color pic3 = color :: black;    // invalid
未限定范围的枚举的阐述类型说明符与限定范围的枚举的阐述类型说明符相同。 例如:
enum letter let1 = letter :: A;            // valid

枚举成员

枚举成员或 枚举器的列表为数据类型提供了一组值。

枚举成员声明语法

读取语法图跳过可视语法图标识=枚举常量

仅限 C 在C语言中, 枚举常量属于 类型。 int 如果将一个常量表达式用作初始化器,则表达式的值不能超过 int 的范围(即头文件 limits.h 中定义的INT_MIN到INT_MAX)。 仅限 C

仅限 C + + 在C++中,每个枚举常量都有一个可以提升为有符号或无符号整数值,且不必是整数类型的不同类型。 在允许使用整数常量的任何地方,或者允许使用枚举类型值的任何地方,都可以使用枚举常量。仅限 C + +

枚举常量的值通过以下方式确定:

  1. 枚举常量后的等号 (=) 和常量表达式给出了枚举常量的显式值。 枚举常量表示常量表达式的值。
  2. 如果没有为第一个枚举符指定显式值,那么它将采用值 0 (零)。
  3. 没有显式分配值的枚举常量将接收到大于先前枚举常量所表示的值的整数值。
C++11
以下枚举的底层类型是固定的。 通过遵循先前规则获得的枚举符值必须可由底层类型表示。 否则,枚举格式不正确。
  • 有作用域的枚举
  • 指定了显式底层类型的未限定范围的枚举
未限定范围的枚举的底层类型 (无显式底层类型) 不是固定的,由枚举符值确定,如下所示:
  • 底层类型是不大于 int 的实现定义的整数类型,可以表示枚举的所有值。
  • 如果枚举的值不可由 intunsigned int表示,那么底层类型是足以表示所有枚举符值的实现定义的整数类型。
  • 如果没有类型可以表示所有枚举符值,那么枚举格式不正确。
C++11
以下数据类型声明将 oatswheatbarleycornrice 作为枚举常量列出。 每个常量下的数字显示整数值。
enum grain { oats, wheat, barley, corn, rice };
   /*         0      1      2      3     4         */

enum grain { oats=1, wheat, barley, corn, rice };
   /*         1        2      3      4     5       */

enum grain { oats, wheat=10, barley, corn=20, rice };
   /*          0     10        11     20       21  */
可以将同一整数与两个不同的枚举常量相关联。 例如,以下定义有效。 标识 suspendhold 具有相同的整数值。
enum status { run, clear=5, suspend, resume, hold=6 };
   /*          0      5        6       7       6       */
每个 unscoped 枚举常量在定义枚举的作用域内必须唯一。 在以下示例中, averagepoor 的第二个声明会导致编译器错误:
func()
    {
       enum score { poor, average, good };
       enum rating { below, average, above };
       int poor;
    }
C++11使用范围枚举可以避免此类错误,因为枚举器仅在枚举的范围内声明,而不是在包含枚举的范围内声明。C++11

枚举变量声明

必须先声明枚举数据类型,然后才能定义具有该类型的变量。

枚举变量声明语法

读取语法图跳过可视语法图 storage_class_说明符类型限定符 enum 标记标识 声明符
tag_identifier 指示先前定义的枚举数据类型。

仅限 C + + 枚举变量声明中,关键字 是可选的。 enum仅限 C + +

单个语句中的枚举类型和变量定义

您可以通过在变量定义之后使用声明符和可选初始化方法在一个语句中定义类型和变量。 要为变量指定存储类说明符,必须将存储类说明符放在声明的开头。 例如:
register enum score { poor=1, average, good } rating = good;
仅限 C + + C++还允许你把存储类放在声明器列表的前面。 例如:
enum score { poor=1, average, good } register rating = good;
仅限 C + +
这些示例中的任何一个都等同于以下两个声明:
enum score { poor=1, average, good };
register enum score rating = good;

这两个示例都定义了枚举数据类型 score 和变量 ratingrating 具有存储类说明符 register,数据类型 enum score和初始值 good

通过将数据类型定义与具有该数据类型的所有变量的定义组合,可以使数据类型保持未命名状态。 例如:
enum { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,
      Saturday } weekday;

定义变量 weekday,可以为其分配任何指定的枚举常量。 但是,不能使用这组枚举常量来声明任何其他枚举变量。