Enums
Brief​
If you are used to using integer constants (or worse, a long list of booleans) to express different possible situations, then don't! Enums are meant to do exactly that and are way clearer to read!
// Bad, you need comments to indicate what the numbers mean!
void Character::move(int direction) {
switch(direction) {
case 0: // North
/*...*/
case 1: // East
/*...*/
case 2: // South
/*...*/
case 3: // West
/*...*/
default:
/*...*/
}
}
// Good, the meaning is incorporated in the names of the enum and its values!
enum class Direction {
North,
East,
South,
West,
};
void Character::move(Direction direction) {
switch (direction) {
case Direction::North:
/*...*/
case Direction::East:
/*...*/
case Direction::South:
/*...*/
case Direction::West:
/*...*/
default:
/*...*/
}
}
Use enum class
, not enum
​
enum class
was introduced in C++ as a better version of the enum
from C.
An enum class
doesn't allow implicit conversion with ints and other enums, and gives a proper namespace to your values!
Bad, there is no type checking that ensures we use the right enum
enum Direction { Left, Right, Up, Down };
enum CardinalDirection { North, East, South, West };
void move(CardinalDirection direction);
move(Left); // Bad, this compiles but doesn't do what we want! It will move North!
Bad, this doesn't compile because we are defining two Ok values in the global namespace
enum FilesystemError {
Ok, // Should be renamed to fs_Ok to avoid conflicting with the other `Ok`
ErrorNoPermission,
// etc.
}
enum DatabaseError {
Ok, // Should be renamed to db_Ok to avoid conflicting with the other `Ok`
ErrorConnectionLost,
// etc.
}
///
/// This is equivalent to defining integer constants in the global namespace:
///
static constexpr int Ok = 0;
static constexpr int ErrorNoPermission = 1;
static constexpr int Ok = 0; // Bad, conflicts with the first Ok
static constexpr int ErrorConnectionLost = 1;
All of these problems disappear with enum class
:
Good, the type checking makes sure we use the right enum
enum class Direction { Left, Right, Up, Down };
enum class CardinalDirection { North, East, South, West };
void move(CardinalDirection direction);
move(Direction::Left); // Good, this doesn't compile and gives us a clear error message
Good, this works just fine and we don't need to give weird prefixes to our enum values
enum class FilesystemError {
Ok,
ErrorNoPermission,
// etc.
}
enum class DatabaseError {
Ok,
ErrorConnectionLost,
// etc.
}
using enum
​
Since C++20 you can have a nicer syntax: using enum
allows you to skip the enum name in all your switch cases:
void Character::move(Direction direction)
{
using enum Direction;
switch (direction) {
case North: // More readable than `Direction::North`. We already know that we are dealing with Directions.
/*...*/
case East:
/*...*/
case South:
/*...*/
case West:
/*...*/
default:
/*...*/
}
}