열거 형 유형에 대한 네임 스페이스-모범 사례 이름 충돌이

종종 여러 개의 열거 형이 함께 필요합니다. 때로는 이름 충돌이 있습니다. 이에 대한 두 가지 해결책이 떠 오릅니다. 네임 스페이스를 사용하거나 ‘더 큰’열거 형 요소 이름을 사용하는 것입니다. 그럼에도 불구하고 네임 스페이스 솔루션에는 두 가지 구현이 가능합니다. 하나는 중첩 된 열거 형이있는 더미 클래스 또는 완전한 네임 스페이스입니다.

세 가지 접근 방식의 장단점을 찾고 있습니다.

예:

// oft seen hand-crafted name clash solution
enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd };
enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd };
void setPenColor( const eColors c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cColorBlue: //...
        //...
    }
 }


// (ab)using a class as a namespace
class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
    switch (c) {
        default: assert(false);
        break; case Colors::cRed: //...
        break; case Colors::cBlue: //...
        //...
    }
 }


 // a real namespace?
 namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
 namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
 void setPenColor( const Colors::e c ) {
    switch (c) {
        default: assert(false);
        break; case Colors::cRed: //...
        break; case Colors::cBlue: //...
        //...
    }
  }



답변

원래 C ++ 03 답변 :

(이상 ) 의 이점 은 원할 때 선언 을 사용할 수 있다는 것 입니다.namespaceclassusing

를 사용할 때 의 문제namespace 는 네임 스페이스가 코드의 다른 곳에서 확장 될 수 있다는 것입니다. 대규모 프로젝트에서는 두 개의 별개 열거 형이 둘 다 호출되었다고 생각하지 않는다고 보장 할 수 없습니다.eFeelings

더 간단한 코드의 struct경우 내용이 공개되기를 원하므로를 사용합니다.

이러한 관행 중 하나를 수행하는 경우 곡선보다 앞서 있으므로 더 자세히 조사 할 필요가 없습니다.

최신 C ++ 11 조언 :

C ++ 11 이상을 사용하는 경우 enum class는 열거 형 이름 내에서 열거 형 값의 범위를 암시 적으로 지정합니다.

이를 통해 enum class암시 적 변환 및 정수 유형 비교를 잃게되지만 실제로는 모호하거나 버그가있는 코드를 발견하는 데 도움이 될 수 있습니다.


답변

참고로 C ++ 0x에는 언급 한 것과 같은 경우에 대한 새로운 구문이 있습니다 ( C ++ 0x 위키 페이지 참조 ).

enum class eColors { ... };
enum class eFeelings { ... };


답변

나는 다음과 같은 것에 대해 앞의 답변을 혼성화했습니다. (편집 : 이것은 C ++ 11 이전에만 유용합니다. C ++ 11을 사용하는 경우 enum class)

이 열거 형은 작업자 클래스간에 공유되고 작업자 클래스 자체에 열거 형을 넣는 것은 의미가 없기 때문에 모든 프로젝트 열거 형을 포함하는 하나의 큰 헤더 파일이 있습니다.

struct문법적하고는 : 대중을 방지 typedef실제로 다른 작업자 클래스 내에서이 열거 형의 변수를 선언 할 수 있습니다.

네임 스페이스를 사용하는 것이 전혀 도움이되지 않는다고 생각합니다. 제가 C # 프로그래머이기 때문일 수 있으며 값을 참조 할 때 열거 형 이름을 사용해야하므로 익숙합니다.

    struct KeySource {
        typedef enum { 
            None, 
            Efuse, 
            Bbram
        } Type;
    };

    struct Checksum {
        typedef enum {
            None =0,
            MD5 = 1,
            SHA1 = 2,
            SHA2 = 3
        } Type;
    };

    struct Encryption {
        typedef enum {
            Undetermined,
            None,
            AES
        } Type;
    };

    struct File {
        typedef enum {
            Unknown = 0,
            MCS,
            MEM,
            BIN,
            HEX
        } Type;
    };

