枚举的字符串在C ++ 11

问题描述 投票:27回答:6

我知道这has been asked before不止一次对SO,但我无法找到一个明确的问题寻找一个当前解决这个问题与C ++ 11,所以在这里,我们再次去..

我们可以方便地获得与C ++ 11枚举的字符串值?

即有没有(现在)在C ++ 11的任何内置功能,使我们能够获得枚举类型的字符串表示形式

typedef enum {Linux, Apple, Windows} OS_type; 
OS_type myOS = Linux;

cout << myOS

这将打印到控制台Linux

c++11 enums
6个回答
16
投票

长期存在的和不必要的缺乏在C ++(和C)的通用枚举到字符串特征的是一个痛苦。 C ++ 11,因为我知道都不会对C ++ 14并没有解决这个问题,而据。

个人而言,我会使用代码生成解决这个问题。 C预处理器是一个办法 - 你可以看到在这里评论该链接的其他一些答案。但实际上我更愿意只写我自己的代码生成专门为枚举。如需要它可以很容易生成to_string (char*)from_stringostream operator<<istream operator<<is_valid,和更多的方法。这种方法可以非常灵活和强大,但它绝对强制执行的一致性在许多枚举的一个项目,这样会导致没有运行时的成本。

不要使用它Python的出色的“灰鲭鲨”包,或在Lua如果你为轻量,或CPP,如果你是对的依赖,或CMake的自己生成代码设施。很多方面,但是这一切都归结为同样的事情:你需要自己生成的代码 - C ++不会为你做这个(很遗憾)。


5
投票

在我看来,最易于维护的办法是写一个辅助函数:

const char* get_name(OS_type os) {
  switch (os) {
  case Linux: return "Linux";
  case Apple: return "Apple";
  case Windows: return "Windows";
  }
}

这是不是实现了“默认”的情况下是一个好主意,因为这样做将确保你得到一个编译器警告,如果你忘了执行的情况下(与合适的编译器和编译器设置)。


4
投票

我喜欢使用C预处理器,这是我第一次在这里看到一个黑客:http://blogs.msdn.com/b/vcblog/archive/2008/04/30/enums-macros-unicode-and-token-pasting.aspx

它使用标记粘贴运算符#。

// This code defines the enumerated values:

#define MY_ENUM(x) x,
enum Fruit_Type {
MY_ENUM(Banana)
MY_ENUM(Apple)
MY_ENUM(Orange)
};
#undef MY_ENUM

// and this code defines an array of string literals for them:

#define MY_ENUM(x) #x,
        const char* const fruit_name[] = {
MY_ENUM(Banana)
MY_ENUM(Apple)
MY_ENUM(Orange)
        };
#undef MY_ENUM

// Finally, here is some client code:

std::cout << fruit_name[Banana] << " is enum #" << Banana << "\n";

// In practice, those three "MY_ENUM" macro calls will be inside an #include file.

坦率地说,它的丑陋和。但你最终在一个包含文件中只出现一次输入你的枚举,这是更易于维护。

顺便说一句,这MSDN博客链接(见上文)用户做出了一招,使整个事情更漂亮,并且避免的#includes评论:

#define Fruits(FOO) \
FOO(Apple) \
FOO(Banana) \
FOO(Orange)

#define DO_DESCRIPTION(e)  #e,
#define DO_ENUM(e)  e,

char* FruitDescription[] = {
Fruits(DO_DESCRIPTION)
};

enum Fruit_Type {
Fruits(DO_ENUM)
};

// Client code:

std::cout << FruitDescription[Banana] << " is enum #" << Banana << "\n";

(我只注意到0x17de的回答也使用标记粘贴操作)


3
投票

下面是使用命名空间和结构一个简单的例子。一类是每个枚举项创建。在这个例子中我选择int作为ID的类型。

#include <iostream>
using namespace std;

#define ENUMITEM(Id, Name) \
struct Name {\
    static constexpr const int id = Id;\
    static constexpr const char* name = #Name;\
};

namespace Food {
ENUMITEM(1, Banana)
ENUMITEM(2, Apple)
ENUMITEM(3, Orange)
}

int main() {
    cout << Food::Orange::id << ":" << Food::Orange::name << endl;
    return 0;
}

输出:

3:Orange

== ==更新

使用:

#define STARTENUM() constexpr const int enumStart = __LINE__;
#define ENUMITEM(Name) \
struct Name {\
    static constexpr const int id = __LINE__ - enumStart - 1;\
    static constexpr const char* name = #Name;\
};

并使用一次ENUMITEM的第一次使用就不再被需要的ID之前。

