2013-06-16 1 views
3

C++ 11은 개선 된 enumenum struct과 함께 제공합니다. 그러나 이것은 아직 확실히 무엇을 앓고 - 당신이 그것에 익혀 얻을 때까지 -의 가장 놀라운 함정 하부 된 enum : 유형 enum struct E의 변수의 값은 열거 된 것들 중 하나가 될 필요하지만 이 될 수 있음 E의 기본 정수형의 범위의 값은 : 그것은 "이 E 중 하나가 아닌있는 당신이 enum 또는 enum struct 유형 E의 객체를 사용하는 모든 곳일반적인 "값 - 안전 enum"을 작성하는 방법은 무엇입니까?

enum struct X { one = 1}; 
X x = X(); // Fine! The value of x is int(0) 
x = X(2); // Cool! The value of x is int(2) 

, 당신 은이 사건을 잡으려고 에스". 하나 enum struct의 대신에 수리 할 수있을 것 일반적인 유형을 정의하는 방법

(반드시 드롭 인 대체) 재산과 인스턴스화하는 클래스의 목적은 이 아닌 다른 값을 가질 수 없습니다 "열거 된"것들?

나는 개체가 가정 어떤 구별되지 값이 아니라 이상을 던질 것이다 없습니다 만족 의미에서 수 있다면 의미 (즉, 그것을 어획량 경우 그것 "는 E들 중 하나를하지"가 될 것입니다) .

그리고 나는 그것이 피할 수없는 것 때문에이 값은 일체형 템플릿 매개 변수의 순서에 의해 "열거"할 것이며 너무 편리하게 액세스 할 수 (매크로에 의존하지 않고) 겁 따옴표에서 "열거"라고 X::one.

"열거 된"값 이 형식에서 열거 인덱스로 정적으로 검색 할 수있는 한 그 불가피한 경우 괜찮습니다. 은 (클라이언트 코드 중 하나 인덱스 또는 인덱스 값 meangingful 심볼을 연결하고, 같은 편리한 매핑을 캡슐화하는 것은 다음 간단한 것! - struct 익명 enum을 -nested A의 예)

가 있는가 이미이 질문에 잘 간주 솔루션은 내가하지 않는다 에 대해 알고 계십니까? commmentator 요청 (알리) 여기

Could you post some pseudo-code? It should show how you would like to use it.

원하는 사용의 어떤 표시를하여

계속 (내 생각) :

/* 1 */ 
/* These 2 structs could just be tag-types X{}, Y{} 
    serving to distinguish value-safe-enums that 
    would otherwise be the same. But you could 
    also get more mileage out them, as shown... 
*/ 
struct turn; 
struct hand; 

using vs_turn = val_safe_enum<turn,int,1,2>; 
using vs_hand = val_safe_enum<hand,int,1,2>; 

struct turn 
{ 
    // Want an anonymous scoped enum; only rvalue 
    enum { 
     right = vs_turn::which<0>(), // = 1 
     left = vs_turn::which<1>() // = 2 
    }; 
}; 

struct hand 
{ 
    enum { 
     right = vs_hand::which<0>(), //= 1 
     left = vs_hand::which<1>() // = 2 
    }; 
}; 
/* End 1 */ 

/* 2 */ 
char const * foo(vs_turn const & t) { 
    // Only 2 possibilities! 
    return int(t) == turn::right ? "right turn" : "left turn"; 
} 
char const * foo(vs_hand const & h) { 
    return int(h) == hand::right ? "right hand" : "left hand"; 
} 
/* End 2 */ 


vs_turn t1(0); // 3.a OK 
vs_turn t2(turn::right); // 3b. OK 
vs_hand h1(hand::left); // 3c. OK 
vs_hand h2(1); // 3d. OK 

t1 == vs_turn(turn::right); // 4. OK 

t1 < t2; // 5. OK 

t1 = t2; // 6. OK 

int(t1) == turn::right; // 7. OK. Explicit conversion to underlying type. 

