Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 68: Enumeration

Section 68.1: Iteration over an enum

There is no built-in to iterate over enumeration.

But there are several ways

for enum with only consecutive values:

enum E { Begin,

E1 = Begin, E2,

// .. En, End

};

for (E e = E::Begin; e != E::End; ++e) { // Do job with e

}

Version ≥ C++11

with enum class, operator ++ has to be implemented:

E& operator ++ (E& e)

{

if (e == E::End) {

throw std::out_of_range("for E& operator ++ (E&)");

}

e = E(static_cast<std::underlying_type<E>::type>(e) + 1); return e;

}

using a container as std::vector

enum E { E1 = 4, E2 = 8, // .. En

};

std::vector<E> build_all_E()

{

const E all[] = {E1, E2, /*..*/ En};

return std::vector<E>(all, all + sizeof(all) / sizeof(E));

}

std::vector<E> all_E = build_all_E();

and then

for (std::vector<E>::const_iterator it = all_E.begin(); it != all_E.end(); ++it) {

GoalKicker.com – C++ Notes for Professionals

355

E e = *it;

// Do job with e;

}

Version ≥ C++11

or std::initializer_list and a simpler syntax:

enum E { E1 = 4, E2 = 8, // .. En

};

constexpr std::initializer_list<E> all_E = {E1, E2, /*..*/ En};

and then

for (auto e : all_E) { // Do job with e

}

Section 68.2: Scoped enums

C++11 introduces what are known as scoped enums. These are enumerations whose members must be qualified with enumname::membername. Scoped enums are declared using the enum class syntax. For example, to store the colors in a rainbow:

enum class rainbow { RED,

ORANGE,

YELLOW,

GREEN,

BLUE,

INDIGO,

VIOLET

};

To access a specific color:

rainbow r = rainbow::INDIGO;

enum classes cannot be implicitly converted to ints without a cast. So int x = rainbow::RED is invalid.

Scoped enums also allow you to specify the underlying type, which is the type used to represent a member. By default it is int. In a Tic-Tac-Toe game, you may store the piece as

enum class piece : char { EMPTY = '\0',

X = 'X',

O = 'O',

};

As you may notice, enums can have a trailing comma after the last member.

GoalKicker.com – C++ Notes for Professionals

356

Section 68.3: Enum forward declaration in C++11

Scoped enumerations:

...

enum class Status; // Forward declaration Status doWork(); // Use the forward declaration

...

enum class Status { Invalid, Success, Fail };

Status doWork() // Full declaration required for implementation

{

return Status::Success;

}

Unscoped enumerations:

...

enum Status: int; // Forward declaration, explicit type required Status doWork(); // Use the forward declaration

...

enum Status: int{ Invalid=0, Success, Fail }; // Must match forward declare type static_assert( Success == 1 );

An in-depth multi-file example can be found here: Blind fruit merchant example

Section 68.4: Basic Enumeration Declaration

Standard enumerations allow users to declare a useful name for a set of integers. The names are collectively referred to as enumerators. An enumeration and its associated enumerators are defined as follows:

enum myEnum

{

enumName1,

enumName2,

};

An enumeration is a type, one which is distinct from all other types. In this case, the name of this type is myEnum. Objects of this type are expected to assume the value of an enumerator within the enumeration.

The enumerators declared within the enumeration are constant values of the type of the enumeration. Though the enumerators are declared within the type, the scope operator :: is not needed to access the name. So the name of the first enumerator is enumName1.

Version ≥ C++11

The scope operator can be optionally used to access an enumerator within an enumeration. So enumName1 can also be spelled myEnum::enumName1.

Enumerators are assigned integer values starting from 0 and increasing by 1 for each enumerator in an enumeration. So in the above case, enumName1 has the value 0, while enumName2 has the value 1.

Enumerators can also be assigned a specific value by the user; this value must be an integral constant expression. Enumerators who's values are not explicitly provided will have their value set to the value of the previous enumerator + 1.

enum myEnum

GoalKicker.com – C++ Notes for Professionals

357

{

enumName1 = 1, // value

will be 1

enumName2 = 2, // value

will be 2

enumName3,

// value

will be 3, previous value + 1

enumName4 = 7, // value

will be 7

enumName5,

// value

will be 8

enumName6 = 5, // value

will be 5, legal to go backwards

enumName7 = 3, // value

will be 3, legal to reuse numbers

enumName8 = enumName4 +

2, // value will be 9, legal to take prior enums and adjust them

};

Section 68.5: Enumeration in switch statements

A common use for enumerators is for switch statements and so they commonly appear in state machines. In fact a useful feature of switch statements with enumerations is that if no default statement is included for the switch, and not all values of the enum have been utilized, the compiler will issue a warning.

enum State { start, middle, end

};

...

switch(myState) { case start:

...

case middle:

...

} // warning: enumeration value 'end' not handled in switch [-Wswitch]

GoalKicker.com – C++ Notes for Professionals

358