Question
I have heard developers recommend using enum class in C++ because it provides better type safety.
What does that mean in practice, and why is enum class considered safer than a plain enum?
For example, how do the two differ when assigning values, comparing them, or using their enumerator names in code?
Short Answer
By the end of this page, you will understand why enum class is usually safer than a plain enum in C++. You will learn how scoped enums prevent accidental conversions, avoid name collisions, and make code more explicit and reliable.
Concept
In C++, both enum and enum class are used to define a fixed set of named values.
Example:
enum Color { Red, Green, Blue };
and
enum class Color { Red, Green, Blue };
These look similar, but they behave differently.
What makes enum class safer?
enum class is safer mainly for two reasons:
- It does not implicitly convert to
int - Its enumerator names stay inside the enum’s scope
1. No accidental implicit conversion to integers
A plain enum can often be used like an integer without you noticing.
enum Color { Red, Green, Blue };
int x = Red; // Allowed
This can lead to bugs because the compiler allows mixing enum values with numbers too easily.
Mental Model
Think of a plain enum like a set of sticky notes with names written on them and then scattered across your desk.
- The names are easy to access.
- But they can get mixed up with other notes.
- They can also be treated like raw numbers too easily.
Think of enum class like labeled containers.
Color::Redstays inside theColorcontainer.TrafficLight::Redstays inside theTrafficLightcontainer.- You must open the right container to get the value.
That extra structure prevents mix-ups.
So the mental model is:
- plain
enum= loose named integers enum class= strongly typed, scoped named values
Syntax and Examples
Plain enum
enum Color { Red, Green, Blue };
Color c = Red;
int n = Red; // implicit conversion allowed
What this means
Redcan be used withoutColor::Redcan become anintautomatically- This is convenient, but easier to misuse
enum class
enum class Color { Red, Green, Blue };
Color c = Color::Red;
// int n = Color::Red; // error
int n = static_cast<int>(Color::Red); // explicit conversion
What this means
- You must write
Color::Red - The compiler does not silently turn it into an integer
- The code is more explicit
Safer comparisons
{ Cat, Dog };
{ Car, Bike };
Animal a = Animal::Cat;
Vehicle v = Vehicle::Car;
Step by Step Execution
Consider this example:
#include <iostream>
enum class Direction { North, South, East, West };
int main() {
Direction d = Direction::East;
if (d == Direction::East) {
std::cout << "Going east\n";
}
}
Step by step
- The program defines a scoped enum named
Direction. - Its possible values are
North,South,East, andWest. - In
main, the variabledis declared with typeDirection. - It is assigned the value
Direction::East. - The
ifstatement comparesdwithDirection::East. - Because both sides are the same enum type and same value, the condition is true.
- The program prints:
Real World Use Cases
enum class is useful anywhere you want a fixed set of meaningful choices.
Common examples
- Application states
enum class AppState { Loading, Ready, Error };
- HTTP or API result categories
enum class RequestStatus { Success, Timeout, Unauthorized };
- User roles
enum class Role { Guest, Member, Admin };
- Game states
enum class GameMode { Menu, Playing, Paused, GameOver };
- Device modes
enum class PowerMode { Off, Sleep, On };
Why it helps in these cases
- The set of valid values is limited and clear.
- The names are self-documenting.
- The compiler prevents accidental mixing with integers or unrelated enums.
- Code becomes easier to read in function parameters and return values.
Example in an API
enum class RequestStatus { Success, Timeout, Unauthorized };
void {
(status == RequestStatus::Timeout) {
}
}
Real Codebase Usage
In real projects, developers often use enum class to make APIs stricter and clearer.
1. Function parameters
enum class LogLevel { Debug, Info, Warning, Error };
void logMessage(LogLevel level, const std::string& message);
This is better than passing an int, because callers cannot accidentally pass unrelated numbers.
2. Guard clauses
void processState(Status status) {
if (status == Status::Rejected) {
return;
}
// continue processing
}
A named enum value makes the guard clause readable.
3. Validation and branching
enum class PaymentResult { Success, Failed, Pending };
bool canShip(PaymentResult result) {
return result == PaymentResult::Success;
}
4. Configuration options
Common Mistakes
1. Forgetting the scope with enum class
Broken code:
enum class Color { Red, Green, Blue };
Color c = Red; // error
Correct:
Color c = Color::Red;
2. Expecting implicit conversion to int
Broken code:
enum class Status { Ok, Error };
int code = Status::Ok; // error
Correct:
int code = static_cast<int>(Status::Ok);
Only do this when you truly need the numeric value.
3. Using plain enum and getting name collisions
Broken code:
enum Color { Red, Green };
enum TrafficLight { Red, Yellow, Green }; // conflict
Comparisons
| Feature | enum | enum class |
|---|---|---|
| Scope of enumerator names | Leaks into surrounding scope | Stays inside enum scope |
| Access syntax | Red | Color::Red |
Implicit conversion to int | Usually allowed | Not allowed |
| Type safety | Weaker | Stronger |
| Name collision risk | Higher | Lower |
| Best for modern C++ | Sometimes | Usually yes |
enum vs
Cheat Sheet
Quick reference
Plain enum
enum Color { Red, Green, Blue };
Color c = Red;
int n = Red; // allowed
Scoped enum
enum class Color { Red, Green, Blue };
Color c = Color::Red;
int n = static_cast<int>(Color::Red);
Key rules
enum classkeeps names scoped:Color::Redenum classdoes not implicitly convert toint- plain
enumexposes names likeReddirectly - plain
enumis easier to misuse as an integer enum classis usually the better default in modern C++
When to use enum class
- fixed set of choices
- function parameters
- state values
- configuration options
FAQ
What is the main safety benefit of enum class in C++?
The main benefit is stronger type safety. enum class prevents implicit conversion to integers and keeps enum names scoped, which reduces accidental misuse.
Why can plain enum be risky?
Plain enum values can behave like integers and their names are placed in the surrounding scope. That can cause accidental comparisons, assignments, or naming conflicts.
Do I always need to use enum class instead of enum?
Not always, but in modern C++, enum class is usually the better default unless you specifically need the older behavior of plain enums.
Why do I have to write Color::Red with enum class?
Because enum class is scoped. The value Red belongs to the type Color, so you access it as Color::Red.
How do I convert an enum class value to an integer?
Use an explicit cast:
Mini Project
Description
Build a small C++ program that models the state of an order in an online store. This project demonstrates why enum class is useful for representing a fixed set of valid states such as Pending, Paid, and Shipped without mixing them up with integers or unrelated values.
Goal
Create a program that stores an order status, checks it safely, and prints a message based on the current state.
Requirements
- Define an
enum classnamedOrderStatuswith at least three values. - Write a function that takes
OrderStatusas a parameter and prints a matching message. - In
main, create an order status variable and pass it to the function. - Use
OrderStatus::ValueNamesyntax consistently. - Do not use raw integers to represent statuses.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.