Enumerations

An enumeration is a data type consisting of a set of named values that represent integral constants, known as enumeration constants. An enumeration is also referred to as an enumerated type because you must list (enumerate) each of the values in creating a name for each of them. In addition to providing a way of defining and grouping sets of integral constants, enumerations are useful for variables that have a small number of possible values.

You can declare an enumeration type separately from the definition of variables of that type, as described in Enumeration type definition and Enumeration variable declarations; or you can define an enumeration data type and all variables that have that type in one statement, as described in Enumeration type and variable definitions in a single statement.

Enumeration type definition

An enumeration type definition contains the enum, C++11enum class, or enum structC++11 keyword followed by an optional identifier (the enumeration tag), C++11an optional underlying type specifierC++11, and a brace-enclosed list of enumerators. C++11For scoped enumerations, the identifier is mandatory.C++11 A comma separates each enumerator in the enumerator list. C99 allows a trailing comma between the last enumerator and the closing brace. XL C++ also supports this feature, for compatibility with C99.

Read syntax diagramSkip visual syntax diagram
Enumeration definition syntax

                                    .-,----------.         
                                    V            |         
>>---enum----+----------------+--{----enumerator-+--}--;-------><
             '-tag_identifier-'                            

C++11
Read syntax diagramSkip visual syntax diagram
Unscoped enumeration definition syntax

>>-enum--+-+----------------+--+-------------------+--------------------+-->
         | '-tag_identifier-'  '-:--type_specifier-'                    |   
         '-nested_name_specifier--::--tag_identifier--:--type_specifier-'   

      .-,----------.         
      V            |         
>--{----enumerator-+--}--;-------------------------------------><

Read syntax diagramSkip visual syntax diagram
Scoped enumeration definition syntax

>>-+-enum class--+--+---------------------------+--tag_identifier-->
   '-enum struct-'  '-nested_name_specifier--::-'                   

                             .-,----------.         
                             V            |         
>--+-------------------+--{----enumerator-+--}--;--------------><
   '-:--type_specifier-'                            

Read syntax diagramSkip visual syntax diagram
Enumeration forward declaration syntax

>>-+-enum--tag_identifier--:--type_specifier----------------+--->
   '-+-enum class--+--tag_identifier--+-------------------+-'   
     '-enum struct-'                  '-:--type_specifier-'     

>--;-----------------------------------------------------------><

The keyword enum declares an unscoped enumeration type, whose enumerators are unscoped enumerators. The keywords enum class or enum struct declare a scoped enumeration type, whose enumerators are scoped enumerators. The keywords enum class and enum struct are semantically equivalent.

For the unscoped enumeration, each enumerator is declared both in the scope of the enumeration specifier, and the scope that immediately contains the enumeration specifier.

For the scoped enumeration, each enumerator is declared in the scope of the enumeration specifier. In addition, the scoped enumeration does not allow the value of an enumerator (or an object of an enumeration type) to be converted to an integer by integral promotion, but explicit cast to int, char, float, or any other scalar type is allowed. For example:
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

The tag_identifier gives a name to the enumeration type. If you do not provide a tag name, you must put all variable definitions that refer to the enumeration type within the declaration of the type, as described in Enumeration type and variable definitions in a single statement. Similarly, you cannot use a type qualifier with an enumeration definition; type qualifiers placed in front of the enum keyword can only apply to variables that are declared within the type definition.

C++11The type_specifier specifies the underlying type of an enumeration explicitly. Each enumeration has an underlying type. The type_specifier can be any integer type. Note that the enumeration type is not an integer type. By specifying the underlying type of an enumeration, you can ensure program correctness and use the enumeration reliably in structs. If type_specifier is not specified, the underlying type of the enumeration is determined as follows:
  • If the enumeration is scoped, the underlying type has the fixed type int.
  • If the enumeration is unscoped, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration.
For example:
// 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 };
The nested_name_specifier refers to the class or namespace where the enumeration was previously declared. For example:
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 };  

You can forward declare an enumeration without providing a list of enumerators. The forward declaration of an enumeration can reduce compile time and dependencies, because it can physically decouple the implementation specifics of the enumeration and its usage.

The forward declaration of an enumeration is a redeclaration of an enumeration in the current scope or a declaration of a new enumeration. The redeclaration of the same enumeration must match the previous declaration. The rules for the redeclaration of enumerations are as follows:
  • A scoped enumeration cannot be later redeclared as unscoped or with a different underlying type.
  • An unscoped enumeration cannot be later redeclared as scoped and each redeclaration must include a type_specifier specifying the same underlying type.
For example:
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