class Worker {
    File::Type fileType;
    void DoIt() {
       switch(fileType) {
       case File::MCS: ... ;
       case File::MEM: ... ;
       case File::HEX: ... ;
    }
}


답변

나는 이것을 위해 클래스를 사용하지 않을 것이다. 대신 네임 스페이스를 사용하십시오. 질문은 네임 스페이스를 사용할 것인지 아니면 열거 형 값에 고유 한 ID를 사용할 것인지로 귀결됩니다. 개인적으로 저는 네임 스페이스를 사용하여 내 ID가 더 짧고 자명 할 수 있기를 바랍니다. 그런 다음 애플리케이션 코드는 ‘using namespace’지시문을 사용하여 모든 것을 더 읽기 쉽게 만들 수 있습니다.

위의 예에서 :

using namespace Colors;

void setPenColor( const e c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cBlue: //...
        //...
    }
}


답변

클래스 또는 네임 스페이스 사용의 차이점은 네임 스페이스처럼 클래스를 다시 열 수 없다는 것입니다. 이렇게하면 나중에 네임 스페이스가 남용 될 가능성을 피할 수 있지만 열거 형 집합에도 추가 할 수없는 문제도 있습니다.

클래스 사용의 가능한 이점은 네임 스페이스의 경우가 아닌 템플릿 유형 인수로 사용할 수 있다는 것입니다.

class Colors {
public:
  enum TYPE {
    Red,
    Green,
    Blue
  };
};

template <typename T> void foo (T t) {
  typedef typename T::TYPE EnumType;
  // ...
}

개인적으로 저는을 사용 하는 것을 좋아하지 않으며 정규화 된 이름을 선호하므로 네임 스페이스에 대한 플러스로 생각하지 않습니다. 그러나 이것은 아마도 프로젝트에서 내리게 될 가장 중요한 결정은 아닐 것입니다!


답변

클래스 사용의 장점은 그 위에 본격적인 클래스를 구축 할 수 있다는 것입니다.

#include <cassert>

class Color
{
public:
    typedef enum
    {
        Red,
        Blue,
        Green,
        Yellow
    } enum_type;

private:
    enum_type _val;

public:
    Color(enum_type val = Blue)
        : _val(val)
    {
        assert(val <= Yellow);
    }

    operator enum_type() const
    {
        return _val;
    }
};

void SetPenColor(const Color c)
{
    switch (c)
    {
        case Color::Red:
            // ...
            break;
    }
}

위의 예에서 볼 수 있듯이 클래스를 사용하여 다음을 수행 할 수 있습니다.

  1. (슬프게도 컴파일 타임이 아닌) C ++에서 잘못된 값에서 캐스트를 허용하지 않습니다.
  2. 새로 생성 된 열거 형에 대해 (0이 아닌) 기본값을 설정합니다.
  3. 선택의 문자열 표현을 반환하는 것과 같은 추가 메서드를 추가하십시오.

operator enum_type()C ++에서 클래스를 기본 열거 형으로 변환하는 방법을 알 수 있도록 선언해야합니다 . 그렇지 않으면 switch문에 유형을 전달할 수 없습니다 .


답변

열거 형은 둘러싸는 범위로 범위가 지정 되므로 전역 네임 스페이스 오염을 방지하고 이름 충돌을 방지하기 위해 열거 형을 어떤 것으로 래핑하는 것이 가장 좋습니다 . 나는 클래스보다 네임 스페이스를 선호하는 이유 namespace는 단순히 들고있는 가방처럼 class느껴지 지만 강력한 객체처럼 느껴 지기 때문입니다 ( struct비교 class토론). 네임 스페이스의 가능한 이점은 나중에 확장 할 수 있다는 것입니다. 수정할 수없는 타사 코드를 처리하는 경우 유용합니다.

물론 C ++ 0x로 enum 클래스를 얻을 때 이것은 모두 문제입니다.