enum
?An enum
is a type for limiting variables to be one of a set of
named constants
enum Name {
first_choice = <integral constant>, // assignment is optional; default is 0
second_choice, // value is previous value + 1
...
nth_choice,
};
Name variable = second_choice;
The enum
keyword may be used for declaring variables of an
enum type
enum Name variable{second_choice}; // `enum` is optional
Name variable{second_choice}; // same as above
Enums can replace "magic numbers" with meaningful names
// ... using magic constants
// imagine a network request
int status = get(url, buffer);
if (status == 200) { // What is 200??
// ...
} else if (status == 404) { // 404??
// ...
}
// ...
enum Status {
SUCCESS = 200,
NOT_FOUND = 404
};
// imagine a network request
Status status = get(url, buffer);
if (status == SUCCESS) {
// ...
} else if (status == NOT_FOUND) {
// ...
}
Values underlying an enum are automatically created if not assigned
enum Orientation {
NORTH, // 0
EAST, // 1
SOUTH,
WEST,
};
Changing values of these constants is done in a single location
Enum constants are not scoped by their enclosing enum block
enum Orientation { NORTH, EAST, SOUTH, WEST, };
// ...
const uint32_t NORTH = 0; // compiler error: namespace is "polluted"
int
Orientation direction = EAST; // intention is clear
int choice = EAST; // much harder to understand intention later on
Lack of regular forward declaration may require major re-compilation when adding a single enum constant
Forward declaration can be achieved since C++11 by specifying the underlying type
enum Orientation; // ISO C++ forbids forward references to 'enum' types
enum Orientation: uint32_t; // forward declaration with underlying type is OK
#include <iostream>
using std::cout, std::endl;
enum Color {
RED = 5,
GREEN,
BLUE = 5, // outch
};
int main() {
if (RED == BLUE) { // valid (an no compiler warning about this)
cout << "what a mess" << endl;
}
return 0;
}
enum
Constants#include <iostream>
using std::cout, std::endl;
enum Color { RED, GREEN, BLUE, };
enum Orientation { NORTH, EAST, SOUTH, WEST, };
int main() {
if (RED == NORTH) { // valid (at least, decent compilers warn about this)
cout << "what a mess" << endl;
}
return 0;
}
It is common to use switch
when working with an
enum
#include <iostream>
using std::cout, std::endl;
enum Orientation {
NORTH,
EAST,
SOUTH,
WEST,
};
int main() {
Orientation heading = EAST; // user controls movement of character
switch (heading) {
case NORTH:
cout << "Hero moves north...\n";
break;
case EAST:
cout << "Hero moves east...\n";
break;
case SOUTH:
cout << "Hero moves south...\n";
break;
case WEST:
cout << "Hero moves west...\n";
break;
}
return 0;
}
Scoped enums (since C++11) address many of the prior limitations
int
)enum class Name {
first_choice = <integral constant>, // assignment is optional; default is 0
second_choice, // value is previous value + 1
...
nth_choice,
};
Name variable = Name::second_choice;
The same value can still be assigned to different constants within a scoped enum
operator<<
cannot be directly used without overloading
#include <iostream>
#include <utility>
using std::cout, std::endl;
enum class Orientation {
NORTH,
EAST,
SOUTH,
WEST,
};
std::ostream& operator<<(std::ostream& os, Orientation o) {
switch (o) {
case Orientation::NORTH:
os << "north";
break;
case Orientation::EAST:
os << "east";
break;
case Orientation::SOUTH:
os << "south";
break;
case Orientation::WEST:
os << "west";
break;
}
return os;
}
int main() {
Orientation o = Orientation::EAST; // user controls movement of character
std::cout << "The hero faces towards " << o << "." << std::endl;
std::cout << std::to_underlying(o) << std::endl; // since C++23
return 0;
}
Download scoped_enum.cpp