https://www.bilibili.com/video/BV1Ur4y1V7Kh?spm_id_from=333.999.0.0&vd_source=3d0c7cbd0c95f2308054440260ab6f64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#pragma once

#include <string>

namespace scienum {

namespace details {

template <class T, T N>
const char *get_enum_name_static() { //关键 根据宏获取函数名字符串
#if defined(_MSC_VER)
return __FUNCSIG__; //return "void __cdecl get_enum_name_static<int>(void)"
#else
return __PRETTY_FUNCTION__; //return "void get_enum_name_static() [with T = int]"
#endif
}

template <bool Cond>
struct my_enable_if {
};

template <>
struct my_enable_if<true> {
typedef void type;
};

template <int Beg, int End, class F> //模板特化 用于结束循环
typename my_enable_if<Beg == End>::type static_for(F const &func) {
}

template <int Beg, int End, class F>
typename my_enable_if<Beg != End>::type static_for(F const &func) {
func.template call<Beg>();
static_for<Beg + 1, End>(func);
}

template <class T>
struct get_enum_name_functor {
int n;
std::string &s;

get_enum_name_functor(int n, std::string &s) : n(n), s(s) {}

template <int I>
void call() const {
if (n == I) s = details::get_enum_name_static<T, (T)I>(); //I需要编译期能确定的,这里不能通过call(int I)调用,虽然前面调用的Beg是编译期确定的值。
//这里可以使用std::integral_constant<Beg> 其中里面有个value成员是constexpr的
}
};

}

template <class T, T Beg, T End>
std::string get_enum_name(T n) {
std::string s;
details::static_for<Beg, End + 1>(details::get_enum_name_functor<T>(n, s));
if (s.empty())
return "";
#if defined(_MSC_VER)//下面是裁剪字符串了
size_t pos = s.find(',');
pos += 1;
size_t pos2 = s.find('>', pos);
#else
size_t pos = s.find("N = ");
pos += 4;
size_t pos2 = s.find_first_of(";]", pos);
#endif
s = s.substr(pos, pos2 - pos);
size_t pos3 = s.find("::");
if (pos3 != s.npos)
s = s.substr(pos3 + 2);
return s;
}

template <class T>
std::string get_enum_name(T n) {
return get_enum_name<T, (T)0, (T)256>(n);
}

template <class T, T Beg, T End>
T enum_from_name(std::string const &s) {
for (int i = (int)Beg; i < (int)End; i++) {
if (s == get_enum_name((T)i)) {
return (T)i;
}
}
throw;
}

template <class T>
T enum_from_name(std::string const &s) {
return enum_from_name<T, (T)0, (T)256>(s);
}

}