我如何 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:23:45  来源:igfitidea点击:

How do i ToString() an enum in c++?

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 switchstatement 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::mapinstead 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 enumvalues.

您可以将名称存储在由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 enumvalues sequentially. In that case this approach will waste memory. Writing a function with a switchover the enumvalue would be useful, as Alexander Gessler has mentioned. Another alternative may be the mapfrom STL.

但是如果您不enum按顺序定义值,这种方法可能不是很有用。在这种情况下,这种方法会浪费内存。有写一个函数switchenum值将是有益的,因为亚历山大·格斯勒提及。另一种选择可能是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++ 风格