/* 8 */ 
switch(int(t1)) { 
case turn::right: 
    /* Something */ break; 
case turn::left: 
    /* Something */; 
    // No default necessary! 
} 
/* End 8 */ 

vs_turn t3(3); // 9. Throw! Value out of range 
vs_turn t4; // 10. Error. No default construction. 

t1 == turn::right; // 11a. Error. No Conversion 
t1 <= h1; // 11b. Error. No conversion. 
t1 = turn::right; // 11c. Error. No conversion 
t1 = h1; // 11d. Error. No conversion. 
foo(turn::right); // 11e. Error. No conversion 

답변

1
struct C 
{ 
    enum E { a, b, c }; 

    C(E e) : e(e) { if (e > c) throw logic_error; } 

private: 
    E e; 
}; 

업데이트 :

template<typename T, T... E> struct Check; 

template<typename T> struct Check<T> { void check(T) { throw logic_error; } } 

template<typename T, T e0, T... E> struct Check<T, e0, E...> 
{ 
    void check(T e) 
    { 
     if (e != e0) 
      Check<T, E>::check(e); 
    } 
} 

template<typename T, T... E> 
struct C 
{ 
    C(T e) : e(e) { Check<T, E...>::check(e); } 

private: 
    T e; 
} 
+0

일반 솔루션을 묻습니다. –

+0

@MikeKinghan : "일반적인 솔루션"의 의미가 명확하지 않습니다. 내 솔루션이 제네릭이 아닌 이유는 무엇입니까? –

+0

"일반 데이터 유형", "일반 알고리즘"(템플릿)에서와 같이 "일반". 인스턴스화 클래스 'C'가 컴파일 타임 등에 그러한 상수의 * i * th를 편리하게 전달할 수 있도록 임의의 정수형 'T'의 임의의 시퀀스 't0, .., tn'에 대해 인스턴스화 할 수있는 솔루션 'C'는't0, .., tn' 값만을 가정 할 수 있습니다. –

0

어떨까요?

struct MyColor { 
public: 
    static MyColor Red; // defined as MyColor(red) 
    static MyColor Blue; // defined as MyColor(blue) 

    // Copy constructors, assignment etc. goes here 
private: 
    MyColor(Value value); 
    enum Value { red, blue, green }; 
    Value value; 
}; 
+0

제너릭 솔루션을 묻습니다. –

0

그것은 추한하지만 컴파일시 실패 오류 메시지가 도움이되지 않습니다 때문에 대부분이 방식을 좋아하지 않는다

enum E { a, b, c }; 

constexpr E range_check(E e) { 
    return e <= c ? e : (throw "enum value out of range"); // fails at compile time, see below 
} 

class wrapper { 
    public: 
    constexpr wrapper(E e) : e(range_check(e)) { } 
    private: 
    enum E e; 
}; 

int main() { 
    constexpr wrapper w((E)42); 
} 

. 그럼에도 불구하고 컴파일시에 it is guaranteed이 실패합니다.

이게 당신이 찾고 있는게 있니?

+0

고맙습니다. 그렇지만, 필수 정수 타입'T'에 대해'enum struct' 메타 타입과 같이 인스턴스화 될 수있는 * generic * 데이터 유형 (템플릿) 을 찾고 있습니다. 와 열거 형 값이 인덱싱 가능한 컴파일 타임 상수이고 'C'가 열거 형 값만을 취할 수있는 클래스 'C'를 제공하기 위해'T' (열거 형)의 임의의 시퀀스를 사용합니다. –

+0

@Mike 의사 코드를 게시 할 수 있습니까? 사용 방법을 보여 주어야합니다. – Ali

0

지난 한 달 동안 나는 당신이 원하는 것을 할 수있는 방법 등을 찾고있었습니다. 당신은 내 github상의 예 -를 -including 전체 코드를 볼 수 있습니다

#define STD_ENUM_ENTRY_WITHOUT_VALUE__(ENUM, NAME)  NAME, 
#define STD_ENUM_ENTRY_WITHOUT_VALUE_(ENUM, NAME)  STD_ENUM_ENTRY_WITHOUT_VALUE__(ENUM, NAME) 
#define STD_ENUM_ENTRY_WITHOUT_VALUE(ENUM, SPLIT...) STD_ENUM_ENTRY_WITHOUT_VALUE_(ENUM, SPLIT) 

