광고


[C++11] Scoped / Strongly typed enumeration TR1 / C++11 / C++14




1. C++03의 enum

1. Type-safety

C++03에서 enum은 type-safe하지 않았다.

enum은 암시적으로 int 이하의 정수 타입에 대입 가능했으며(암시적 형 변환), (즉 int a = Enum::AAA)
값만 동일하다면, 다른 enum 타입과도 값 비교가 가능했었다.

C++03에서 유일하게 보장한 type-safety는 아래와 같다.
  • A type의 enum을 B 타입의(즉, 다른 타입의) enum 타입으로 암시적 형 변환을 할 수 없다.
  • enum 타입의 값에 대해 정수를 직접 대입할 수 없다.
지금까지의 내용을 예제로 살펴보자.

  1. enum StateType
  2. {
  3.     ST_NONE = 0,
  4.  
  5.     ST_IDLE,
  6.     ST_MOVE,
  7.     ST_ATTACK,
  8.     ST_DEAD,
  9.  
  10.     ST_MAX,
  11. };
  12.  
  13. enum MoveType
  14. {
  15.     MT_NONE = 0,
  16.  
  17.     MT_WALK,
  18.     MT_DASH,
  19.     MT_JUMP,
  20.     MT_CROUCH,
  21.  
  22.     MT_MAX,
  23. };
  24.  
  25. int _tmain(int argc, _TCHAR* argv[])
  26. {
  27.     -- enum 값을 정수형에 대입 --
  28.     unsigned short a = ST_IDLE;
  29.  
  30.     -- enum의 크기는 int와 같다 --
  31.     int b = sizeof(StateType);
  32.  
  33.     MoveType c = MT_WALK;
  34.     -- 서로 다른 타입의 enum간 값 비교가 가능하다 --                   
  35.     if (== ST_IDLE)
  36.     {
  37.     }
  38.  
  39.     -- 다른 타입의 enum으로는 대입이 불가능하다 --
  40.     MoveType d = ST_IDLE;    
  41.  
  42.     -- 정수 값을 enum에 대입시킬 수 없다 --
  43.     StateType e = 1;
  44.  
  45.     return 0;
  46. }

2. Scope

C++03까지의 enum scope는 enum {};의 scope에 국한되지 않았다.

따라서, 위 예제처럼 ST_IDLE을 StateType의 영역지정 없이 사용이 가능했던 것이고,
당연하게도 두 개의 enum이 같은 열거 이름을 가질 수 없었다.

다음 상황의 예를 살펴보자.
  • Main.cpp에 두 개의 헤더 A.h와 B.h를 포함하고 있다.
  • A.h에 CarType이라는 enum이 있고, CarType의 열거자 중 CT_NORMAL이 포함되어 있다.
  • B.h에 CurveType이라는 enum이 있고, 역시 열거자 중 CT_NORMAL이 포함되어 있다.
이 경우 컴파일을 하게 되면, 아래와 같은 컴파일 에러가 발생한다.

error C2365: 'CT_NORMAL' : 재정의: 이전 정의는 '열거자'입니다.


2. C++11의 enum

C++11은 당연하게도 이전의 C++이 가지고 있던 불안정한 모습을 모두 개선시켰다.
  • enum에 대해 자유롭게 타입을 부여할 수 있다.
  • type에 대해 strong-safety를 제공할 수 있다.
  • enum 열거자의 scope 역시 enum 정의의 scope 안으로 한정지을 수 있다.
이를 위해 전통의 enum 키워드 대신 enum class를 사용할 수 있다.

C++03의 enum과 C++11의 enum class를 비교하기 위해, 앞서 사용했던 예제를 enum class를 이용하여 다시 작성해 보았다.

  1. enum class StateType : unsigned short
  2. {
  3.     ST_NONE = 0,
  4.  
  5.     ST_IDLE,
  6.     ST_MOVE,
  7.     ST_ATTACK,
  8.     ST_DEAD,   
  9.  
  10.     ST_MAX,
  11. };
  12.  
  13. enum class MoveType
  14. {
  15.     MT_NONE = 0,
  16.  
  17.     MT_WALK,
  18.     MT_DASH,
  19.     MT_JUMP,
  20.     MT_CROUCH,
  21.  
  22.     -- 열거자의 scope가 enum class {};안으로 국한되므로,
  23.         StateType의 열거 이름과 같은 것을 사용해도 무방하다. --
  24.     ST_DEAD,
  25.  
  26.     MT_MAX,
  27. };
  28.  
  29. int _tmain(int argc, _TCHAR* argv[])
  30. {
  31.     -- StateType의 열거이름은 StateType의 scope 안에서만 유효하다 --
  32.     -- 따라서, 반드시 StateType에 대한 영역 지정을 해야 한다 --
  33.     -- error C2065: 'ST_IDLE' : 선언되지 않은 식별자입니다. --
  34.     StateType a = ST_IDLE;
  35.  
  36.     -- enum class 열거자를 정수형에 암시적으로 대입할 수 없다 --
  37.     -- error C2440: '초기화 중' : 'StateType'에서 'unsigned char'(으)로 변환할 수 없습니다. --
  38.     unsigned char b = StateType::ST_IDLE;
  39.  
  40.     -- StateType은 unsigned short로 타입 지정되었으므로, 그 크기는 2 바이트이다 --
  41.     int c = sizeof(StateType);
  42.  
  43.     MoveType d= MoveType::MT_WALK;
  44.  
  45.     -- 서로 다른 타입의 열거자끼리는 비교가 불가능하다 --         
  46.     -- error C2676: 이항 '==' : 'MoveType'이(가) 이 연산자를 정의하지 않거나
  47.                                 미리 정의된 연산자에 허용되는 형식으로의 변환을 정의하지 않습니다. --
  48.     if (== StateType::ST_IDLE)
  49.     {
  50.     }
  51.  
  52.     -- 다른 타입의 enum으로는 대입이 불가능하다 --
  53.     -- error C2440: '초기화 중' : 'StateType'에서 'MoveType'(으)로 변환할 수 없습니다. --
  54.     MoveType e = StateType::ST_IDLE;    
  55.  
  56.     -- 정수 값을 enum에 대입시킬 수 없다 --
  57.     -- error C2440: '초기화 중' : 'int'에서 'StateType'(으)로 변환할 수 없습니다. --
  58.     StateType f = 1;
  59.  
  60.     return 0;
  61. }

위 내용 중 "enum에 대해 자유롭게 타입을 부여할 수 있다"는 VS2010에서도 지원이 되긴 한다.

즉, 아래와 같이 작성을 할 수 있는 것인데...

  1. enum StateType : unsigned short
  2. {
  3.     ST_NONE = 0,
  4.  
  5.     ST_IDLE,
  6.     ST_MOVE,
  7.     ST_ATTACK,
  8.     ST_DEAD,
  9.  
  10.     ST_MAX,
  11. };

비표준 확장이라 경고 레벨을 4로 올리면, 다음과 같은 컴파일시 경고 메시지가 출력된다.

warning C4480: 비표준 확장이 사용되었습니다. 'StateType' 열거형에 대해 내부 형식을 지정합니다.


핑백

덧글

댓글 입력 영역