Elaborated type specifier

Read syntax diagramSkip visual syntax diagram
Elaborated type specifier syntax

>>-enum--tag_identifier--x-------------------------------------><

The elaborated type specifier refers to a previously declared enumeration. The x is a variable that has the type tag_identifier.

The enum keyword can be used to refer to scoped or unscoped enumerations during variable declaration or definition. For example:
// 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; 
You cannot use enum class or enum struct in the elaborated type specifier. For example:
enum class color pic3 = color :: black;    // invalid
The elaborated type specifier for an unscoped enumeration is the same as that for a scoped enumeration. For example:
enum letter let1 = letter :: A;            // valid

Enumeration members

The list of enumeration members, or enumerators, provides the data type with a set of values.

Read syntax diagramSkip visual syntax diagram
Enumeration member declaration syntax

>>-identifier--+-------------------------+---------------------><
               '-=--enumeration_constant-'   

C only In C, an enumeration constant is of type int. If a constant expression is used as an initializer, the value of the expression cannot exceed the range of int (that is, INT_MIN to INT_MAX as defined in the header limits.h).

C++ only In C++, each enumeration constant has a value that can be promoted to a signed or unsigned integer value and a distinct type that does not have to be integral. You can use an enumeration constant anywhere an integer constant is allowed, or anywhere a value of the enumeration type is allowed.

The value of an enumeration constant is determined in the following way:

  1. An equal sign (=) and a constant expression after the enumeration constant gives an explicit value to the enumeration constant. The enumeration constant represents the value of the constant expression.
  2. If no explicit value is assigned to the first enumerator, then it takes the value 0 (zero).
  3. Enumeration constants with no explicitly assigned values receive the integer value that is one greater than the value represented by the previous enumeration constant.
C++11
The underlying type of the following enumerations is fixed. The enumerator values obtained by following the previous rules must be representable by the underlying type. Otherwise the enumeration is ill-formed.
  • Scoped enumerations
  • Unscoped enumerations with explicit underlying type specified
The underlying type of an unscoped enumeration, with no explicit underlying type, is not fixed, and is determined by enumerator values as follows:
  • The underlying type is an implementation-defined integral type that is not larger than int and can represent all values of the enumeration.
  • If the values of the enumeration are not representable by an int or unsigned int, the underlying type is an implementation-defined integral type large enough to represent all enumerator values.
  • If no type can represent all enumerator values, the enumeration is ill-formed.
C++11
The following data type declarations list oats, wheat, barley, corn, and rice as enumeration constants. The number under each constant shows the integer value.
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  */
It is possible to associate the same integer with two different enumeration constants. For example, the following definition is valid. The identifiers suspend and hold have the same integer value.
enum status { run, clear=5, suspend, resume, hold=6 };
   /*          0      5        6       7       6       */
Each unscoped enumeration constant must be unique within the scope in which the enumeration is defined. In the following example, the second declarations of average and poor cause compiler errors:
func()
    {
       enum score { poor, average, good };
       enum rating { below, average, above };
       int poor;
    }
C++11With scoped enumerations, you can avoid such an error, because the enumerators are declared only in the scope of the enumeration, not the scope containing the enumeration.C++11

Enumeration variable declarations

You must declare the enumeration data type before you can define a variable having that type.

Read syntax diagramSkip visual syntax diagram
Enumeration variable declaration syntax

   .-----------------------------.                         
   V                             |                         
>>---+-------------------------+-+--enum--tag_identifier-------->
     +-storage_class_specifier-+                           
     '-type_qualifier----------'                           

>--declarator--------------------------------------------------><

The tag_identifier indicates the previously-defined data type of the enumeration.

C++ only The keyword enum is optional in enumeration variable declarations.

Enumeration type and variable definitions in a single statement

You can define a type and a variable in one statement by using a declarator and an optional initializer after the variable definition. To specify a storage class specifier for the variable, you must put the storage class specifier at the beginning of the declaration. For example:
register enum score { poor=1, average, good } rating = good;
C++ only C++ also lets you put the storage class immediately before the declarator list. For example:
enum score { poor=1, average, good } register rating = good;
Either of these examples is equivalent to the following two declarations:
enum score { poor=1, average, good };
register enum score rating = good;

Both examples define the enumeration data type score and the variable rating. rating has the storage class specifier register, the data type enum score, and the initial value good.

Combining a data type definition with the definitions of all variables having that data type lets you leave the data type unnamed. For example:
enum { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,
      Saturday } weekday;

defines the variable weekday, which can be assigned any of the specified enumeration constants. However, you cannot declare any additional enumeration variables using this set of enumeration constants.