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 타입의 값에 대해 정수를 직접 대입할 수 없다.
지금까지의 내용을 예제로 살펴보자.
- enum StateType
- {
- ST_NONE = 0,
- ST_IDLE,
- ST_MOVE,
- ST_ATTACK,
- ST_DEAD,
- ST_MAX,
- };
- enum MoveType
- {
- MT_NONE = 0,
- MT_WALK,
- MT_DASH,
- MT_JUMP,
- MT_CROUCH,
- MT_MAX,
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- -- enum 값을 정수형에 대입 --
- unsigned short a = ST_IDLE;
- -- enum의 크기는 int와 같다 --
- int b = sizeof(StateType);
- MoveType c = MT_WALK;
- -- 서로 다른 타입의 enum간 값 비교가 가능하다 --
- if (c == ST_IDLE)
- {
- }
- -- 다른 타입의 enum으로는 대입이 불가능하다 --
- MoveType d = ST_IDLE;
- -- 정수 값을 enum에 대입시킬 수 없다 --
- StateType e = 1;
- return 0;
- }
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를 이용하여 다시 작성해 보았다.
- enum class StateType : unsigned short
- {
- ST_NONE = 0,
- ST_IDLE,
- ST_MOVE,
- ST_ATTACK,
- ST_DEAD,
- ST_MAX,
- };
- enum class MoveType
- {
- MT_NONE = 0,
- MT_WALK,
- MT_DASH,
- MT_JUMP,
- MT_CROUCH,
- -- 열거자의 scope가 enum class {};안으로 국한되므로,
- StateType의 열거 이름과 같은 것을 사용해도 무방하다. --
- ST_DEAD,
- MT_MAX,
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- -- StateType의 열거이름은 StateType의 scope 안에서만 유효하다 --
- -- 따라서, 반드시 StateType에 대한 영역 지정을 해야 한다 --
- -- error C2065: 'ST_IDLE' : 선언되지 않은 식별자입니다. --
- StateType a = ST_IDLE;
- -- enum class 열거자를 정수형에 암시적으로 대입할 수 없다 --
- -- error C2440: '초기화 중' : 'StateType'에서 'unsigned char'(으)로 변환할 수 없습니다. --
- unsigned char b = StateType::ST_IDLE;
- -- StateType은 unsigned short로 타입 지정되었으므로, 그 크기는 2 바이트이다 --
- int c = sizeof(StateType);
- MoveType d= MoveType::MT_WALK;
- -- 서로 다른 타입의 열거자끼리는 비교가 불가능하다 --
- -- error C2676: 이항 '==' : 'MoveType'이(가) 이 연산자를 정의하지 않거나
- 미리 정의된 연산자에 허용되는 형식으로의 변환을 정의하지 않습니다. --
- if (d == StateType::ST_IDLE)
- {
- }
- -- 다른 타입의 enum으로는 대입이 불가능하다 --
- -- error C2440: '초기화 중' : 'StateType'에서 'MoveType'(으)로 변환할 수 없습니다. --
- MoveType e = StateType::ST_IDLE;
- -- 정수 값을 enum에 대입시킬 수 없다 --
- -- error C2440: '초기화 중' : 'int'에서 'StateType'(으)로 변환할 수 없습니다. --
- StateType f = 1;
- return 0;
- }
위 내용 중 "enum에 대해 자유롭게 타입을 부여할 수 있다"는 VS2010에서도 지원이 되긴 한다.
즉, 아래와 같이 작성을 할 수 있는 것인데...
- enum StateType : unsigned short
- {
- ST_NONE = 0,
- ST_IDLE,
- ST_MOVE,
- ST_ATTACK,
- ST_DEAD,
- ST_MAX,
- };
비표준 확장이라 경고 레벨을 4로 올리면, 다음과 같은 컴파일시 경고 메시지가 출력된다.
warning C4480: 비표준 확장이 사용되었습니다. 'StateType' 열거형에 대해 내부 형식을 지정합니다.
덧글
{
}
이런식으로 하지 않고
typedef enum
{
MT_0;
}MoveType;
이런식으로 정의할 경우 어떻게 수정해야 하나용??