[c++] C ++ 열거 형을 문자열에 쉽게 매핑하는 방법

사용중인 일부 라이브러리 헤더 파일에 열거 형 유형이 많이 있으며 열거 형 값을 사용자 문자열로 변환하는 방법을 원합니다.

RTTI는 ‘사용자 문자열’이 열거 형보다 조금 더 읽기 쉬워야하기 때문에 나를 위해하지 않습니다.

무차별 대입 솔루션은 이와 같은 여러 기능이 될 수 있지만 너무 C와 비슷하다고 생각합니다.

enum MyEnum {VAL1, VAL2,VAL3};

String getStringFromEnum(MyEnum e)
{
  switch e
  {
  case VAL1: return "Value 1";
  case VAL2: return "Value 2";
  case VAL1: return "Value 3";
  default: throw Exception("Bad MyEnum");
  }
}

템플릿을 사용하는 우아한 솔루션이 있다는 직감이 있지만 아직 머리가 잘 잡히지 않습니다.

업데이트 : 제안 해 주셔서 감사합니다-열거 형이 타사 라이브러리 헤더에 정의되어 있음을 분명히 했어야했기 때문에 정의를 변경할 필요가 없습니다.

이제 내 직감은 템플릿을 피하고 다음과 같이하는 것입니다.

char * MyGetValue(int v, char *tmp); // implementation is trivial

#define ENUM_MAP(type, strings) char * getStringValue(const type &T) \
 { \
 return MyGetValue((int)T, strings); \
 }

; enum eee {AA,BB,CC}; - exists in library header file
; enum fff {DD,GG,HH};

ENUM_MAP(eee,"AA|BB|CC")
ENUM_MAP(fff,"DD|GG|HH")

// To use...

    eee e;
    fff f;
    std::cout<< getStringValue(e);
    std::cout<< getStringValue(f);



답변

열거 형 이름 자체를 문자열로하려면 이 게시물을 참조하십시오 . 그렇지 않으면 a std::map<MyEnum, char const*>가 잘 작동합니다. (문자열 리터럴을 맵의 std :: strings에 복사 할 필요가 없습니다)

추가 구문 설탕을 위해 map_init 클래스를 작성하는 방법은 다음과 같습니다. 목표는

std::map<MyEnum, const char*> MyMap;
map_init(MyMap)
    (eValue1, "A")
    (eValue2, "B")
    (eValue3, "C")
;

이 함수 template <typename T> map_init(T&)map_init_helper<T>.
map_init_helper<T>T &를 저장하고 사소한 map_init_helper& operator()(typename T::key_type const&, typename T::value_type const&). (반환 *this에서 것은 operator()의 체인을 허용 operator()처럼, operator<<std::ostream들)

template<typename T> struct map_init_helper
{
    T& data;
    map_init_helper(T& d) : data(d) {}
    map_init_helper& operator() (typename T::key_type const& key, typename T::mapped_type const& value)
    {
        data[key] = value;
        return *this;
    }
};

template<typename T> map_init_helper<T> map_init(T& item)
{
    return map_init_helper<T>(item);
}

함수 및 도우미 클래스는 템플릿 화되어 있으므로 모든지도 또는지도와 유사한 구조에 사용할 수 있습니다. 즉, 항목을 추가 할 수도 있습니다.std::unordered_map

이러한 도우미를 작성하는 것을 좋아하지 않는 경우 boost :: assign은 기본적으로 동일한 기능을 제공합니다.


답변

MSalters 솔루션은 좋은 솔루션이지만 기본적으로 boost::assign::map_list_of. 부스트가있는 경우 직접 사용할 수 있습니다.

#include <boost/assign/list_of.hpp>
#include <boost/unordered_map.hpp>
#include <iostream>

using boost::assign::map_list_of;

enum eee { AA,BB,CC };

const boost::unordered_map<eee,const char*> eeeToString = map_list_of
    (AA, "AA")
    (BB, "BB")
    (CC, "CC");

int main()
{
    std::cout << " enum AA = " << eeeToString.at(AA) << std::endl;
    return 0;
}


답변

한 양식을 다른 양식에서 자동 생성합니다.

출처:

enum {
  VALUE1, /* value 1 */
  VALUE2, /* value 2 */
};

생성 :

const char* enum2str[] = {
  "value 1", /* VALUE1 */
  "value 2", /* VALUE2 */
};

열거 형 값이 크면 생성 된 양식은 Constantin이 제안한대로 unorder_map <> 또는 템플릿을 사용할 수 있습니다.

출처:

enum State{
  state0 = 0, /* state 0 */
  state1 = 1, /* state 1 */
  state2 = 2, /* state 2 */
  state3 = 4, /* state 3 */

