2011-02-12 3 views
11

는 : GCC 4.4은 다음과 같은 C++ 0X 코드를 허용합니다"열거 클래스"에뮬레이션 또는 고체 대안은 10.0 나는 다음과 같은 문제에 대한 해결책의 해키 종류를 찾고 있어요

enum class my_enum 
{ 
    value1, 
    value2 
}; 

을 어느 다음과 같이 사용할 수 있습니다.

my_enum e = my_enum::value1; 

모든 종류의 벨과 호루라기가 있습니다. MSVC 2010과 호환되도록이 코드를 작성하여 사용 구문이 변경되지 않도록하고 싶습니다. 나는 이미 here 전에 이것에 대해 숙고 해왔다. 그리고 대답은 받아 들여지지 만 enum과 enum 값에 대한 두 개의 서로 다른 이름에 대한 필요성 때문에이 두 가지 접근 방법의 호환성이 사라지게된다. 이것은 물론 C++ 0x 코드를 그대로 사용할 수 없게 만듭니다. 어떤 #undef#define 속임수가이 문제를 해결할 수 있는지 궁금해했습니다. 과 같은 구문 (엄격한 유형 안전성 제외)을 사용할 수 있지만 최소한 동일한 구문을 사용할 수 있습니다. 감사!

답변

20

난 그냥 제임스 '좋은 해킹에 문제가 발견 :

는 해킹 해결 방법으로, 당신은 struct에서 enum을 포장 할 수 있고 암시 적 변환 한 쌍을 사용했다 그 사용하고있다), 문제 수정. my_enum에 대한 스트림 연산자를 정의하려고 할 때 문제를 발견했습니다.

#include <iostream> 

struct my_enum { 
    enum type { 
     value1, 
     value2 
    }; 

    my_enum(type v) : value_(v) { } 

    operator type() const { return value_; } 

private: 

    type value_; 
}; 

std::ostream& 
operator<<(std::ostream& os, my_enum v) 
{ 
    return os << "streaming my_enum"; 
} 

int main() 
{ 
    std::cout << my_enum::value1 << '\n'; 
} 

출력은 :

0 

문제가 my_enum::value1my_enum 상이한 형태를 갖는다. 제임스의 해킹에 대한 해킹이 있습니다.

struct my_enum 
{ 
    static const my_enum value1; 
    static const my_enum value2; 

    explicit my_enum(int v) : value_(v) { } 

    // explicit // if you have it! 
     operator int() const { return value_; } 

private: 

    int value_; 
}; 

my_enum const my_enum::value1(0); 
my_enum const my_enum::value2(1); 

주 : 그렇지 않으면 ENUM 계 지정하지 않는

  1. 하기, 열거 범위의 기본 타입 int이다.
  2. 기본 정수 유형과의 명시 적 변환이 허용됩니다. 그러나 암시 적 전환은 그렇지 않습니다. 최선을 다해.
  3. 이 해킹은 값을 두 번 열거해야하기 때문에 James '보다 더 피타입니다. 범위가 지정된 열거 형 지원이없는 컴파일러가 빠르게 멸종되기를 바라고 있습니다.
+0

아주 멋진 솔루션입니다. –

+0

놀라운 솔루션. 이것은 위장해야합니다. – FailedDev

+1

이 방법은 적어도 MSVC 10에서는 "switch"/'case "를 허용하지 않는 것 같습니다 ("C2051 : case expression not constant "를 얻습니다). 'enum'이 전형적으로 이런 방식으로 사용되기 때문에 이것은 큰 PITA입니다. –

5

이 솔루션을 사용하지 마십시오. 하워드 (Howard)가 더 좋은 해결책을 제시하는 대답을 참조하십시오. 나는 하워드의 대답이 그것을 언급하기 때문에이 포스트를 여기에서 떠날 것이다.

새롭고 아직 표준이 아니거나 광범위하게 구현되지 않은 새로운 언어 기능을 아직 지원하지 않는 컴파일러로 코드를 컴파일해야하는 경우 코드에서 해당 언어 기능을 사용하지 않는 것이 가장 좋습니다. 내가 지금까지 가지고있는 (

struct my_enum { 
    enum type { 
     value1, 
     value2 
    }; 

    my_enum(type v) : value_(v) { } 

    operator type() const { return value_; } 

private: 

    type value_; 
}; 
+0

이것은 패턴인가요? 왜 그것을 해킹이라고 생각합니까? 그것은 청초하다. – Inverse

+1

@Inverse : 반복적으로 사용하면 패턴이됩니다 :-). 네임 스페이스 오염을 막기 위해 구조체 또는 네임 스페이스에서 열거 형을 래핑하는 것은 일반적인 기술이며 일관되게 사용합니다 (주로 대부분). 묵시적 변환을 사용하여 캡슐화 구조체를 열거 형처럼 사용할 수있게하는 것은 공통적 인 패턴이 아니며 최소한 코드를 읽는 즐거움을 누렸다. 암시 적 변환 때문에 암묵적인 변환을 통해 지속적으로 다른 방법을 발견하고 있습니다. –

0

나는 진정으로 최적의 해결책을 찾기 위해 하루 종일 싸우고 있지만, 하나가되지는 않습니다.나는 다음과 함께 온 비 형 템플릿 매개 변수

에서 같은

  • 사용 가능한 switch 문에
  • 가능한 핵심 형식으로 암시 적으로 변환

    1. 하지 내 열거 필요 코드, Howard Hinnant의 솔루션 위에 구축 됨 :

      struct DataType 
      { 
          struct integral { 
           enum type { None, Single, Double, Int }; 
          }; 
      
          typedef typename integral::type integral_type; 
      
          explicit DataType(integral_type v) : val(v) {} 
          integral_type integral_value() const { return val; } 
      
          bool operator==(const DataType& s) const { return val == s.val; } 
          bool operator!=(const DataType& s) const { return val != s.val; } 
      
          static const DataType None; 
          static const DataType Single; 
          static const DataType Double; 
          static const DataType Int; 
      
      private: 
          integral_type val; 
      }; 
      

      .cpp 파일 : 비 타입 템플릿 매개 변수로

      const DataType DataType::None (DataType::integral::None); 
      const DataType DataType::Single (DataType::integral::Single); 
      const DataType DataType::Double (DataType::integral::Double); 
      const DataType DataType::Int (DataType::integral::Int); 
      

      : 스위치에서

      template <DataType::integral_type> 
      struct DataTypeTraits; 
      
      template <> 
      struct DataTypeTraits<DataType::integral::Single> 
      { 
          enum { size = 4 }; 
      }; 
      

      :

      size_t get_size(DataType type) 
      { 
          switch (type.integral_value()) { 
           case DataType::integral::Single: return DataTypeTraits<DataType::integral::Single>::size; 
           case DataType::integral::Double: return DataTypeTraits<DataType::integral::Double>::size; 
           case DataType::integral::Int:  return DataTypeTraits<DataType::integral::Int>::size; 
           default:       throw std::logic_error("Unknown data type."); 
          } 
      } 
      
      특히 큰되지

      ,하지만 그것을 얻을만큼 좋은 것 같아요. ..

  • 관련 문제