Rod*_*ddy 113 c++ enums templates
我在一些库头文件中有一堆枚举类型,我正在使用,我想有一种方法将枚举值转换为用户字符串 - 反之亦然.
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");
}
}
Run Code Online (Sandbox Code Playgroud)
我有一种直觉,认为使用模板有一个优雅的解决方案,但我还不能完全理解它.
更新:感谢您的建议 - 我应该明确说明枚举是在第三方库头中定义的,所以我不想更改它们的定义.
我现在的直觉是避免使用模板并执行以下操作:
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);
Run Code Online (Sandbox Code Playgroud)
MSa*_*ers 59
如果你想让enum将自己命名为字符串,请参阅这篇文章.否则,一个std::map<MyEnum, char const*>将很好地工作.(没有必要将字符串文字复制到地图中的std :: strings)
对于额外的语法糖,这里是如何编写map_init类.目标是允许
std::map<MyEnum, const char*> MyMap;
map_init(MyMap)
(eValue1, "A")
(eValue2, "B")
(eValue3, "C")
;
Run Code Online (Sandbox Code Playgroud)
该函数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::ostreamS)
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);
}
Run Code Online (Sandbox Code Playgroud)
由于函数和辅助类是模板化的,因此可以将它们用于任何地图或类似地图的结构.即它也可以添加条目std::unordered_map
如果您不喜欢编写这些帮助程序,boost :: assign提供了相同的功能.
Ala*_*air 31
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;
}
Run Code Online (Sandbox Code Playgroud)
jfs*_*jfs 19
从另一个表单自动生成一个表单.
资源:
enum {
VALUE1, /* value 1 */
VALUE2, /* value 2 */
};
Run Code Online (Sandbox Code Playgroud)
产生:
const char* enum2str[] = {
"value 1", /* VALUE1 */
"value 2", /* VALUE2 */
};
Run Code Online (Sandbox Code Playgroud)
如果枚举值很大,那么生成的表单可以使用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 */
};
Run Code Online (Sandbox Code Playgroud)
产生:
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";
Run Code Online (Sandbox Code Playgroud)
例:
#include <iostream>
int main()
{
std::cout << enum2str<state16>::value << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
小智 11
我记得在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;}
Run Code Online (Sandbox Code Playgroud)
要在代码中使用它,只需执行以下操作:
AWESOME_MAKE_ENUM(Animal,
DOG,
CAT,
HORSE
);
auto dog = Animal::DOG;
std::cout<<dog;
Run Code Online (Sandbox Code Playgroud)
Dav*_*nch 10
我建议混合使用X-macro是最好的解决方案和以下模板功能:
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)
Run Code Online (Sandbox Code Playgroud)
colour.def
X(Red)
X(Green)
X(Blue)
X(Cyan)
X(Yellow)
X(Magenta)
Run Code Online (Sandbox Code Playgroud)
我知道我参加聚会迟到了,但是对于访问此页面的其他人来说,您可以尝试一下,它比那里的所有内容都更容易并且更有意义:
namespace texs {
typedef std::string Type;
Type apple = "apple";
Type wood = "wood";
}
Run Code Online (Sandbox Code Playgroud)
我使用以下复制的解决方案:
#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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
204477 次 |
| 最近记录: |