enum
In C++, enum (enumeration types) let you define related constants as a group. Since C++11, enum class (scoped enumeration) was added, enabling type-safe constants without polluting the surrounding namespace.
Syntax
// ========================================
// enum and enum class basic syntax
// ========================================
// Traditional enum (unscoped)
// Enumerators are exposed directly in the surrounding scope
enum InvestigationStatus {
CLEAR, // value 0 (assigned automatically)
WATCHING, // value 1
SUSPECT, // value 2
TARGET // value 3
};
// Explicit value assignment
enum SuspectLevel {
LEVEL_LOW = 1,
LEVEL_MEDIUM = 50,
LEVEL_HIGH = 100
};
// enum class (scoped): C++11 and later
// Enumerators are accessed with the class name (type-safe)
enum class JudgementStatus {
CLEAR, // Access as JudgementStatus::CLEAR
CAUTION,
DANGEROUS,
CRIMINAL
};
// Specify the underlying type (e.g., unsigned char)
enum class ThreatLevel : unsigned char {
LOW = 1,
MEDIUM = 2,
HIGH = 3
};
// Usage
InvestigationStatus is = SUSPECT; // Traditional enum (no prefix needed)
JudgementStatus js = JudgementStatus::DANGEROUS; // enum class (class name required)
Syntax Reference
| Syntax / Concept | Description |
|---|---|
| enum name { enumerator, ... } | Defines a traditional unscoped enumeration. Enumerators are exposed in the surrounding scope and implicitly convert to int. |
| enum class name { enumerator, ... } | Scoped enumeration type introduced in C++11. Enumerators must be accessed with the class name and do not implicitly convert to integers. Type-safe. |
| enum class name : type { ... } | Specifies the underlying type (int, unsigned char, etc.) explicitly. Useful for memory optimization and binary compatibility. |
| enumerator = value | Assigns an explicit integer value to an enumerator. If omitted, the value is the previous enumerator + 1 (starting from 0). |
| static_cast<int>(enumerator) | Converts an enum class value to an integer. Explicit cast is required because enum class prohibits implicit conversion. |
| Use with switch statement | Enumeration types can be used as case labels in switch. Covering all enumerators lets you omit default and leverage compiler warnings. |
Sample Code
deathnote_enum.cpp
// ========================================
// deathnote_enum.cpp
// Defines investigation statuses and evidence levels
// from DEATH NOTE using enum / enum class
// ========================================
#include <iostream>
#include <string>
// Traditional enum: InvestigationStatus
// No scope, so CLEAR etc. can be used without a prefix
enum InvestigationStatus {
CLEAR = 0,
WATCHING = 1,
SUSPECT = 2,
TARGET = 3
};
// enum class: InvestigatorRole (type-safe)
enum class InvestigatorRole {
LEAD,
ANALYST,
FIELD
};
// enum class: EvidenceLevel with unsigned char underlying type
enum class EvidenceLevel : unsigned char {
WEAK = 1,
MEDIUM = 2,
STRONG = 3
};
std::string statusLabel(InvestigationStatus status) {
switch (status) {
case CLEAR: return "No suspicion";
case WATCHING: return "Under observation";
case SUSPECT: return "Prime suspect";
case TARGET: return "Confirmed target";
default: return "Unknown";
}
}
std::string roleLabel(InvestigatorRole role) {
switch (role) {
case InvestigatorRole::LEAD: return "Lead investigator";
case InvestigatorRole::ANALYST: return "Analyst";
case InvestigatorRole::FIELD: return "Field investigator";
default: return "Unknown";
}
}
std::string evidenceDesc(EvidenceLevel level) {
switch (level) {
case EvidenceLevel::WEAK: return "Weak evidence — further investigation needed";
case EvidenceLevel::MEDIUM: return "Moderate evidence — continue surveillance";
case EvidenceLevel::STRONG: return "Strong evidence — warrant can be requested";
default: return "Unknown level";
}
}
struct Investigator {
std::string name;
InvestigatorRole role;
InvestigationStatus status;
};
int main() {
Investigator members[] = {
{ "Yagami Light", InvestigatorRole::LEAD, WATCHING },
{ "L", InvestigatorRole::LEAD, CLEAR },
{ "Amane Misa", InvestigatorRole::FIELD, SUSPECT },
{ "Near", InvestigatorRole::ANALYST, CLEAR },
{ "Mello", InvestigatorRole::FIELD, WATCHING }
};
int memberCount = sizeof(members) / sizeof(members[0]);
std::cout << "=== Kira Investigation Team — Status ===" << std::endl << std::endl;
for (int i = 0; i < memberCount; i++) {
const Investigator& inv = members[i];
std::cout << "Name: " << inv.name << std::endl;
std::cout << " Role : " << roleLabel(inv.role) << std::endl;
std::cout << " Status: " << statusLabel(inv.status) << std::endl;
int roleInt = static_cast<int>(inv.role);
std::cout << " Role code: " << roleInt << std::endl << std::endl;
}
std::cout << "=== Evidence Levels ===" << std::endl << std::endl;
EvidenceLevel levels[] = { EvidenceLevel::WEAK, EvidenceLevel::MEDIUM, EvidenceLevel::STRONG };
for (int i = 0; i < 3; i++) {
int val = static_cast<int>(levels[i]);
std::cout << "Level " << val << ": " << evidenceDesc(levels[i]) << std::endl;
}
return 0;
}
g++ -std=c++11 deathnote_enum.cpp -o deathnote_enum ./deathnote_enum === Kira Investigation Team — Status === Name: Yagami Light Role : Lead investigator Status: Under observation Role code: 0 Name: L Role : Lead investigator Status: No suspicion Role code: 0 Name: Amane Misa Role : Field investigator Status: Prime suspect Role code: 2 Name: Near Role : Analyst Status: No suspicion Role code: 1 Name: Mello Role : Field investigator Status: Under observation Role code: 2 === Evidence Levels === Level 1: Weak evidence — further investigation needed Level 2: Moderate evidence — continue surveillance Level 3: Strong evidence — warrant can be requested
Common Mistake 1: Implicitly converting an enum class value to int
enum class prohibits implicit integer conversion, so directly comparing or using arithmetic with int causes a compile error.
// NG: Using enum class value implicitly as int
enum class EvidenceLevel { WEAK = 1, MEDIUM = 2, STRONG = 3 };
EvidenceLevel lv = EvidenceLevel::MEDIUM;
int val = lv; // Compile error: implicit conversion not allowed
if (lv == 2) { } // Compile error: cannot compare with int directly
OK: Use static_cast for explicit conversion.
// OK: Explicit conversion with static_cast
enum class EvidenceLevel { WEAK = 1, MEDIUM = 2, STRONG = 3 };
EvidenceLevel lv = EvidenceLevel::MEDIUM;
int val = static_cast<int>(lv); // 2
if (lv == EvidenceLevel::MEDIUM) { } // Comparing enum class values is OK
g++ -std=c++11 enum_cast.cpp -o enum_cast ./enum_cast EvidenceLevel::MEDIUM value: 2
Common Mistake 2: Name collision with traditional enum enumerators
Traditional enum enumerators are exposed without a scope prefix. If multiple enums have the same enumerator name, a compile error occurs.
// NG: Same enumerator name in multiple enums
enum InvestigationStatus { CLEAR, SUSPECT };
enum WeatherStatus { CLEAR, CLOUDY }; // Error: CLEAR is ambiguous
OK: Switch to enum class to separate scopes.
// OK: enum class separates scopes
enum class InvestigationStatus { CLEAR, SUSPECT };
enum class WeatherStatus { CLEAR, CLOUDY };
InvestigationStatus is = InvestigationStatus::CLEAR;
WeatherStatus ws = WeatherStatus::CLEAR; // No collision
g++ -std=c++11 enum_scope.cpp -o enum_scope ./enum_scope Investigation status: No suspicion Weather: Clear
Overview
Traditional enum is convenient because its enumerators are directly accessible in the surrounding scope, but it has drawbacks such as values from different enum types being mixed and implicit integer conversion. The enum class added in C++11 is a scoped enumeration type that requires the class name to access enumerators, preventing name collisions and detecting implicit integer conversions as compile errors. When an integer value is needed, use static_cast<int> for an explicit conversion. Specifying the underlying type with enum class name : type allows memory size optimization and binary compatibility. enum class is commonly used in newer code, but traditional enum remains an option when compatibility with existing code or simplicity is a priority. Combining with switch statements and variables / types enables safer and more readable constant management.
If you find any errors or copyright issues, please contact us.