【发布时间】:2012-02-05 15:45:54
【问题描述】:
如何在 C++ 中使用“ToString()”枚举?
在 Java 和 C# 中,我只会调用 ToString。
enum Colours
{
Red =0,
Green=1,
Blue=2
};
我需要创建一个字符串,如:“无效颜色'”+颜色+“'选择。”
【问题讨论】:
标签: c++
如何在 C++ 中使用“ToString()”枚举?
在 Java 和 C# 中,我只会调用 ToString。
enum Colours
{
Red =0,
Green=1,
Blue=2
};
我需要创建一个字符串,如:“无效颜色'”+颜色+“'选择。”
【问题讨论】:
标签: c++
虽然这通常通过开关完成,但我更喜欢数组:
#include <iostream>
namespace foo {
enum Colors { BLUE = 0, RED, GREEN, SIZE_OF_ENUM };
static const char* ColorNames[] = { "blue", "red", "green" };
// statically check that the size of ColorNames fits the number of Colors
static_assert(sizeof(foo::ColorNames)/sizeof(char*) == foo::SIZE_OF_ENUM
, "sizes dont match");
} // foo
int main()
{
std::cout << foo::ColorNames[foo::BLUE] << std::endl;
return 0;
}
显式数组大小有利于生成编译时间 错误应该枚举的大小发生变化并且您忘记添加 合适的字符串。
另外,Boost 保险库中有 Boost.Enum。图书馆 尚未正式发布但相当稳定并提供 你要。不过我不会向新手推荐它。
【讨论】:
const unordered_map。这几乎可以屏蔽维护者可能对枚举做的所有事情,并防止在运行时误用,但有点昂贵。
ColorNames[SIZE_OF_ENUM] 替换为ColorNames[] 并添加static_assert(sizeof(foo::ColorNames)/sizeof(char*) == foo::SIZE_OF_ENUM, "sizes dont match");
用宏来个小魔术怎么样:
#include <iostream>
#include <string>
#include <vector>
// http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
std::vector<std::string> split(const std::string &text, char sep) {
std::vector<std::string> tokens;
int start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
tokens.push_back(text.substr(start, end - start));
start = end + 1;
}
tokens.push_back(text.substr(start));
return tokens;
}
#define ENUM(name, ...)\
enum name \
{\
__VA_ARGS__\
};\
std::vector<std::string> name##Map = split(#__VA_ARGS__, ',');\
std::string toString(const name v) { return name##Map.at(v);}
ENUM(Color, Red,Green,Blue)
int main(int c, char**v)
{
std::cout << toString(Red) << toString(Blue);
return 0;//a.exec();
}
是的,我知道这很丑,你最好不要这样做
【讨论】:
这本来就是不可能的。
C++ 枚举只是一组带有编译时名称的数字。
在运行时,它们与普通数字无法区分。
您需要编写一个返回字符串的switch 语句。
【讨论】:
Enum 类的源代码中看到反射。
我真的很喜欢@Lol4t0 的宏观方法。
我对其进行了扩展,使其也能够从字符串转换枚举:
#include <iostream>
#include <string>
#include <vector>
// http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
std::vector<std::string> split(const std::string &text, char sep) {
std::vector<std::string> tokens;
int start = 0, end = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
tokens.push_back(text.substr(start, end - start));
start = end + 1;
}
tokens.push_back(text.substr(start));
return tokens;
}
#define ENUM(name, ...)\
enum name\
{\
__VA_ARGS__\
};\
static const int name##Size = (sizeof((int[]){__VA_ARGS__})/sizeof(int));\
static const vector<string> name##ToStringMap = split(#__VA_ARGS__, ',');\
const string name##ToString(const name value)\
{\
return name##ToStringMap.at(value);\
};\
map<string, name> name##ToFromStringMap(...)\
{\
map<string, name> m;\
name args[name##Size] = { __VA_ARGS__ };\
\
int i;\
for(i = 0; i < name##Size; ++i)\
{\
m[name##ToString(args[i])] = args[i];\
}\
return m;\
};\
static map<string, name> name##FromStringMap = name##ToFromStringMap(__VA_ARGS__);\
const name name##FromString(const string value, const name defaultValue)\
{\
if(name##FromStringMap.count(value) == 0)\
{\
return defaultValue;\
}\
return name##FromStringMap[value];\
};
用法:
ENUM(MyEnum, Value1, Value2)
void main()
{
string valueName = MyEnumToString(MyEnum::Value2);
MyEnum value = MyEnumFromString(valueName, MyEnum::Value1);
}
我不是 C++ 专家,所以请告诉我您的想法或如何做得更好。
【讨论】:
enum Color
{
Red =0,
Green=1,
Blue=2
};
std::string ColorMap[] = { "Red", "Green","Blue" };
使用ColorMap[c]获取字符串表示:
std::string msg = "Invalid colour '" + ColorMap[c] + "' selected.";
但是,如果 enum 的值不连续,那么您可以使用std::map 代替:
enum Color
{
Red = 0x1,
Green = 0x2,
Blue = 0x4,
Black = 0x8,
};
//C++11 only, as it uses std::initializer_list
std::map<Color, std::string> ColorMap = {
{Red, "Red"},
{Green, "Green"},
{Blue, "Blue"},
{Black, "Black"}
};
//same as before!
std::string msg = "Invalid colour '" + ColorMap[c] + "' selected.";
【讨论】:
你必须手动完成,即
const char* ToString(Colours co) {
switch(co) {
case Red:
return "Red";
// ...
}
}
查找表也是可能的。我还看到人们使用自定义脚本在其源代码之上生成此类内容。
【讨论】:
正如@FlopCoder 所说:
enum Colours
{
Red =0,
Green=1,
Blue=2
};
char* ColourNames[] = { "Red", "Green", "Blue" };
int colour = Green;
printf( "Invalid colour '%s' selected.", ColourNames[ colour ] );
这当然只有当您的枚举从 0 开始并且是连续的时才有效。
@Nawaz 的方式更 C++ 时尚。
【讨论】:
您可以将名称存储在由enum 值索引的字符串数组中。
enum Colours
{
Red =0,
Green=1,
Blue=2
};
char* names[3] = {"Red", "Green", "Blue"};
然后就可以打印了:"Invalid colour '" + names[colour] + "' selected."
但如果您不按顺序定义enum 值,这种方法可能不是很有用。在那种情况下,这种方法会浪费内存。正如 Alexander Gessler 所提到的,在 enum 值上编写一个带有 switch 的函数会很有用。另一种选择可能是来自 STL 的map。
【讨论】: