[C++] enum class : 범위 있는 열거형

[C++] enum class : 범위 있는 열거형

개요

안녕하세요. 이번 글에서는 C++11에서 추가된 enum class(범위 있는 열거형, scoped enum)에 대해 알아보겠습니다. 기존 enum은 편리하지만 이름 충돌과 의도치 않은 정수 변환이라는 약점이 있습니다. enum class는 이 두 문제를 해결합니다.

기존 enum의 문제

먼저 전통적인 enum을 보겠습니다. 두 가지 불편한 점이 있습니다.

enum Color { Red, Green, Blue };
enum Fruit { Apple, Red };   // 에러! Red가 이미 있음 (이름 충돌)

enum Color { Red, Green, Blue };
int x = Red;        // 문제 1: enum 값이 그냥 int로 들어감 (0)
if (Red == 0) { }   // 문제 2: 정수와 바로 비교돼 버림
  • 이름 충돌: enum 안의 이름이 바깥 범위로 그대로 노출돼, 다른 enum과 같은 이름을 못 씀.
  • 암묵적 정수 변환: 열거형 값이 아무 제약 없이 int로 변환돼, 실수로 숫자와 섞여도 컴파일됨.

enum class — 범위 있는 열거형

enum 뒤에 class를 붙이면 됩니다. 이름이 열거형 안으로 갇히기 때문에, 사용할 때 열거형이름::값 형태로 적어야 합니다.

enum class Color { Red, Green, Blue };
enum class Fruit { Apple, Red };   // OK! 서로 범위가 달라 충돌 없음

Color c = Color::Red;      // 반드시 Color:: 를 붙임
// Color c = Red;          // 에러: Red만으로는 못 찾음

// int x = c;              // 에러: 암묵적 정수 변환 금지
int x = static_cast<int>(c);  // 변환하려면 명시적으로

이렇게 하면 이름 충돌이 사라지고, 정수로 바꾸려면 반드시 static_cast를 쓰도록 강제되어 실수가 줄어듭니다.

기존 enum vs enum class

구분enum (기존)enum class
이름 범위바깥으로 노출열거형 안으로 한정 (이름::값)
정수 변환암묵적으로 변환됨금지 (static_cast 필요)
이름 충돌잘 발생범위가 달라 안전
권장레거시 코드새 코드는 enum class 권장

기본 타입 지정

열거형이 내부적으로 사용할 정수 타입을 지정할 수 있습니다. 값의 범위가 작으면 메모리를 아끼거나, 통신 프로토콜에서 크기를 맞출 때 유용합니다.

// 각 값을 1바이트(unsigned char)로 저장
enum class Direction : unsigned char
{
    North = 0,
    East  = 1,
    South = 2,
    West  = 3
};

Direction d = Direction::East;

: 타입을 생략하면 기본은 int입니다. enum class뿐 아니라 기존 enum에도 이 문법을 쓸 수 있습니다.

switch와 함께 쓰기

열거형은 switch문과 자주 함께 쓰입니다. enum class도 동일하게 쓰되, case에도 열거형이름::값을 적습니다.

Color c = Color::Green;

switch (c)
{
case Color::Red:   std::cout << "빨강"; break;
case Color::Green: std::cout << "초록"; break;
case Color::Blue:  std::cout << "파랑"; break;
}

정리

  • 기존 enum은 이름 충돌과 암묵적 정수 변환이라는 약점이 있다.
  • enum class는 이름을 범위 안에 가두고(이름::값), 정수 변환을 막아 더 안전하다.
  • 정수로 바꾸려면 static_cast를 명시적으로 쓴다.
  • : 타입으로 내부 저장 타입을 지정할 수 있다.
  • 특별한 이유가 없으면 새 코드에서는 enum class를 쓰는 것이 권장된다.

enum class는 약간 더 길게 적어야 하지만, 이름 충돌과 타입 실수를 컴파일 단계에서 막아 줍니다. 이상으로 enum class에 대해 간단히 알아보았습니다.

참고