#define STD_ENUM_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) NAME = VALUE, 
#define STD_ENUM_ENTRY_WITH_VALUE_(ENUM, NAME, VALUE) STD_ENUM_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) 
#define STD_ENUM_ENTRY_WITH_VALUE(ENUM, SPLIT...)  STD_ENUM_ENTRY_WITH_VALUE_(ENUM, SPLIT) 

#define FP_PP_ENUM_STD_ENTRY_1(ENUM, SPLIT...)   STD_ENUM_ENTRY_WITHOUT_VALUE(ENUM, SPLIT) 
#define FP_PP_ENUM_STD_ENTRY_2(ENUM, SPLIT...)   STD_ENUM_ENTRY_WITH_VALUE(ENUM, SPLIT) 
#define FP_PP_ENUM_STD_ENTRY__(N, ENUM, SPLIT...)  FP_PP_ENUM_STD_ENTRY_##N(ENUM, SPLIT) 
#define FP_PP_ENUM_STD_ENTRY_(N, ENUM, VALUE)   FP_PP_ENUM_STD_ENTRY__(N, ENUM, FP_PP_EXPAND VALUE) 
#define FP_PP_ENUM_STD_ENTRY(ENUM, VALUE)    FP_PP_ENUM_STD_ENTRY_(FP_PP_NUM_ARGS VALUE, ENUM, VALUE) 

#define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE__(ENUM, NAME)  ::fp::enum_entry<ENUM>(ENUM::NAME, #NAME), 
#define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE_(ENUM, NAME)  FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE__(ENUM, NAME) 
#define FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE(ENUM, SPLIT...) FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE_(ENUM, SPLIT) 

#define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) ::fp::enum_entry<ENUM>(ENUM::NAME, #NAME), 
#define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE_(ENUM, NAME, VALUE) FP_PP_ENUM_EXT_ENTRY_WITH_VALUE__(ENUM, NAME, VALUE) 
#define FP_PP_ENUM_EXT_ENTRY_WITH_VALUE(ENUM, SPLIT...)  FP_PP_ENUM_EXT_ENTRY_WITH_VALUE_(ENUM, SPLIT) 

#define FP_PP_ENUM_EXT_ENTRY_1(ENUM, SPLIT...)   FP_PP_ENUM_EXT_ENTRY_WITHOUT_VALUE(ENUM, SPLIT) 
#define FP_PP_ENUM_EXT_ENTRY_2(ENUM, SPLIT...)   FP_PP_ENUM_EXT_ENTRY_WITH_VALUE(ENUM, SPLIT) 
#define FP_PP_ENUM_EXT_ENTRY__(N, ENUM, SPLIT...)  FP_PP_ENUM_EXT_ENTRY_##N(ENUM, SPLIT) 
#define FP_PP_ENUM_EXT_ENTRY_(N, ENUM, VALUE)   FP_PP_ENUM_EXT_ENTRY__(N, ENUM, FP_PP_EXPAND VALUE) 
#define FP_PP_ENUM_EXT_ENTRY(ENUM, VALUE)    FP_PP_ENUM_EXT_ENTRY_(FP_PP_NUM_ARGS VALUE, ENUM, VALUE) 

