我如何 ToString() 在 C++ 中枚举?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9150538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do i ToString() an enum in c++?
提问by CodingHero
How do i ToString() an enum in c++? In Java and C# I would just call ToString.
我如何 ToString() 在 C++ 中枚举?在 Java 和 C# 中,我只会调用 ToString。
enum Colours
{
Red =0,
Green=1,
Blue=2
};
I need to create a string like: "Invalid colour '" + colour + "' selected."
我需要创建一个字符串,如:“无效颜色'”+颜色+“'已选择。”
回答by pmr
While this is commonly done through switches, I prefer arrays:
虽然这通常是通过开关完成的,但我更喜欢数组:
#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;
}
The explicit array size has the benefit of generating a compile time error should the size of the enum change and you forget to add the appropriate string.
如果枚举的大小发生变化并且您忘记添加适当的字符串,则显式数组大小的好处是会生成编译时错误。
Alternatively, there is Boost.Enum in the Boost vault. The library hasn't been officially released but is quite stable and provides what you want. I wouldn't recommend it to a novice though.
或者,Boost 保险库中有 Boost.Enum。该库尚未正式发布,但非常稳定并提供您想要的。不过我不会推荐给新手。
回答by Lol4t0
How about a little magic with macros:
用宏来点魔法怎么样:
#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();
}
Yes, I understand that this is ugly and you'd better not do do such things
是的,我知道这很丑陋,你最好不要做这样的事情
回答by SLaks
That's inherently impossible.
这本质上是不可能的。
A C++ enum is just a set of numbers with compile-time names.
At runtime, they are indistinguishable from ordinary numbers.
C++ 枚举只是一组带有编译时名称的数字。
在运行时,它们与普通数字没有区别。
You need to write a switch
statement that returns a string.
您需要编写一个switch
返回字符串的语句。
回答by me.
I really like the macro approach of @Lol4t0.
我真的很喜欢@Lol4t0 的宏方法。
I extended it to be able to convert an enum from a string too:
我将它扩展为也能够从字符串转换枚举:
#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];\
};
Usage:
用法:
ENUM(MyEnum, Value1, Value2)
void main()
{
string valueName = MyEnumToString(MyEnum::Value2);
MyEnum value = MyEnumFromString(valueName, MyEnum::Value1);
}
I am not a C++ expert, so let me know what you think or how to do better.
我不是 C++ 专家,所以让我知道您的想法或如何做得更好。
回答by Nawaz
enum Color
{
Red =0,
Green=1,
Blue=2
};
std::string ColorMap[] = { "Red", "Green","Blue" };
Use ColorMap[c]
to get the string representation:
使用ColorMap[c]
得到的字符串表示:
std::string msg = "Invalid colour '" + ColorMap[c] + "' selected.";
However, if the values of enum are not continuous, then you can use std::map
instead as:
但是,如果 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.";
回答by Alexander Gessler
You have to do it manually, i.e.
你必须手动完成,即
const char* ToString(Colours co) {
switch(co) {
case Red:
return "Red";
// ...
}
}
A lookup table would also be possible. I've also seen people using custom scripts to generate such stuff on top of their source code.
查找表也是可能的。我还看到人们使用自定义脚本在他们的源代码之上生成这样的东西。
回答by 0605002
You can store the names in an array of strings, indexed by the enum
values.
您可以将名称存储在由enum
值索引的字符串数组中。
enum Colours
{
Red =0,
Green=1,
Blue=2
};
char* names[3] = {"Red", "Green", "Blue"};
Then you can print: "Invalid colour '" + names[colour] + "' selected."
然后你可以打印: "Invalid colour '" + names[colour] + "' selected."
But this approach may not be very useful if you do not define the enum
values sequentially. In that case this approach will waste memory. Writing a function with a switch
over the enum
value would be useful, as Alexander Gessler has mentioned. Another alternative may be the map
from STL.
但是如果您不enum
按顺序定义值,这种方法可能不是很有用。在这种情况下,这种方法会浪费内存。有写一个函数switch
在enum
值将是有益的,因为亚历山大·格斯勒提及。另一种选择可能是map
来自 STL。
回答by Petruza
As @FlopCoder said:
正如@FlopCoder 所说:
enum Colours
{
Red =0,
Green=1,
Blue=2
};
char* ColourNames[] = { "Red", "Green", "Blue" };
int colour = Green;
printf( "Invalid colour '%s' selected.", ColourNames[ colour ] );
This of course will only work if your enum starts at 0 and is continuous.
@Nawaz's way is more C++ stylishthough.
这当然只有在您的枚举从 0 开始并且是连续的时才有效。
不过@Nawaz 的方式更符合C++ 风格。