namespace Food {
STARTENUM()
ENUMITEM(Banana)
ENUMITEM(Apple)
ENUMITEM(Orange)
}

变量enumStart只有通过命名空间访问 - 所以仍然可以使用多个枚举。


0
投票

您可以使用宏来解决这个问题:

#define MAKE_ENUM(name, ...) enum class name { __VA_ARGS__}; \
static std::vector<std::string> Enum_##name##_init(){\
    const std::string content = #__VA_ARGS__; \
    std::vector<std::string> str;\
    size_t len = content.length();\
    std::ostringstream temp;\
    for(size_t i = 0; i < len; i ++) {\
    if(isspace(content[i])) continue;\
    else if(content[i] == ',') {\
    str.push_back(temp.str());\
    temp.str(std::string());}\
    else temp<< content[i];}\
    str.push_back(temp.str());\
    return str;}\
static const std::vector<std::string> Enum_##name##_str_vec = Enum_##name##_init();\
static std::string to_string(name val){\
    return Enum_##name##_str_vec[static_cast<size_t>(val)];\
}\
static std::string print_all_##name##_enum(){\
    int count = 0;\
    std::string ans;\
    for(auto& item:Enum_##name##_str_vec)\
    ans += std::to_string(count++) + ':' + item + '\n';\
    return ans;\
}

由于静态变量只能被初始化一次,所以枚举_ ##名## _ str_vec将使用枚举_ ##名## _ init()函数本身首先初始化。

示例代码如下:

MAKE_ENUM(Analysis_Time_Type,
                  UNKNOWN,
                  REAL_TIME, 
                  CLOSSING_TIME 
);

然后你可以用下面的句子来打印一个枚举值:

to_string(Analysis_Time_Type::UNKNOWN)

并使用下面的句子打印所有枚举的字符串:

print_all_Analysis_Time_Type_enum()

0
投票

如前所述,有做这种没有标准的方式。但有一点预处理魔术(类似于AlejoHausner的第二个贡献)和一些模板魔术,它可以非常优雅。

包括这一次代码:

#include <string>
#include <algorithm>

#define ENUM_VALS( name ) name,
#define ENUM_STRINGS( name ) # name,

/** Template function to return the enum value for a given string
*  Note: assumes enums are all upper or all lowercase,
*        that they are contiguous/default-ordered,
*        and that the first value is the default
*  @tparam ENUM     type of the enum to retrieve
*  @tparam ENUMSIZE number of elements in the enum (implicit; need not be passed in)
*  @param valStr   string version of enum value to convert; may be any capitalization (capitalization may be modified)
*  @param enumStrs array of strings corresponding to enum values, assumed to all be in lower/upper case depending upon
*  enumsUpper
*  @param enumsUpper true if the enum values are in all uppercase, false if in all lowercase (mixed case not supported)
*  @return enum value corresponding to valStr, or the first enum value if not found
*/
template <typename ENUM, size_t ENUMSIZE>
static inline ENUM fromString(std::string &valStr, const char *(&enumStrs)[ENUMSIZE], bool enumsUpper = true) {
    ENUM e = static_cast< ENUM >(0); // by default, first value
    // convert valStr to lower/upper-case
    std::transform(valStr.begin(), valStr.end(), valStr.begin(), enumsUpper ? ::toupper : ::tolower);
    for (size_t i = 0; i< ENUMSIZE; i++) {
        if (valStr == std::string(enumStrs[i])) {
            e = static_cast< ENUM >(i);
            break;
        }
    }
    return e;
}

然后定义每个枚举,如下所示:

//! Define ColorType enum with array for converting to/from strings
#define ColorTypes(ENUM) \
    ENUM(BLACK) \
    ENUM(RED) \
    ENUM(GREEN) \
    ENUM(BLUE)
enum ColorType {
    ColorTypes(ENUM_VALS)
};
static const char* colorTypeNames[] = {
    ColorTypes(ENUM_STRINGS)
};

你只需要一次枚举枚举值和代码来定义它是相当紧凑和直观。

价值必然在默认的方式进行编号(即0,1,2,...)。 fromString()的代码假定枚举值是要么全部大写或小写(从字符串转换),默认值是第一个,当然你可以改变这些东西是如何处理的。

这里是你如何得到字符串值:

ColorType c = ColorType::BLUE;   
std::cout << colorTypeNames[c]; // BLUE

这里是你如何设置一个字符串值,枚举:

ColorType c2 = fromString<ColorType>("Green", colorTypeNames); // == ColorType::GREEN
© www.soinside.com 2019 - 2024. All rights reserved.