Site

Enums — enum and enum class

Tutorial 8.0  •  C++ / Learn

8.0 What This Teaches

Enumerations give names to a fixed set of integer values. This tutorial covers:

8.1 Plain enum

enum Direction { North, South, East, West };

Direction d = North;   // North is in the enclosing scope
int n = d;             // implicit conversion to int (North = 0)
Plain enum names leak into the enclosing scope. If two enums define Red, they conflict. The implicit conversion to int is also a common source of bugs.

8.2 enum class (Scoped Enum)

enum class Color { Red, Green, Blue };

Color c = Color::Green;   // must qualify with Color::
// int n = c;             // error: no implicit conversion
int n = static_cast<int>(c);   // 1 - explicit cast required
enum class keeps names in the enum's own scope and disables implicit conversion to int. Prefer enum class in new code.

8.3 Underlying Integer Type

enum class Status : uint8_t { Ok = 0, NotFound = 1, Error = 2 };
enum class Flags  : uint32_t { None = 0, Read = 1, Write = 2, Exec = 4 };
The default underlying type is int. Specifying it explicitly controls storage size and enables bitwise flag operations on Flags-style enums.

8.4 Enums in switch

std::string color_name(Color c) {
    switch (c) {
        case Color::Red:   return "Red";
        case Color::Green: return "Green";
        case Color::Blue:  return "Blue";
    }
    return "Unknown";
}
Compilers warn when a switch on an enum class omits a case. This makes exhaustive handling easier to enforce than with integers.

8.5 Example - All Together

// Enums - plain enum, enum class, underlying type, switch.

#include <iostream>
#include <string>

enum Direction { North, South, East, West };

enum class Color { Red, Green, Blue };

enum class Status : uint8_t { Ok = 0, NotFound = 1, Error = 2 };

std::string direction_name(Direction d) {
    switch (d) {
        case North: return "North";
        case South: return "South";
        case East:  return "East";
        case West:  return "West";
    }
    return "Unknown";
}

std::string color_name(Color c) {
    switch (c) {
        case Color::Red:   return "Red";
        case Color::Green: return "Green";
        case Color::Blue:  return "Blue";
    }
    return "Unknown";
}

int main() {
    Direction d = North;
    std::cout << direction_name(d) << " (" << d << ")\n";

    Color c = Color::Green;
    std::cout << color_name(c) << "\n";

    Status s = Status::NotFound;
    std::cout << "status: " << static_cast<int>(s) << "\n";
    return 0;
}
North (0)
Green
status: 1

8.6 Exercise

Exercise
  • Define an enum class Weekday with values Mon through Sun. Write a function is_weekend(Weekday d) that returns true for Sat and Sun.
  • Define an enum class Permission : uint8_t with None=0, Read=1, Write=2, Exec=4. Use bitwise OR to combine permissions and check them with bitwise AND.
  • Add a default: case to a switch on your Weekday enum that prints an error, then observe the compiler warning about the unhandled cases when you also have explicit cases for all values.

8.7 Common Mistakes

Name collision with plain enum

enum Fruit { Apple, Orange };
enum Color { Red, Orange };   // error: Orange already defined
Use enum class to put names in their own scope.

Comparing enum class to integer without cast

Color c = Color::Red;
if (c == 0) { }   // error: no implicit conversion from int to Color
Use static_cast<Color>(0) or compare against a named enum value.

Missing case in switch on enum class

When you add a new value to an enum class, the compiler warns about switch statements that don't handle it - but only if you compile with -Wall and do not have a default: case. Omit default: on exhaustive enums to get this safety check.

8.8 Key Terms

TermMeaning
enumPlain enumeration; names leak into enclosing scope; implicit int conversion
enum classScoped enumeration; names qualified by type; no implicit int conversion
underlying typeThe integer type used to store enum values; default is int
static_cast<int>(e)Explicit conversion from enum class to integer
exhaustive switchA switch that handles every enumerator; compiler warns if a case is missing