前言
前段时间接触了 magic_enum 这个开源库,代码量不算太多,是一个但头文件的枚举操作库,关于如何使用还写了一篇总结 《推荐一个C++枚举转字符串的开源项目magic_enum》,当时觉得这个库很棒,但是对于我当前枚举转化字符串的需求还说还是太臃肿了,所以决定改造一下,这不今天过来填坑了。
改造
一开始还没太理解开源库的原理,认为原来的实现限制太大,为了实现后面字符串转枚举,获取所有枚举名等需求,不得不限定一个枚举的范围,这个范围在 magic_enum 这个开源库中是 [-128, 128],所以当我开始改造时打算把这个范围去掉,但是当我真正弄懂它的原理后,才发现这个范围是必须指定的,不然无法在编译期预处理,从而达到枚举值转换成字符串的目的。
认识到这一点以后,我也不再纠结范围的限制,设定了一个 [0, 31]
的常用枚举范围,相比于原来 [-128, 128]
的范围缩小了不少,这样能加快编译的速度,参考这个开源库和一些网络上关于这个库的讲解,我也实现了一个功能单一的简洁的枚举转字符串的函数 Enum2String
,大约70行代码,使用起来还是比较方便的。
1 |
|
函数使用
这个Enum2String
函数使用也非常方便,直接把枚举变量作为参数传进去就可以了:
1 |
|
编译运行后的结果为:
1 | $ g++ enumtest.cpp -std=c++17 && ./a.out |
各函数的作用
前面提到过,我这个库还是参考 magic_enum 这个开源库的源码及网上对它的讲解来实现的,只不过精简了大部分我用不到的内容,仅实现了我想要的枚举转字符串的功能,并且大部分都在编译器求值,仅 Enum2String
函数中遍历的部分只能在运行时才能计算求得,所以效率还算不错,各个模板函数作用明确,下面简单描述下:
1 | template <typename E, E V> |
PrettyName()
函数是利用 __PRETTY_FUNCTION__
这个宏来截取最终我们想要的字符串,如果不做处理,__PRETTY_FUNCTION__
的值会是这样:
constexpr auto PrettyName() [with E = Color; E V = Color::BLUE]
靠近结尾的 Color::BLUE
正是我们想要得到的字符串,所以我们可以按照自己的需要把它截取出来。
1 | template <typename E, E V> |
IsValidEnum()
函数是用于判断一个枚举名字是否有效,如果截取的最终名字为空,则认为此枚举无效。
1 | template <int... Seq> |
MakeIntegerSequence()
用于生成一个范围是 [0, 32)
的整数数列。
1 | template <typename E, int... Seq> |
GetEnumSize()
用于遍历数列范围内的各个整数,找出有效的枚举有多少个。
1 | template <typename E, int... Seq> |
GetAllValidValues()
用于遍历数列范围内各个整数,找出全部有效枚举值,返回包含有效值的数组。
1 | template <typename E, int... Seq> |
GetAllValidNames()
用于遍历数列范围内各个整数,找出全部有效枚举值的名字,返回包含这些名字的数组。
1 | template <typename E> |
Enum2String()
用于从编译期生成的数组中遍历寻找枚举值等于参数的枚举值名字,如果枚举值无效或者超出范围就范围对应的整数字符串。
总结
magic_enum
是个很不错的库,但他相对于我的需求来说显得太大了- 根据自己的需求改造开源库,一方面巩固了知识,另一方面也更适合自己的要求
constexpr
这个东东可以在编译期求值,后面可以多花点时间研究一下
原始财富的积累的真的是太难了,那些趁着各种东风各种红利的人们是幸运的,运气也是人生的一部分,而大部分没有这运气的人们想要积累财富,必然要付出十倍甚至上百倍的努力,这些不可选择也无需抱怨,只要踏踏实实往前走就好了~
2022-8-7 16:19:20