#define DEFINE_EXT_ENUM(ENUM, ...)               \ 
    enum class ENUM {                  \ 
     FP_PP_SEQ_FOR_EACH(FP_PP_ENUM_STD_ENTRY, ENUM, __VA_ARGS__)       \ 
    };                      \ 
    template<typename>                  \ 
    struct enum_descriptor;                 \ 
                          \ 
    template<>                    \ 
    struct enum_descriptor<ENUM> {               \ 
    public:                     \ 
     using enum_type = ENUM;                \ 
     using entry_type = ::fp::enum_entry<enum_type>;          \ 
     using this_type = enum_descriptor<enum_type>;          \ 
     using const_iterator = entry_type const *;           \ 
     using const_reverse_iterator = std::reverse_iterator<const_iterator>;    \ 
     using size_type = std::size_t;              \ 
    private:                    \ 
     constexpr static std::size_t Size = FP_PP_NUM_ARGS(__VA_ARGS__);     \ 
     using container_type = std::array<entry_type, Size>;        \ 
                          \ 
     constexpr static container_type const _entries          \ 
     {                     \ 
      {                    \ 
       FP_PP_SEQ_FOR_EACH(FP_PP_ENUM_EXT_ENTRY, ENUM, __VA_ARGS__)     \ 
      }                    \ 
     };                     \ 
                          \ 
     template<std::size_t... Is >              \ 
     constexpr static char const * name_of_impl(enum_type v, ::fp::indices<Is...>) {  \ 
      using std::get;                 \ 
      return ::fp::enum_helper<enum_type>::get_name(v, get<Is>(_entries)...);   \ 
     }                     \ 
                          \ 
     template<std::size_t... Is >              \ 
     constexpr static enum_type value_of_impl(char const * n, ::fp::indices<Is...>) { \ 
      using std::get;                 \ 
      return ::fp::enum_helper<enum_type>::get_value(n, get<Is>(_entries)...);  \ 
     }                     \ 
                          \ 
     template<typename V, std::size_t... Is >           \ 
     static bool try_parse_impl(V val, enum_type & res, ::fp::indices<Is...>) {   \ 
      using std::get;                 \ 
      return (::fp::enum_helper<enum_type>::is_valid_entry(val, get<Is>(_entries)...)) ? \ 
       ((res = static_cast<enum_type> (val)), true)        \ 
       : false;                 \ 
     }                     \ 
                          \ 
     template<typename V, std::size_t... Is >           \ 
     constexpr static enum_type parse_impl(V val, ::fp::indices<Is...>) {    \ 
      using std::get;                 \ 
      return (::fp::enum_helper<enum_type>::parse(val, get<Is>(_entries)...));  \ 
     }                     \ 
    public:                     \ 
     constexpr enum_descriptor() = default;            \ 
     enum_descriptor(enum_descriptor const &) = delete;         \ 
     enum_descriptor(enum_descriptor &&) = delete;          \ 
                          \ 
     constexpr static char const * name() noexcept {          \ 
      return #ENUM;                 \ 
     }                     \ 
                          \ 
     constexpr static char const * name_of(enum_type value) {       \ 
      return name_of_impl(value, ::fp::build_indices<Size>());      \ 
     }                     \ 
                          \ 
     constexpr static enum_type value_of(char const * name) {       \ 
      return value_of_impl(name, ::fp::build_indices<Size>());      \ 
     }                     \ 
                          \ 
     constexpr static size_type size() noexcept {          \ 
      return Size;                 \ 
     }                     \ 
                          \ 
     constexpr static const_iterator begin() {           \ 
      using std::get;                 \ 
      return const_iterator(&get<0>(_entries));          \ 
     }                     \ 
                          \ 
     constexpr static const_iterator end() {            \ 
      using std::get;                 \ 
      return const_iterator(&get<(Size - 1)>(_entries) + 1);       \ 
     }                     \ 
                          \ 
     template<typename T,                \ 
       typename = typename std::enable_if<std::is_integral<T>::value>::type>  \ 
     static bool try_parse(T value, enum_type & res){         \ 
      return try_parse_impl(value, res, ::fp::build_indices<Size>());     \ 
     }                     \ 
                          \ 
     template<typename T,                \ 
       typename = typename std::enable_if<std::is_integral<T>::value>::type>  \ 
     constexpr static enum_type parse(T value){           \ 
      return parse_impl(value, ::fp::build_indices<Size>());       \ 
     }                     \ 
    };                      \ 
    template<>                    \ 
    constexpr std::array<::fp::enum_entry<ENUM>, FP_PP_NUM_ARGS(__VA_ARGS__)> const enum_descriptor<ENUM>::_entries; 

