我声明了一个枚举类型如下,
enum WeekEnum
{
Mon = 0;
Tue = 1;
Wed = 2;
Thu = 3;
Fri = 4;
Sat = 5;
Sun = 6;
};
当我已经有项目值"0,1"时,如何获取项目名称 "Mon,Tue等"?
我已经有了这样的一个函数:
Log(今天是 "2",享受一下!);
现在我想要以下输出:
今天是 星期三,享受一下
你无法直接这样做,在C++中enum
与Java的枚举不同。
通常的方法是创建一个std::map<WeekEnum,std::string>
。
std::map<WeekEnum,std::string> m;
m[Mon] = "Monday";
//...
m[Sun] = "Sunday";
m[Mon]
视为m[1]
,这通常只需要单个操作码。你可能是在考虑按值而不是按索引在数组中查找的情况。 - Mooing Duck这里有另一个使用X Macro定义枚举的巧妙技巧:
#include <iostream>
#define WEEK_DAYS \
X(MON, "Monday", true) \
X(TUE, "Tuesday", true) \
X(WED, "Wednesday", true) \
X(THU, "Thursday", true) \
X(FRI, "Friday", true) \
X(SAT, "Saturday", false) \
X(SUN, "Sunday", false)
#define X(day, name, workday) day,
enum WeekDay : size_t
{
WEEK_DAYS
};
#undef X
#define X(day, name, workday) name,
char const *weekday_name[] =
{
WEEK_DAYS
};
#undef X
#define X(day, name, workday) workday,
bool weekday_workday[]
{
WEEK_DAYS
};
#undef X
int main()
{
std::cout << "Enum value: " << WeekDay::THU << std::endl;
std::cout << "Name string: " << weekday_name[WeekDay::THU] << std::endl;
std::cout << std::boolalpha << "Work day: " << weekday_workday[WeekDay::THU] << std::endl;
WeekDay wd = SUN;
std::cout << "Enum value: " << wd << std::endl;
std::cout << "Name string: " << weekday_name[wd] << std::endl;
std::cout << std::boolalpha << "Work day: " << weekday_workday[wd] << std::endl;
return 0;
}
演示链接:https://ideone.com/bPAVTM
输出结果:
Enum value: 3
Name string: Thursday
Work day: true
Enum value: 6
Name string: Sunday
Work day: false
enum class WeekDay { WEEK_DAYS ...
。 - Matthieu不,你无法从C++中的数值中获取"名称",因为所有符号都在编译期间被丢弃。
你可能需要使用这种方式:X 宏
__FUNCTION__
、__PRETTY_FUNCTION__
等内容,为什么 __ENUM_NAME__(x)
不存在还没有解释。编译器的开发者可以为枚举类型提供类似的解决方案。Rust 中有类似 #[derive(Debug)]
或 #[derive(Display)]
的东西。Haskell 中有 deriving Show
这样的编译器好处,也是一样的作用。 - BitTicklerstd::ostream& operator<<(std::ostream& lhs, WeekEnum e) {
switch(e) {
case Monday: lhs << "Monday"; break;
.. etc
}
return lhs;
}
const char * Week[] = { "", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; // The blank string at the beginning is so that Sunday is 1 instead of 0.
cout << "Today is " << Week[2] << ", enjoy!"; // Or whatever you'de like to do with it.
On GCC it may look like this:
const char* WeekEnumNames [] = {
[Mon] = "Mon",
[Tue] = "Tue",
[Wed] = "Wed",
[Thu] = "Thu",
[Fri] = "Fri",
[Sat] = "Sat",
[Sun] = "Sun",
};
当我已经有“0, 1等”这样的项目值时,如何获取项目名称“Mon,Tue等”?
在一些旧的C代码中(相当久以前),我找到了类似于以下代码:
std::string weekEnumToStr(int n)
{
std::string s("unknown");
switch (n)
{
case 0: { s = "Mon"; } break;
case 1: { s = "Tue"; } break;
case 2: { s = "Wed"; } break;
case 3: { s = "Thu"; } break;
case 4: { s = "Fri"; } break;
case 5: { s = "Sat"; } break;
case 6: { s = "Sun"; } break;
}
return s;
}
可能不是最好的解决方案,但这个方案做得很好。
枚举名称是懒加载的,所以在第一次调用 to_string
后,它将被加载并保留在内存中。
from_string
方法没有实现,因为这里没有要求,但可以通过调用 get_enum_names
,在向量中搜索名称,并将其位置强制转换为枚举类型来轻松实现。
请在 cpp 文件中添加 get_enum_names
的定义(只需在头文件中声明即可)。
它应该能够在 C++ >= 11 中正常工作
已在 gcc 和 MSVC 中测试过
实现:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_map>
// Add the definition of this method into a cpp file. (only the declaration in the header)
const std::vector<std::string>& get_enum_names(const std::string& en_key, const std::string& en_str)
{
static std::unordered_map<std::string, std::vector<std::string>> en_names_map;
const auto it = en_names_map.find(en_key);
if (it != en_names_map.end())
return it->second;
constexpr auto delim(',');
std::vector<std::string> en_names;
std::size_t start{};
auto end = en_str.find(delim);
while (end != std::string::npos)
{
while (en_str[start] == ' ')
++start;
en_names.push_back(en_str.substr(start, end - start));
start = end + 1;
end = en_str.find(delim, start);
}
while (en_str[start] == ' ')
++start;
en_names.push_back(en_str.substr(start));
return en_names_map.emplace(en_key, std::move(en_names)).first->second;
}
#define DECLARE_ENUM(ENUM_NAME, ...) \
enum class ENUM_NAME{ __VA_ARGS__ }; \
inline std::string to_string(ENUM_NAME en) \
{ \
const auto& names = get_enum_names(#ENUM_NAME #__VA_ARGS__, #__VA_ARGS__); \
return names[static_cast<std::size_t>(en)]; \
}
用法:
DECLARE_ENUM(WeekEnum, Mon, Tue, Wed, Thu, Fri, Sat, Sun);
int main()
{
WeekEnum weekDay = WeekEnum::Wed;
std::cout << to_string(weekDay) << std::endl; // prints Wed
std::cout << to_string(WeekEnum::Sat) << std::endl; // prints Sat
return 0;
}
我使用了一种类似于@RolandXu指向的X宏技术,取得了极大的成功。我们还广泛使用了字符串化运算符。这种技术可以缓解在应用程序域中,项目既以字符串形式出现,又以数字标记形式出现时所带来的维护噩梦。
当可用机器可读文档时,该技术特别方便,因为宏X(...)行可以自动生成。新文档将立即导致一致的程序更新,涵盖字符串、枚举和在两个方向之间转换它们的字典(我们正在处理PCL6标记)。
虽然预处理器代码看起来相当丑陋,但所有这些技术细节都可以隐藏在头文件中,而这些文件永远不需要再次修改,源文件也是如此。一切都是类型安全的。唯一变化的是包含所有X(...)行的文本文件,这可能是自动生成的。
如果您知道实际枚举标签与其值的相关性,可以使用容器和C++17的std::string_view
来快速访问值及其字符串表示,并自己跟踪。 [
]
运算符。在创建时,std::string_view
只分配内存。 如果您希望它们在运行时可用于更多的性能节省,则还可以使用static constexpr
指定它们。这个小控制台应用程序应该相当快。
#include <iostream>
#include <string_view>
#include <tuple>
int main() {
enum class Weekdays { //default behavior starts at 0 and iterates by 1 per entry
Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};
static constexpr std::string_view Monday = "Monday";
static constexpr std::string_view Tuesday = "Tuesday";
static constexpr std::string_view Wednesday = "Wednesday";
static constexpr std::string_view Thursday = "Thursday";
static constexpr std::string_view Friday = "Friday";
static constexpr std::string_view Saturday = "Saturday";
static constexpr std::string_view Sunday = "Sunday";
static constexpr std::string_view opener = "enum[";
static constexpr std::string_view closer = "] is ";
static constexpr std::string_view semi = ":";
std::pair<Weekdays, std::string_view> Weekdays_List[] = {
std::make_pair(Weekdays::Monday, Monday),
std::make_pair(Weekdays::Tuesday, Tuesday),
std::make_pair(Weekdays::Wednesday, Wednesday),
std::make_pair(Weekdays::Thursday, Thursday),
std::make_pair(Weekdays::Friday, Friday),
std::make_pair(Weekdays::Saturday, Saturday),
std::make_pair(Weekdays::Sunday, Sunday)
};
for (int i=0;i<sizeof(Weekdays_List)/sizeof(Weekdays_List[0]);i++) {
std::cout<<opener<<i<<closer<<Weekdays_List[(int)i].second<<semi\
<<(int)Weekdays_List[(int)i].first<<std::endl;
}
return 0;
}
输出:
enum[0] is Monday:0
enum[1] is Tuesday:1
enum[2] is Wednesday:2
enum[3] is Thursday:3
enum[4] is Friday:4
enum[5] is Saturday:5
enum[6] is Sunday:6