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

标签 c++ c++11 dictionary enums

我需要创建一个 intenum 值的映射。 (我正在读取文件中的整数,需要在运行时根据它们创建一个 enum。)我可以手动创建一个 map ,如下面的示例所示。然而,这是一个微不足道的例子,我的枚举中只有几个(即七个)元素。

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

我希望自动创建我称为 WeekMap 的 map ,这样我就可以向它传递一个整数并获取 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;
}

最佳答案

您不需要 map 。您的 WhatDay 函数可以这样写:

Days WhatDay (unsigned int D) {
    return static_cast<Days>(D);
}

这基本上是免费的(在效率方面。)但是你可能想确保你的 enum 的底层类型确实是一个 int(或者更小或更大的东西;) 再次出于效率原因和可靠性原因:

enum class Days : int {
    ...
};

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

更新 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.

这是我所拥有的关于每个条目的所有信息,以一般形式(即传递给一个未知的类似thing的函数,称为action

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

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

作为进一步的示例,您可以定义所需的映射,以及另一个将 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

(此示例代码为 available on Ideone 。)

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

这是一项非常强大的技术,可能(也可能不会)对您有用。


UPDATE 1(针对更新后的问题):

不,在 C++ 中无法在运行时创建 enum。当没有更多编译器时(如果这确实是您所追求的),您不能在运行时为编译器创建新类型。

但是,由于 C++ 中的 enum 完全不提供运行时设施,因此在运行时,具有相同底层类型的两个 enum 之间没有区别。或者实际上,在 enumint 之间(如果 int 是该 enum 的基础类型。)

因此,我建议:您定义一个 enum,并像以前一样编写WhatDay 函数。一切都会好起来的! (因为您不需要边界检查。)

具体来说,我的建议是:

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

Days WhatDay (unsigned int D) {
    return static_cast<Days>(D);
}

之所以可行,是因为在我看来您在编译时不知道您的枚举值,并且编译器一点也不关心枚举 在运行时。没有人这样做!

如果您想要错误和范围检查,我建议您使用“区间树”(read up on it on Wikipedia。)当您阅读枚举时填充这棵树在运行时从您的文件中获取值(这是您填充的唯一数据结构),然后对照它检查传递给 WhatDay 函数的每个值。

关于C++11 自动创建整数到枚举值映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24827493/

相关文章:

c++ - 字符串在 RC4 解密过程中被截断

c++ - 操纵输入文件流

c++ - 多数元素-数组的一部分

c++ - C++11 中的静态局部变量?

python - 引用二维列表中每个列表的第 i 个元素

c++ - 如何部署将在特定时间或使用次数后过期的 .NET 应用程序

c++ - Valgrind 在不终止程序的情况下检测内存泄漏

c++ - typename参数包和auto参数包的区别?

javascript - 谷歌地图标记聚类不适用于缩小

c# - LINQ 等效查询