: 는 여기에 내가 무엇을 최대 온 것입니다.

이것이 예상 한대로 수행되지만, 기존 열거 형의 드롭 인 대체품으로 (직접) 사용할 수 없습니다.

DEFINE_EXT_ENUM(my_1st_enum, (fread, 3), (fwrite), (fflush, fread << 2)); 
DEFINE_EXT_ENUM(my_2nd_enum, (fopen), (fclose, 1)); 

마지막 한가지 : 다음 -Werr 플래그 GCC에이를 컴파일하려고하지 않습니다 때문에

것은, 자신에게 당신과 같이 정의되어야 지원하고자하는 열거 형을 코딩을 많이 저장하려면 컴파일이 오류가 발생합니다 (이유를 이해하지만 현재 해결 방법을 알지 못합니다).

편집 : 귀하의 예제를 바탕으로

이 당신이 내 DEFINE_EXT_ENUM 사용하여 어떻게 할 것입니다 : 내가 열거 형의 래퍼 (안 C 지원을 생성하는이 추악한 매크로를 썼다

#include "enum_pp_def.hpp" 

#include <cassert> 
#include <iostream> 

DEFINE_EXT_ENUM(turn, (right,1), (left,2)); 
DEFINE_EXT_ENUM(hand, (right,1), (left,2)); 

using turn_descr = enum_descriptor<turn>; 
using hand_descr = enum_descriptor<hand>; 

/* 2 */ 
constexpr char const * foo(turn t) { 
    return (turn_descr::is_valid((int)t)) ? (turn::right == t) ? "right turn" : "left turn" : throw t; 
} 
constexpr char const * foo(hand h) { 
    return (hand_descr::is_valid((int)h)) ? (hand::right == h) ? "right hand" : "left hand" : throw h; 
} 
/* End 2 */ 

int main(int argc, char ** argv) { 
    turn t1 = turn_descr::parse(1); // 3.a OK 
    turn t2(turn::right); // 3b. OK 
    hand h1(hand::left); // 3c. OK 
    hand h2 = hand_descr::parse(2); // 3d. OK 

    assert(t1 == turn::right); // 4. OK 

    /* 8 */ 
    switch(t1) { 
    case turn::right: 
     std::cout << "right turn" << std::endl; 
     break; 
    case turn::left: 
     std::cout << "left turn" << std::endl; 
     break; 
    } 
    /* End 8 */ 

    std::cout << foo(hand::left) << std::endl; 
    std::cout << foo(turn::right) << std::endl; 

    constexpr turn t3 = turn_descr::parse(3) // throw at compile time 
    turn t4 = turn_descr::parse(3);    // throw at runtime 
} 
+0

gcc 4.8.1,'-g; -O0; -Wall; -std = C++ 11'은 github 예제를 경고 7 개로 컴파일하지만 올바르게 실행합니다. clang 3.2 barfs './enum_descriptor.hpp:24:32 : 오류 : 가상 함수는 constexpr 일 수 없습니다. ' 아무튼 열거 형 값 중 하나를 사용하여 열거 형 중 하나를 초기화 할 수 없습니다 (예 : 'ext :: my_1st_enum en1 (3);'barfs; 그래서 나는'enum struct' 또는'enum' 대신에 이것을 사용할 수 있다고 생각하지 않을 것입니다. Ali에 대한 응답으로 내 게시물에 대한 업데이트를 확인하십시오. –

+0

@MikeKinghan 제 편집을보세요. DEFINE_EXT_ENUM 구현을 사용하여 예제를 변환했습니다. –

+0

프로그램이 gcc 4.7.2/4.8.1, clang 3.2, '-g; -O0으로 컴파일되지 않습니다. ; -Wall; -std = C++ 11' (컴파일되지 않은 행을 주석 처리했습니다). gcc 4.8.1 :'error : 'is_valid'는 'turn_descr {aka enum_descriptor }'의 멤버가 아닙니다. '; '오류 : constexpr 함수의 본문 'constexpr const char * foo (turn)'return 문 '이 아니며'turn' 대신'hand'에 대해 같은 오류가 발생합니다. –

0

를 ++ 열거 :(11) 볼 수 있듯이, 전달되는 값이 열거의 값이면 ctor에 검사 :.

#include <iostream> 
using namespace std; 

#define GENERATE_ENUM(NAME,VALUES...) class NAME           \ 
             {             \ 
             private:           \ 
             static const int _ENUM_LOOKUP_TABLE[];   \ 
             static const unsigned int _lenght;    \ 
             public:           \ 
             enum { __VA_ARGS__ };       \ 
                         \ 
             NAME(int value)         \ 
             {            \ 
              bool trying = true;       \ 
                         \ 
              for(int i = 0; i < _lenght ; ++i)   \ 
               trying = _ENUM_LOOKUP_TABLE[i] != value; \ 
                         \ 
              if(trying) throw;       \ 
             }            \ 
             };             \ 
                         \ 
             const int NAME::_ENUM_LOOKUP_TABLE[] = { __VA_ARGS__ }; \ 
             const unsigned int NAME::_lenght = sizeof(NAME::_ENUM_LOOKUP_TABLE)/sizeof(int); 

GENERATE_ENUM(MyEnum,ONE,TWO,THREE,FOUR,FIVE,SIX)       

int main() 
{ 
    MyEnum e(33); //This throws an exception (Is not a value of the enum) 

    cout << MyEnum::THREE << endl; //Scoped enums, like C++11 
    cout << MyEnum::ONE << endl; 
    return 0; 
} 

이 예는 CPP을 발생 다음 코드를

#include <iostream> 
using namespace std; 


class MyEnum 
{ 
private: 
    static const int _ENUM_LOOKUP_TABLE[]; 
    static const unsigned int _lenght; 
public: 
    enum { ONE , TWO , THREE , FOUR , FIVE , SIX }; 

    MyEnum (int value) 
    { 
     bool trying = false; 
     for(int i = 0; i < _lenght ; ++i) 
      trying = _ENUM_LOOKUP_TABLE[i] != value; 

     if(trying) throw; 
    } 
}; 
const int MyEnum ::_ENUM_LOOKUP_TABLE[] = { ONE , TWO , THREE , FOUR , FIVE , SIX }; 
const unsigned int MyEnum ::_lenght = sizeof(MyEnum ::_ENUM_LOOKUP_TABLE)/sizeof(int); 



int main() 
{ 
    MyEnum e(33); //This throws an exception (Is not a value of the enum) 

    cout << MyEnum::THREE << endl; 
    cout << MyEnum::ONE << endl; 
    return 0; 
} 

내가 생각하는 가장 간단한 매크로 솔루션으로, 정확히 문제를 다룹니다.

+0

이 코드가 컴파일되지 않을까 걱정됩니다 (gcc 4.7.2, gcc 4.8,1, clang 3.2). 경고 : __VA_ARGS__는 C99 가변 매크로 확장에만 나타납니다. '; '오류 : 'THREE'는 'MyEnum'의 멤버가 아닙니다. '오류 : 'ONE'은 'MyEnum'의 멤버가 아닙니다. 그리고 user1131467과 Ali에 대한 내 대답을보십시오. 나는 매크로를 찾고 있지 않다. –

+0

문제는 C/C++에서 열거 형은 정수 상수의 간격이며 열거 형은 "클래스"가 아니므로 해당 유형의 검사를 수행 할 수 없습니다. 그래서 제네릭 솔루션은 불가능합니다 (매크로없이). – Manu343726

+0

아, 예, 코드가 컴파일되지 않으며 이유를 모르겠습니다. Im이 GCC4.7.2와 함께 writting하고 컴파일하는 대부분의 시간 동안 나는 그것을 컴파일하고있다. (왜 컴파일되지 않는지, 익명의 enum은 public이며, 매크로에 의해 잘 확장되어있다.) – Manu343726

0

C++ 11 관용구에 C++ 03 문제로 인한 문제가 있습니다.

하나의 인수가있는 X(2)이라는 "생성자 호출"표기법은 실제로 C 스타일 캐스트 (X) 2의 축약어로, 이는 독성이 reinterpret_cast<X>(2)으로 변환됩니다. 범위가 지정된 열거 형의 판매 지점 중 하나는 int으로 변환하지 않는다는 것입니다.

클래스 유형을 제외하고 Type(initializer) 구문을 사용하지 마십시오. 예기치 않은 값을 가져 오지 않아야합니다. (음, GCC에 경고가 있으면 좋겠지 만 찾을 수는 없습니다.)

코드에서 "uniform initialization"을 X{ 2 }으로 바꾸면 컴파일러가 적절한 오류를 발생시킵니다.

+0

)는 의'struct enum'에 대한 취약성을 보여주고 있었지만,'struct {{arg {}} '는 항상 같은 의미는 아니기 때문에 uniform 초기화를 할 수 없습니다. 'T (arg)'와'T'가 클래스 타입인지 아닌지를 알지 못할 수도 있습니다 .하지만 현재 표준의'reinterpret_cast'에 대한 현재 제한은 해결책이 그것을 거부하도록 허용 할 수도 있습니다. –

0

나는 이것에 관해 이미 생각해 왔으며, Core C++ 의미 론적 추가가 필요하다.표준에서 정의 된 두 가지 유형 인 boolnullptr_t을 제외하고 C++에서는 찾고자하는 것을 사용할 수 없습니다.

사실, 명시 적으로 객체 표준에 명시되어있다 (그래, 나는 물체를 의미, 그 표준에 사용되는 이름이다) 유형 bool의는 true 또는 false 중 하나 인 값을했다. 정의되지 않은 동작 범위를 벗어났습니다. 즉, bool 유형의 (예 : 로컬) 변수는 정의 된 동작 영역에서 true 또는 false 이외의 값을 가질 수 없다는 것을 의미합니다. (단순화하기 위해 256을 가정 해 봅시다.) 이것은 bool 값에 대한 스토리지 요구 사항을 설명하지 않고 언어 레벨을 처리하지만, int으로의 변환과 관련된 요구 사항을 설명합니다. (false0으로 변환해야하고 true1으로 변환해야합니다.) :1 비트 필드가 bool으로 올바르게 변환되어야한다는 요구 사항이 있습니다.

실제로 이것은 C++에서는 아직 존재하지 않습니다. enum 유형을 정의하는 방법을 사용하면 원하는 방식으로 행동하는 것이 실제로 많은 흥미로운 것을 암시 (허용)합니다. enum 유형이 합법적 인 한도로 가득 찼습니다. 모든 값은 기본 유형에 맞는 경우 enum 유형으로 변환 할 수 있으며 안전하게 int로 다시 변환 할 수 있습니다. 그리고 유형에 의해 취해지지 않는 가치가없는 "무료 저장 용량"이 없습니다.

자,이 기능이 존재한다고 가정하고 explicit enum라고 가정 해 보겠습니다. 두 값은 "촬영"때문에

explicit enum bool { 
    false, 
    true 
}; 

, 나는 bool의 모든 값과 세 번째가 타입 정의 할 "말 :이 해당 bool 맵을 지정할 수

explicit enum tristate { 
    using bool; 
    undefined 
}; 

그런 다음 강하게 컴파일러는 tristate 변수에 조건을 전파 할 수있다. 당신은 명시 적으로 booltristate에서 변환 할 수 있습니다. 당신은 암시 적으로 tristatebool에서 변환 할 수 있습니다. 이러한 유형의 변수를 입력합니다, 컴파일러는 알 것이라고을 경우다음 x == true, 방법은 이미 bool 변수와 않습니다. explicit enum에 새 값을 추가하려고 할 때마다 switch 문에 default 사례가 필요하지 않으며 악의적으로 컴파일에 실패 할 것으로 판단 할 수 있습니다.

임의 전환을 int에서 금지해야합니다.

이것은위원회에그룹에 대한 토론을 작성하고 제출하는 제안 일 것입니다.

관련 문제