4 분 소요

개요

기존에는 열거형의 이름이 한정되지 않아 이름 충돌의 우려가 있어 클래스 내에 정의하는 방식을 사용했었는데요(열거형 참고),

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 기존
enum Week {
    Sunday, Monday, Tuesday, Wednesday, 
    Thursday, Friday, Saturday
};
Week week{Sunday}; // (△) 비권장. 이름 충돌이 쉬움

// 혹은
class Week {
public:
    // 클래스내에 정의. 사용시 클래스명을 기재해야 함
    enum Val {
        Sunday, Monday, Tuesday, Wednesday, 
        Thursday, Friday, Saturday
    };
};

Week::Val val{Week::Sunday}; // 범위 확인 연산자와 클래스명 사용

C++11 부터는 범위 있는 열거형을 지원하여 이름 충돌 회피가 훨씬 쉬워졌습니다.

1
2
3
4
5
6
// 범위 있는 열거형
enum class Week_11 {
    Sunday, Monday, Tuesday, Wednesday, 
    Thursday, Friday, Saturday
};
Week_11 week{Week_11::Sunday}; // 열거형 이름을 같이 사용하여 이름 충돌 회피

열거형의 암시적 형변환

기존 열거형은 암시적으로 형변환이 되지만, 범위 있는 열거형은 형변환되지 않습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum Week {
    Sunday, Monday, Tuesday, Wednesday, 
    Thursday, Friday, Saturday
};
Week week = Sunday;
int val = week; // int형으로 형변환 됩니다.

enum class Week_11 {
    Sunday, Monday, Tuesday, Wednesday, 
    Thursday, Friday, Saturday    
};

Week_11 week_11 = Week_11::Sunday;
// int val_11 = week_11; // (X) 컴파일 오류. 형변환되지 않습니다.

전방 선언

범위 있는 열거형전방 선언을 지원합니다. 지난날 열거형이 정의된 헤더 파일이 수정될 때마다 엄청나게 많은 파일들이 쓸데없이 재빌드 되던 걸 생각하면, 참 사소하지만 감사한 기능입니다.

1
2
enum MyEnum; // (X) 컴파일 오류.
enum class MyEnum_11; // (O)

기반 타입

기존에는 열거형의 크기를 지정하기 위하여 열거자에 강제적으로 더미(Dummy) 값을 입력했는데요(열거형의 크기 참고),

C++11 부터는 열거형의 기반 타입을 지정할 수 있습니다. 기본적으로는 int를 사용하며, 다음과 같이 명시적으로 변경할 수 있습니다.

1
2
enum MyEnum1_11 : int {a, b, c}; // int 형을 기반 타입으로 사용합니다.
enum class MyEnum2_11 : char {i, j, k}; // char 형을 기반 타입으로 사용합니다.

열거형 초기화와 암시적 형변환 차단

열거자에 열거형의 기반 타입만 지정하고 열거자를 생략할 수 있습니다.

1
    enum MyInt_11 : int {}; // 열거자가 빠졌습니다!!

보통 나열된 열거자를 사용하기 위해 열거형을 정의하는데, 이를 생략하다니 좀 의아한데요, 재밌게도 다음과 같이 값을 대입할 수 있습니다. 반드시 같은 타입의 열거형만 대입할 수 있습니다. 단, 중괄호 직접 초기화는 지원하지 않습니다.

(C++17~) 열거형의 중괄호 직접 초기화를 허용하여 암시적 형변환을 차단하는 사용자 정의 열거형의 사용이 좀더 쉬워졌습니다.

1
2
3
4
5
6
7
8
9
10
11
enum MyInt_11 : int {};

// 특정 값을 대입합니다. 반드시 MyInt 타입만 대입받을 수 있습니다.
MyInt_11 val1{MyInt_11(10)};
MyInt_11 val2 = MyInt_11(10); // MyInt_11 val1{MyInt_11(10)}; 와 동일
MyInt_11 val3{val1}; 

// MyInt_11 val4 = 10; // (X) 컴파일 오류. 정수는 대입 받을 수 없습니다.
// MyInt_11 val5(10); // (X) 컴파일 오류. 정수는 대입 받을 수 없습니다.
// MyInt_11 val6{10}; // (X) 컴파일 오류. 중괄호 직접 초기화는 지원하지 않습니다.
// MyInt_11 val7 = {10}; // (X) 컴파일 오류. 암시적으로 중괄호 직접 초기화를 사용하므로 지원하지 않습니다.

이 기능을 이용하면, 암시적 형변환을 차단하는 정수 타입을 만들 수 있습니다. 다음 예에서 Func()은 암시적으로 int로 변환될 수 있는 모든 타입이 전달될 수 있지만, Func_11()은 오로지 MyInt_11만 전달 받을 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
enum MyInt_11 : int {};
void Func(int val) {}
void Func_11(MyInt_11 val) {}    

Func(10);
Func('c'); // (△) 비권장. 암시적 형변환 됩니다.

// Func_11(10); // (X) 컴파일 오류. 암시적 형변환을 차단합니다.
// Func_11('c'); // (X) 컴파일 오류. 암시적 형변환을 차단합니다.
Func_11(MyInt_11(10)); // MyInt_11 타입만 가능합니다.    

(C++17~) 열거형의 중괄호 직접 초기화 허용

C++17 부터는 열거형의 중괄호 직접 초기화를 허용하여 암시적 형변환을 차단하는 사용자 정의 열거형의 사용이 좀더 쉬워졌습니다.

1
2
3
4
5
6
7
8
9
10
enum MyInt_11 : int {};

MyInt_11 val1{MyInt_11(10)};
MyInt_11 val2 = MyInt_11(10); // MyInt_11 val1{MyInt_11(10)}; 와 동일
MyInt_11 val3{val1}; 

// MyInt_11 val4 = 10; // (X) 컴파일 오류. 정수는 대입 받을 수 없습니다.
// MyInt_11 val5(10); // (X) 컴파일 오류. 정수는 대입 받을 수 없습니다.
MyInt_11 val6_17{10}; // (O) C++17~ 중괄호 직접 초기화를 지원합니다.
// MyInt_11 val7_17 = {10}; // (X) 컴파일 오류. 중괄호 직접 초기화는 허용하지만, {10}은 int로 추론되어 사용할 수 없습니다.

(C++20~) using enum

범위 있는 열거형 덕에 이름 충돌은 회피되어 좋지만, 매번 열거형의 이름을 함께 명시하다 보니 코드가 지저분해질 수 있는데요,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enum class Week_11 {
    Sunday, Monday, Tuesday, Wednesday, 
    Thursday, Friday, Saturday
};
Week_11 week{Week_11::Sunday}; 

bool isFreeDay{false};
switch(week) {
case Week_11::Sunday: isFreeDay = true; break;
case Week_11::Monday: break;
case Week_11::Tuesday: break;
case Week_11::Wednesday: break;
case Week_11::Thursday: break;
case Week_11::Friday: break;
case Week_11::Saturday: break;
}

C++20 부터는 using enum이 추가되어 범위 있는 열거형의 이름 없이 열거자를 유효 범위내에서 사용할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum class Week_11 {
    Sunday, Monday, Tuesday, Wednesday, 
    Thursday, Friday, Saturday
};
Week_11 week{Week_11::Sunday}; 
bool isFreeDay{false};
switch(week) {

using enum Week_11; // (C++20~) 유효 범위 내에서 Week_11의 열거자를 사용할 수 있습니다.
case Sunday: isFreeDay = true; break;
case Monday: break;
case Tuesday: break;
case Wednesday: break;
case Thursday: break;
case Friday: break;
case Saturday: break;
}

태그:

카테고리:

업데이트:

댓글남기기