C++

C++11 enum class

남자6호 2020. 4. 12. 17:57

언리얼 코딩표준을 보다가 enum class를 알게 되었다.

무엇이 다른걸까?

 

C++11 부터 추가되었다고 들은 enum class

enum class eUserType : unsigned char 
{ 
    NONE = 0,       //  비엇음  
    FIRST,          //  첫번째 엘리먼트  
    SECOND, 
    MAX 
};

기존의 enum과 조금 다르다.

1. 자료의 기본형(사이즈)가 추가되었다. (마치 클래스 상속처럼 선언)

2. enum 사용시 class 이름을 namespace처럼 넣어주어야 한다. 

3. namespace에 넣은것처럼 enum의 정의한 내용이 다른 enum과 중복되어도 상관없다.

4. 암시적 변환 ( to int )이 이루어지지 않는다. 일일이 static cast를 해주어야한다... (이건좀 귀찮네)

5. 클래스처럼 선언과 구현이 분리가 가능하다.

 

 

그래도 컴파일러가 맘대로 바꾸는것보단 암시적 변환을 허용하지 않는게 오류를 줄이는데는 좋기는 하다.

다만..

int arrFoo[ (int) eUserType::MAX ] = { 0, };
for (int i = 0; i < (int) eUserType::MAX; ++i) // 형변환 없이 그냥 DEFINE 처럼 쓰고싶다!!
{
    arrFoo[i] = i;
    _tprintf(_T("%u \n"), arrFoo[i]);
}


이런식으로 타입캐스트를 (귀찮지만) 써야한다.

그리고 산술연산자 +,-,* 등등... 여러곳에서도 일일이 캐스팅을 다 붙여줘야한다.

사실 이러려고 enum을 쓰는건 아니었던거 같은데...

솔직히 enum을 쓰는 이유는 개인적으로 #define 으로 선언하기 싫어서 인게 가장크다.

그런데 쓸때마다 (int) 타입캐스트 형변환을 해주면, 코드가 지저분해 보여서 맘에 안든다. -_-

 

 

 

enum class의 장점과 기존 enum의 암시적 캐스팅을 사용하기 위한 꼼수들...

 

C스타일

typedef enum eUserState : unsigned char
{ 
    NONE = 0,       //  비엇음 
    FIRST,          //  첫번째 엘리먼트 
    SECOND, 
    MAX 
}eUserState;

c스타일로도 써봤지만, 다른 enum과 재정의 충돌이나서 마음에 들지 않는다.

 

 

C++ namespace 스타일

namespace eUserType 
{ 
    enum type: unsigned char 
    { 
        NONE = 0,       //  비엇음 
        FIRST,          //  첫번째 엘리먼트 
        SECOND, 
        MAX 
    };
};

enum 선언할때마다 namespace를 타이핑하는게 귀찮을것같다... 또 한눈에 잘 안들어오는느낌

enum 타입 자료형을 선언할때, eUserType::type으로 선언하는것도 조금 마음에 안듬.

 

 

이거저거 해보다가  결국 namespace 기반으로 매크로를 만들어서 사용하고 있다.

이또한 C++11에서 기존 enum의 선언과 구현의 분리와 기본형 설정이 가능해서 쓰는것이기도 하다.

//  매크로 사용

#define DEF_ENUM(ENUM_NAME, TYPE)        \ 
namespace ENUM_NAME { enum type:TYPE; }; \
enum ENUM_NAME::type : TYPE

DEF_ENUM(eUserType, unsigned char) 
{ 
    NONE = 0,     // 비엇음
    FIRST,        // 첫번째 엘리먼트
    SECOND, 
    MAX 
};
// 사실상 컴파일하면 이렇게 바뀌게 된다.

namespace eUserType 
{ 
    enum type : unsigned char; 
};

enum eUserType::type : unsigned char 
{ 
    NONE = 0,      // 비엇음
    FIRST,         // 첫번째 엘리먼트
    SECOND, 
    MAX 
};

음... 나쁘진 않은데, 조금 아쉬운점이 몇가지 있다.

첫째 역시나 namespace 기반이라 eUserType::type으로 선언해야하는것과

둘째 eUserType::FIRST 쓸때 [첫번째 엘리먼트]라는 툴팁주석이 보이질 않는다는것이다. (매크로의한계)

세번째 위의 주석이 안보이듯, Doxygen에서 namespace와 enum을 인식하지 못하는것이다. (아아... 매크로의한계)

네번째 에디터에서도 enum으로 인식하지 않고,

마치 배열의 앨리먼트 선언하는것처럼 보여서인지 두번째 부터는 들여쓰기가된다....

 

 

그래도 define의 대신으로 쓰기에는 이게 그나마 최선이라고 본다.

코드에서 사용할때도 암시적 캐스팅이 되고, (내가 바라는)

주석이야 툴팁으로 나오지 않아도 크게 불편하지는 않으니...