如何轻松地将c ++枚举映射到字符串 [英] How to easily map c++ enums to strings
问题描述
RTTI不会为我做,因为'用户字符串'需要比枚举更易读。
一个强力解决方案将是一堆这样的功能,但我觉得这有点像C一样。
枚举MyEnum {VAL1,VAL2,VAL3};
String getStringFromEnum(MyEnum e)
{
switch e
{
case VAL1:returnValue 1;
case VAL2:returnValue 2;
case VAL1:returnValue 3;
default:throw异常(Bad MyEnum);
}
}
我有一个直觉,有一个优雅的解决方案使用模板,但我不能完全了解它。
更新:感谢您的建议 - 我应该已经明确表示枚举在第三方库标题中定义,所以我不想更改它们的定义。
我现在的感觉是避免模板和做这样的事情:
char * MyGetValue(int v,char * tmp); //实现是微不足道的
#define ENUM_MAP(类型,字符串)char * getStringValue(const类型& T)\
{\
返回MyGetValue((int) T,字符串); \
}
; enum eee {AA,BB,CC}; - 存在于库头文件
;枚举fff {DD,GG,HH};
ENUM_MAP(eee,AA | BB | CC)
ENUM_MAP(fff,DD | GG | HH)
//要使用.. 。
eee e;
fff f;
std :: cout<<<向GetStringValue(E);
std :: cout<<<向GetStringValue(F);
如果您希望将枚举名称作为字符串,请参阅这篇文章。
否则,一个 std :: map< MyEnum,char const *>
将会很好地工作。 (没有意义的将字符串文字复制到地图中的std :: string)
对于额外的语法糖,下面是如何编写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&)
。 (从运算符()
返回 *
允许链接
operator()
,如运算符<
在 std :: ostream
s)
模板< typename T> struct map_init_helper
{
T&数据;
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;
}
};
模板< typename T> map_init_helper< T> map_init(T& item)
{
return map_init_helper< T>(item);
}
由于函数和助手类是模板化的,因此可以将它们用于任何地图,或地图样结构。即它也可以添加条目到 std :: unordered_map
如果您不喜欢编写这些帮助器,boost :: assign将提供相同的功能开箱即用。
I have a bunch of enum types in some library header files that I'm using, and I want to have a way of converting enum values to user strings - and vice-versa.
RTTI won't do it for me, because the 'user strings' need to be a bit more readable than the enumerations.
A brute force solution would be a bunch of functions like this, but I feel that's a bit too C-like.
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");
}
}
I have a gut feeling that there's an elegant solution using templates, but I can't quite get my head round it yet.
UPDATE: Thanks for suggestions - I should have made clear that the enums are defined in a third-party library header, so I don't want to have to change the definition of them.
My gut feeling now is to avoid templates and do something like this:
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);
If you want the enum names themselves as strings, see this post.
Otherwise, a std::map<MyEnum, char const*>
will work nicely. (No point in copying your string literals to std::strings in the map)
For extra syntactic sugar, here's how to write a map_init class. The goal is to allow
std::map<MyEnum, const char*> MyMap;
map_init(MyMap)
(eValue1, "A")
(eValue2, "B")
(eValue3, "C")
;
The function template <typename T> map_init(T&)
returns a map_init_helper<T>
.
map_init_helper<T>
stores a T&, and defines the trivial map_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Returning *this
from operator()
allows the chaining of operator()
, like operator<<
on std::ostream
s)
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);
}
Since the function and helper class are templated, you can use them for any map, or map-like structure. I.e. it can also add entries to std::unordered_map
If you don't like writing these helpers, boost::assign offers the same functionality out of the box.
这篇关于如何轻松地将c ++枚举映射到字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!