title: “이번 주의 팁 #86: 클래스(enum class)를 활용한 열거형” layout: tips sidenav: side-nav-tips.html published: true permalink: tips/86 type: markdown order: “086”

원래 totw/86로 2015-01-05에 게시됨

작성자: Bradley White (bww@google.com)

“품격을 보여주고, … 그리고 캐릭터를 드러내라.” - Bear Bryant

열거형(enumeration) 또는 줄여서 enum은 특정 정수 집합 중 하나의 값을 가질 수 있는 타입입니다. 이 집합의 일부 값에 이름을 부여할 수 있으며, 이를 **열거자(enumerator)**라고 부릅니다.

비스코프 열거형 (Unscoped Enumerations)

이 개념은 C++ 프로그래머에게 익숙할 것입니다. 그러나 C++11 이전의 열거형에는 두 가지 큰 단점이 있었습니다:

  1. 열거자 이름이 열거형 타입과 동일한 스코프에 존재했습니다.
  2. 열거자는 암묵적으로 정수형 타입으로 변환되었습니다.

C++98에서의 예시:

C++
enum CursorDirection { kLeft, kRight, kUp, kDown };
CursorDirection d = kLeft; // 가능: 열거자가 같은 스코프에 있음
int i = kRight;            // 가능: 열거자가 정수형으로 변환됨
클릭하여 더 보기

그러나 다음과 같은 경우에는 문제가 발생합니다:

C++
// 오류: kLeft와 kRight가 중복 선언됨
enum PoliticalOrientation { kLeft, kCenter, kRight };
클릭하여 더 보기

C++11에서의 변경 사항

C++11에서는 비스코프 열거형의 동작을 약간 변경했습니다. 열거자는 이제 열거형 내부에 로컬로 존재하지만, 이전 버전과의 호환성을 위해 여전히 해당 열거형의 스코프로 내보내집니다.

C++
CursorDirection d = CursorDirection::kLeft;  // C++11에서 가능
int i = CursorDirection::kRight;             // 가능: 여전히 정수형으로 변환됨
클릭하여 더 보기

하지만 PoliticalOrientation의 선언은 여전히 오류를 발생시킵니다.

스코프 열거형 (Scoped Enumerations)

암묵적인 정수형 변환은 흔히 발생하는 버그의 원인이 되며, 열거자가 같은 스코프에 존재함으로 인해 네임스페이스 오염이 발생해 대규모 프로젝트에서는 문제가 될 수 있습니다. 이러한 문제를 해결하기 위해, C++11은 새로운 개념인 **스코프 열거형(scoped enum)**을 도입했습니다.

스코프 열거형에서는 enum class 키워드를 사용하며, 이 경우 열거자는:

  1. 해당 열거형에만 로컬로 존재하며 (열거형의 스코프로 내보내지 않음),
  2. 정수형 타입으로 암묵적으로 변환되지 않습니다.

예시 (추가된 class 키워드 주목):

C++
enum class CursorDirection { kLeft, kRight, kUp, kDown };
CursorDirection d = kLeft;                    // 오류: kLeft가 이 스코프에 없음
CursorDirection d2 = CursorDirection::kLeft;  // 가능
int i = CursorDirection::kRight;              // 오류: 변환 불가
클릭하여 더 보기

그리고 다음과 같이:

C++
// 가능: kLeft와 kRight는 각각의 스코프 열거형에 로컬로 존재함
enum class PoliticalOrientation { kLeft, kCenter, kRight };
클릭하여 더 보기

이러한 간단한 변경으로 기존의 열거형 문제를 해결할 수 있으며, 새로운 코드에서는 enum class를 사용하는 것이 권장됩니다.

스코프 열거형을 사용하면 여전히 정수형 타입으로 변환이 필요할 때는 명시적으로 캐스팅해야 합니다 (예: 열거형 값을 로그에 출력하거나 플래그와 같은 열거자에 비트 연산을 사용하는 경우). 그러나 std::hash를 사용하는 해싱 작업(std::unordered_map<CursorDirection, int> 등)에는 여전히 문제가 없습니다.

열거형의 기본 타입 지정

C++11은 또한 두 종류의 열거형 모두에 대해 기본 타입을 지정할 수 있는 기능을 추가했습니다. 이전에는 열거형의 기본 정수형 타입이 열거자들의 부호와 크기를 보고 결정되었으나, 이제는 명시적으로 지정할 수 있습니다.

예시:

C++
// CursorDirection의 기본 타입을 "int"로 사용
enum class CursorDirection : int { kLeft, kRight, kUp, kDown };
클릭하여 더 보기

열거자 범위가 작고, CursorDirection 값을 저장할 때 메모리를 절약하고 싶다면 char로 지정할 수도 있습니다.

C++
// CursorDirection의 기본 타입을 "char"로 사용
enum class CursorDirection : char { kLeft, kRight, kUp, kDown };
클릭하여 더 보기

컴파일러는 열거자 값이 기본 타입의 범위를 초과하면 오류를 발생시킵니다.

결론

새로운 코드에서는 enum class를 사용하는 것이 좋습니다. 이렇게 하면 네임스페이스 오염을 줄일 수 있고, 암묵적인 변환에서 발생할 수 있는 버그를 피할 수 있습니다.

C++
enum class Parting { kSoLong, kFarewell, kAufWiedersehen, kAdieu };
클릭하여 더 보기

reference

https://github.com/abseil/abseil.github.io/blob/master/_posts/2017-10-26-totw-86.md

라이선스

저작자: Jaehun Ryu

링크: https://jaehun.me/posts/abseil-tip-86-%ED%81%B4%EB%9E%98%EC%8A%A4enum-class%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%97%B4%EA%B1%B0%ED%98%95/

라이선스: CC BY 4.0

이 저작물은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다. 출처를 밝히면 상업적 목적을 포함해 자유롭게 이용 가능합니다.

댓글

검색 시작

검색어를 입력하세요

↑↓
ESC
⌘K 단축키