当前位置:  开发笔记 > 编程语言 > 正文

如何轻松地将c ++枚举映射到字符串

如何解决《如何轻松地将c++枚举映射到字符串》经验,为你挑选了6个好方法。

我在一些库头文件中有一堆枚举类型,我正在使用,我想有一种方法将枚举值转换为用户字符串 - 反之亦然.

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);

MSalters.. 59

如果你想让enum将自己命名为字符串,请参阅这篇文章.否则,一个std::map将很好地工作.(没有必要将字符串文字复制到地图中的std :: strings)

对于额外的语法糖,这里是如何编写map_init类.目标是允许

std::map MyMap;
map_init(MyMap)
    (eValue1, "A")
    (eValue2, "B")
    (eValue3, "C")
;

该函数template map_init(T&)返回一个map_init_helper. map_init_helper存储T&,并定义琐碎map_init_helper& operator()(typename T::key_type const&, typename T::value_type const&).(返回*thisoperator()允许的链接operator(),像operator<<std::ostreamS)

template 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 map_init_helper map_init(T& item)
{
    return map_init_helper(item);
}

由于函数和辅助类是模板化的,因此可以将它们用于任何地图或类似地图的结构.即它也可以添加条目std::unordered_map

如果您不喜欢编写这些帮助程序,boost :: assign提供了相同的功能.



1> MSalters..:

如果你想让enum将自己命名为字符串,请参阅这篇文章.否则,一个std::map将很好地工作.(没有必要将字符串文字复制到地图中的std :: strings)

对于额外的语法糖,这里是如何编写map_init类.目标是允许

std::map MyMap;
map_init(MyMap)
    (eValue1, "A")
    (eValue2, "B")
    (eValue3, "C")
;

该函数template map_init(T&)返回一个map_init_helper. map_init_helper存储T&,并定义琐碎map_init_helper& operator()(typename T::key_type const&, typename T::value_type const&).(返回*thisoperator()允许的链接operator(),像operator<<std::ostreamS)

template 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 map_init_helper map_init(T& item)
{
    return map_init_helper(item);
}

由于函数和辅助类是模板化的,因此可以将它们用于任何地图或类似地图的结构.即它也可以添加条目std::unordered_map

如果您不喜欢编写这些帮助程序,boost :: assign提供了相同的功能.


@xtofl:此处显示的“相关问题”与我发布问题时列出的相关问题完全不同!

2> Alastair..:

MSalters解决方案很好,但基本上是重新实现的boost::assign::map_list_of.如果你有提升,你可以直接使用它:

#include 
#include 
#include 

using boost::assign::map_list_of;

enum eee { AA,BB,CC };

const boost::unordered_map eeeToString = map_list_of
    (AA, "AA")
    (BB, "BB")
    (CC, "CC");

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


实际上这个答案在很大程度上已经过时了.

3> jfs..:

从另一个表单自动生成一个表单.

资源:

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

产生:

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

如果枚举值很大,那么生成的表单可以使用Constantin建议的unordered_map <>或模板.

资源:

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

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

产生:

template  struct enum2str { static const char * const value; };
template  const char * const enum2str::value = "error";

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

例:

#include 

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


如果您有一些perl/python来从文本文件中读取字符串列表,并在编译时使用静态char生成.h文件.="编写程序来编写程序"

4> 小智..:

我记得在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 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(value)]; \
return os;} 

要在代码中使用它,只需执行以下操作:

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



5> David Allan ..:

我建议混合使用X-macro是最好的解决方案和以下模板功能:

借用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  T str2enum( const char* );
template  const char* enum2str( T );

#define STR2ENUM(TYPE,ARRAY) \
template <> \
TYPE str2enum( 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 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)



6> 小智..:

我使用以下复制的解决方案:

#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;
}

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有