我需要创建int
到enum
值的地图。 (我在文件中读取整数,需要在运行时从它们创建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;
}
答案 0 :(得分:8)
您不需要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.
这是我对每个条目的所有信息,一般形式(即传递给名为action
的未知函数,如 thing 。
现在,为了定义枚举,我们可以简单地说:
#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
构造等。想要那些数据。所有这些都是在编译时(或之前)完成的,没有任何麻烦。
这是一种非常强大的技术,可能(或可能不)对您有用。
更新1 (响应更新的问题):
不,在C ++中无法在运行时创建enum
。当没有更多的编译器时,你不能在运行时为编译器创建一个新类型(如果这真的是你所追求的。)
但是,由于C ++中的enum
完全没有提供运行时功能,因此,在运行时,具有相同基础类型的两个enum
之间没有区别。或者事实上,在enum
和int
之间(如果int
是enum
的基础类型。)
因此,我建议:你定义一个空 enum
,并像以前一样编写WhatDay
函数。一切都会好的! (因为你不需要边界检查。)
具体来说,我提议的是:
enum class Days : int { /*really, really empty!*/ };
Days WhatDay (unsigned int D) {
return static_cast<Days>(D);
}
这是有效的,因为在我看来你在编译时不知道你的枚举值,并且编译器在运行时不关心enum
的值。没人做!
如果您想要错误和范围检查,我建议您使用“间隔树”(read up on it on Wikipedia。)当您阅读enum
值时填充此树在运行时从您的文件中(这是您填充的唯一数据结构),然后检查传递给WhatDay
函数的每个值。