숏컷 코드
cpp
enum class Color { red, green, blue };
enum class State { idle, running, stopped };
Color c = Color::green;
State s = State::running;
// c == s; // ❌ 컴파일 오류 — 다른 타입 비교 불가
if (s == State::running) std::cout << "running\n";문법
구식 enum의 문제 — 이름 누출과 암시적 변환
구식 enum은 열거자 이름이 바깥 스코프로 퍼져 충돌을 만들고, 정수와 암시적으로 비교되어 버그를 감춥니다.
cpp
enum Direction { up, down, left, right }; // 구식 enum
enum Status { ok, error, left }; // ❌ 컴파일 오류 — left 중복
// 구식 enum은 정수로 암시적 변환
Direction d = up;
int i = d; // ✅ 암시적으로 정수 0
if (d == 0) { ... } // ✅ 컴파일되지만 의미상 이상한 비교
// ✅ enum class — 이름 스코프 분리, 암시적 변환 없음
enum class Dir { up, down, left, right };
int j = Dir::up; // ❌ 컴파일 오류 — 암시적 변환 없음
if (Dir::up == 0) { ... } // ❌ 컴파일 오류기저 타입 지정 — 크기와 전방 선언
기저 타입을 지정하면 메모리 크기를 제어하고 전방 선언이 가능합니다.
cpp
// 기저 타입 지정 (기본은 int)
enum class Opcode : uint8_t { nop = 0, add = 1, sub = 2 };
// sizeof(Opcode) == 1
// 전방 선언 — 기저 타입 있어야 가능
enum class Priority : int; // 헤더에서 전방 선언
// 나중에 다른 파일에서 정의 가능
// 명시적 정수 변환
Opcode op = Opcode::add;
uint8_t raw = static_cast<uint8_t>(op); // 1플래그 enum — 비트 연산 패턴
여러 옵션을 비트 플래그로 조합할 때 enum class에 |, &, ~를 오버로딩합니다.
cpp
enum class Permission : uint8_t {
none = 0,
read = 1 << 0, // 0b001
write = 1 << 1, // 0b010
execute = 1 << 2, // 0b100
};
// 비트 연산자 오버로딩
Permission operator|(Permission a, Permission b) {
return static_cast<Permission>(
static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
}
Permission operator&(Permission a, Permission b) {
return static_cast<Permission>(
static_cast<uint8_t>(a) & static_cast<uint8_t>(b));
}
bool hasFlag(Permission set, Permission flag) {
return (set & flag) != Permission::none;
}
// 사용
Permission perm = Permission::read | Permission::write; // 0b011
bool canRead = hasFlag(perm, Permission::read); // true
bool canExec = hasFlag(perm, Permission::execute); // falseswitch와 enum class — 완전성 경고 활용
컴파일러는 switch에서 enum class 열거자가 빠지면 경고를 줍니다. 이를 이용해 새 열거자 추가 시 처리 누락을 방지합니다.
cpp
enum class Direction { north, south, east, west };
void move(Direction d) {
switch (d) {
case Direction::north: goNorth(); break;
case Direction::south: goSouth(); break;
case Direction::east: goEast(); break;
// ⚠️ west 처리 없음 — 컴파일러 경고
// 새 열거자 추가 시 처리 누락을 컴파일러가 알려줌
}
}체크포인트
| 상황 | 적합한 선택 |
|---|---|
| 이름 충돌 방지 + 타입 안전성 | enum class |
| 정수 값 직접 필요 | static_cast<int>(val) |
| 크기 줄이기 (네트워크, 파일) | enum class Foo : uint8_t |
| 전방 선언 | 기저 타입 지정 후 전방 선언 |
| 새 열거자 추가 시 처리 누락 감지 | switch + 컴파일러 경고 (-Wall) |
| 여러 옵션 조합 (비트 플래그) | 2의 거듭제곱 값 + |/& 오버로딩 |
주의할 점
enum class는 자동으로 문자열로 변환되지 않습니다. 로그나 출력이 필요하면 변환 함수를 따로 만들어야 합니다.
cpp
enum class Status { ok, error, timeout };
// ❌ 직접 출력 불가
Status s = Status::error;
std::cout << s; // 컴파일 오류
// ✅ 변환 함수 작성
std::string_view toString(Status s) {
switch (s) {
case Status::ok: return "ok";
case Status::error: return "error";
case Status::timeout: return "timeout";
}
return "unknown";
}
std::cout << toString(s); // "error"
// ⚠️ 구식 enum은 +1, -1 같은 정수 연산이 가능해 의도치 않은 버그 발생
enum OldColor { red, green, blue };
OldColor c = static_cast<OldColor>(red + 1); // green — 암묵적 허용참고 링크
1 sources