C++ 我如何';ToString()';C+中的枚举+;?

C++ 我如何';ToString()';C+中的枚举+;?,c++,C++,在Java和C语言中,我只需要调用ToString enum Colours { Red =0, Green=1, Blue=2 }; 我需要创建一个字符串,如:“无效颜色”“选定颜色+”。这本质上是不可能的 一个C++的枚举只是一组编译时间名称的数字。 在运行时,它们与普通数字无法区分 您需要编写一个返回字符串的switch语句。您可以将名称存储在字符串数组中,由enum值索引 enum Colours { Red =0, Green=1, B

在Java和C语言中,我只需要调用ToString

enum Colours
{
    Red =0,
    Green=1,
    Blue=2
};

我需要创建一个字符串,如:“无效颜色”“选定颜色+”。

这本质上是不可能的

一个C++的枚举只是一组编译时间名称的数字。 在运行时,它们与普通数字无法区分


您需要编写一个返回字符串的
switch
语句。

您可以将名称存储在字符串数组中,由
enum
值索引

enum Colours
{
    Red =0,
    Green=1,
    Blue=2
};

char* names[3] = {"Red", "Green", "Blue"};
然后您可以打印:
“无效颜色”+“已选择名称[颜色]+”。


但是,如果不按顺序定义
enum
值,这种方法可能不会非常有用。在这种情况下,这种方法将浪费内存。正如Alexander Gessler所提到的,用
开关
枚举
值上编写函数会很有用。另一种选择可能是STL中的
映射

您必须手动执行,即

const char* ToString(Colours co) {
     switch(co) {
        case Red:
           return "Red";
        // ...
     }
}
也可以使用查找表。我还见过人们使用自定义脚本在源代码之上生成这样的东西

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.";
枚举颜色
{
红色=0x1,
绿色=0x2,
蓝色=0x4,
黑色=0x8,
};
//仅限C++11,因为它使用std::initializer\u list
std::map ColorMap={
{红色,“红色”},
{绿色,绿色},
{蓝色,蓝色},
{黑色,“黑色”}
};
//和以前一样!
std::string msg=“无效颜色””+ColorMap[c]+“”已选定。“;
正如@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开始并且是连续的时,这才有效。

虽然纳瓦兹的方式更为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;
}
#包括
名称空间foo{
枚举颜色{蓝色=0,红色,绿色,大小为_enum};
静态常量字符*颜色名称[]={“蓝色”、“红色”、“绿色”};
//静态检查ColorNames的大小是否与颜色的数量相匹配
静态\u断言(sizeof(foo::ColorNames)/sizeof(char*)==foo::SIZE\u的\u枚举
,“尺寸不匹配”);
}//富
int main()
{

std::cout用宏实现一点魔法怎么样:

#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();
}
#包括
#包括
#包括
// http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c
标准::向量拆分(常量标准::字符串和文本,字符sep){
std::向量标记;
int start=0,end=0;
while((end=text.find(sep,start))!=std::string::npos){
tokens.push_back(text.substr(start,end-start));
开始=结束+1;
}
tokens.push_back(text.substr(start));
归还代币;
}
#定义枚举(名称,…)\
枚举名\
{\
__瓦乌阿格斯__\
};\
std::vector name##Map=split(###VA_uargs_#,',')\
std::string toString(const name v){return name##Map.at(v)}
枚举(颜色、红色、绿色、蓝色)
int main(int c,字符**v)
{

std::cout我非常喜欢@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];\
    };

<我不是一个C++专家,所以让我知道你的想法或如何做得更好。< /P>它如何工作于C……反射?”CONQUAND QUANT:是的,你可以看到代码< EnUM>代码>类的反射。看看我的大小限制。这使成语有点好。如果忘记添加字符串,它不会产生错误…@ Matth。嗯。是的。构建类似这样的东西的唯一可靠方法可能是宏。我恐怕是这样。我一直认为这也是一种耻辱,我会很感激编译器在一旁构建函数。我发现的一种方法是使用宏,尽管这或多或少是内联函数。另一种方法是使用测试来确保lation对以前的类型有效(至少),然后依赖开发人员来思考:)@MatthieuM。我想真正的解决方案仍然是使用
常量无序_map
。它可以屏蔽维护人员对枚举可能做的几乎所有事情,并在运行时防止误用,但有点昂贵。替换
ColorNames[SIZE_OF_ENUM]
ColorNames[]
并添加
静态断言(sizeof(foo::ColorNames)/sizeof(char*)==foo::SIZE_OF_ENUM,“大小不匹配”)这是非常棒的!我很确定这可以用C++ 11个参数包做得更干净,所以在运行时你根本没有任何工作。C++被认为是消除了宏。我认为,这种方法的最佳解决方案也可以用包含间隙的枚举来使用。例如,红色= 0x01,绿色,蓝色=0x10,黄色。
ENUM(MyEnum, Value1, Value2)

void main()
{
    string valueName = MyEnumToString(MyEnum::Value2);
    MyEnum value = MyEnumFromString(valueName, MyEnum::Value1);
}