C++ 11自动创建整数到枚举值映射

jlc*_*lin 1 c++ enums map c++11

我需要创建地图intenum值.(我正在读取文件中的整数,需要enum在运行时从它们创建一个.)我可以手动创建一个地图,如下例所示.然而,这是一个简单的例子,我的枚举只有少数(即七个)元素.

我的现实问题有几百个元素enum class.我不需要打印我的真实世界的名字enum,但我需要得到enum给定整数的值.我已经enum class创建了并且想要一种自动方式来创建从整数到枚举值的映射.

我正在寻找自动创建我调用的地图,WeekMap所以我可以传递一个整数并获取enum值.这甚至可能吗?请告诉我它是.

// Compile with:
//      clang++ -std=c++11 -stdlib=libc++ enum_test.cpp -o enum_test
// 

#include <iostream>
#include <string>
#include <map>

enum class Days {
    SUNDAY    = 1,
    MONDAY    = 2,
    TUESDAY   = 3,
    WEDNESDAY = 4,
    THURSDAY  = 5,
    FRIDAY    = 6,
    SATURDAY  = 7
};

std::ostream& operator<< (std::ostream& os, const Days& day){
    os << static_cast<std::underlying_type<Days>::type>(day);
    return os;
}

std::map<unsigned int, Days> WeekMap{
    {1, Days::SUNDAY},
    {2, Days::MONDAY},
    {3, Days::TUESDAY},
    {4, Days::WEDNESDAY},
    {5, Days::THURSDAY},
    {6, Days::FRIDAY},
    {7, Days::SATURDAY},
};

// Return the day of the week
Days WhatDay(unsigned int D){
    return WeekMap[D];
}

int main() {

    std::cout << "\nLearning how to 'cout' enums." << std::endl;

    Days myDay = Days::MONDAY;

    std::cout << "\nMonday is day: " << myDay << "\n" << std::endl;

    for (int i=1; i<8; i++){
        std::cout << "Day number: " << i << " is " << WhatDay(i) << std::endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

yzt*_*yzt 8

你不需要map.你的WhatDay功能可以像这样写:

Days WhatDay (unsigned int D) {
    return static_cast<Days>(D);
}
Run Code Online (Sandbox Code Playgroud)

这基本上是免费的(在效率方面.)但是出于效率原因和可靠性原因,您可能希望再次确保您enum的基础类型确实是int(或更小或更大的东西):

enum class Days : int {
    ...
};
Run Code Online (Sandbox Code Playgroud)

但是,使用此方法将丢失的是错误检查.您将无法检查整数是否是有效的枚举值; 特别是如果你的枚举值不连续.

更新2(更新1在下面!)为了有点自动创建这种enum以及许多其他代码,您可以使用以下技术:

您首先以一般格式记下您感兴趣的数据:

#define EXPAND_VALUES(action)           \
    action (1, SUNDAY,    "Sunday")     \
    action (2, MONDAY,    "Monday")     \
    action (3, TUESDAY,   "Tuesday")    \
    action (4, WEDNESDAY, "Wednesday")  \
    action (5, THURSDAY,  "Thursday")   \
    action (6, FRIDAY,    "Friday")     \
    action (7, SATURDAY,  "Saturday")
    // Note the lack of a separator after the entries; this is more flexible.
Run Code Online (Sandbox Code Playgroud)

这是我的所有关于每个条目的信息,在一般的形式(即通过一个未知函数样的东西action.

现在,为了定义枚举,我们可以简单地说:

#define DEF_ENUM(i,v,s) v = i,
enum class Days : int { EXPAND_VALUES(DEF_ENUM) };
#undef DEF_ENUM
Run Code Online (Sandbox Code Playgroud)

作为进一步的示例,您可以定义所需的映射,以及将enum值映射到字符串的另一个表,如下所示:

#define DEF_MAP(i,v,s)  {i, Days::v},
std::map<int, Days> WeekMap { EXPAND_VALUES(DEF_MAP) };
#undef DEF_MAP

#define DEF_STR_MAP(i,v,s)  {Days::v, s},
std::map<Days, std::string> WeekStrMap { EXPAND_VALUES(DEF_STR_MAP) };
#undef DEF_STR_MAP
Run Code Online (Sandbox Code Playgroud)

(此示例代码在Ideone上可用.)

请注意这项技术对您的作用.如果没有在数据定义的任何冗余,获得尽可能多的数据结构的定义,数组的初始化,switch语句来的情况下,if- else if- else你要的是数据结构等.所有这些都是在编译时(或之前)完成的,没有任何麻烦.

这是一种非常强大的技术,可能(或可能不)对您有用.


更新1(回应更新的问题):

不,不可能enum在C++中创建运行时.当没有更多的编译器时,你不能在运行时为编译器创建一个新类型(如果你真的是这样的话.)

但是,由于enumC++中的s绝对没有提供运行时功能,因此,在运行时,enum具有相同底层类型的两个s 之间没有区别.或者实际上,在an enum和an 之间int(如果int是底层类型enum).

因此,我提出这个:你定义一个 enum,并WhatDay像以前一样完全写函数.一切都会好的!(因为你不需要边界检查.)

具体来说,我建议的是:

enum class Days : int { /*really, really empty!*/ };

Days WhatDay (unsigned int D) {
    return static_cast<Days>(D);
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为在我看来,您在编译时不知道您的枚举值,并且编译器不关心enum运行时的值.没人做到!

如果你想要错误和范围检查,我建议你使用一个" 间隔树 "(在维基百科上阅读它.)当你读你填写此树enum在运行时从文件中的值(这是唯一的数据结构你populate,)然后检查传递给WhatDay函数的每个值.