  state16 = 0x10000, /* state 16 */
};

생성 :

template <State n> struct enum2str { static const char * const value; };
template <State n> const char * const enum2str<n>::value = "error";

template <> struct enum2str<state0> { static const char * const value; };
const char * const enum2str<state0>::value = "state 0";

예:

#include <iostream>

int main()
{
  std::cout << enum2str<state16>::value << std::endl;
  return 0;
}


답변

나는 StackOverflow의 다른 곳에서 이것을 답한 것을 기억합니다. 여기에서 반복합니다. 기본적으로 가변 매크로를 기반으로하는 솔루션이며 사용하기 매우 쉽습니다.

#define AWESOME_MAKE_ENUM(name, ...) enum class name { __VA_ARGS__, __COUNT}; \
inline std::ostream& operator<<(std::ostream& os, name value) { \
std::string enumName = #name; \
std::string str = #__VA_ARGS__; \
int len = str.length(); \
std::vector<std::string> strings; \
std::ostringstream temp; \
for(int i = 0; i < len; i ++) { \
if(isspace(str[i])) continue; \
        else if(str[i] == ',') { \
        strings.push_back(temp.str()); \
        temp.str(std::string());\
        } \
        else temp<< str[i]; \
} \
strings.push_back(temp.str()); \
os << enumName << "::" << strings[static_cast<int>(value)]; \
return os;} 

코드에서 사용하려면 다음을 수행하십시오.

AWESOME_MAKE_ENUM(Animal,
    DOG,
    CAT,
    HORSE
);
auto dog = Animal::DOG;
std::cout<<dog;


답변

X- 매크로를 혼합하여 사용 하는 것이 최상의 솔루션 이라고 제안합니다. 이며 다음과 같은 템플릿 기능을 합니다.

marcinkoziukmyopenidcom 을 빌리고 확장 하려면

enum Colours {
#   define X(a) a,
#   include "colours.def"
#   undef X
    ColoursCount
};

char const* const colours_str[] = {
#   define X(a) #a,
#   include "colours.def"
#   undef X
    0
};

template <class T> T str2enum( const char* );
template <class T> const char* enum2str( T );

#define STR2ENUM(TYPE,ARRAY) \
template <> \
TYPE str2enum<TYPE>( const char* str ) \
    { \
    for( int i = 0; i < (sizeof(ARRAY)/sizeof(ARRAY[0])); i++ ) \
        if( !strcmp( ARRAY[i], str ) ) \
            return TYPE(i); \
    return TYPE(0); \
    }

#define ENUM2STR(TYPE,ARRAY) \
template <> \
const char* enum2str<TYPE>( TYPE v ) \
    { \
    return ARRAY[v]; \
    }

#define ENUMANDSTR(TYPE,ARRAY)\
    STR2ENUM(TYPE,ARRAY) \
    ENUM2STR(TYPE,ARRAY)

ENUMANDSTR(Colours,colours_str)

colour.def

X(Red)
X(Green)
X(Blue)
X(Cyan)
X(Yellow)
X(Magenta)


답변

아래에서 재현 하는 솔루션을 사용 합니다.

#define MACROSTR(k) #k

#define X_NUMBERS \
       X(kZero  ) \
       X(kOne   ) \
       X(kTwo   ) \
       X(kThree ) \
       X(kFour  ) \
       X(kMax   )

enum {
#define X(Enum)       Enum,
    X_NUMBERS
#undef X
} kConst;

static char *kConstStr[] = {
#define X(String) MACROSTR(String),
    X_NUMBERS
#undef X
};

int main(void)
{
    int k;
    printf("Hello World!\n\n");

    for (k = 0; k < kMax; k++)
    {
        printf("%s\n", kConstStr[k]);
    }

    return 0;
}


답변

MyEnum 변수의 문자열 표현을 얻으려면 템플릿이 잘라 내지 않습니다. 템플릿은 컴파일 타임에 알려진 정수 값에 특화 될 수 있습니다.

그러나 그것이 당신이 원하는 것이라면 다음을 시도하십시오.

#include <iostream>

enum MyEnum { VAL1, VAL2 };

template<MyEnum n> struct StrMyEnum {
    static char const* name() { return "Unknown"; }
};

#define STRENUM(val, str) \
  template<> struct StrMyEnum<val> { \
    static char const* name() { return str; }};

STRENUM(VAL1, "Value 1");
STRENUM(VAL2, "Value 2");

int main() {
  std::cout << StrMyEnum<VAL2>::name();
}

이것은 장황하지만 문제가 된 것과 같은 오류를 포착합니다 case VAL1.