当前位置: 首页 > news >正文

推荐一个C++枚举转字符串的开源项目magic_enum

文章目录

  • 前言
  • magic_enum
    • 简单介绍
    • 具体使用
    • 原理简述
    • 局限性
  • 简化与改进
  • 总结

前言

C++11引入了强类型的枚举类 enum class 用来代替旧风格枚举enum,新引入的 enum class 具有诸多优点:防止命名空间污染,不能隐式的转换为整型,防止不同类型的枚举相互赋值,支持前置声明。当然它也不是只有优点,因为类型不能隐式转换成int,所以在使用或者输出时需要使用 static_cast 进行转换,不过即便使用 static_cast 可以转换后输出,也不便于我们辨识枚举的值,如果想输出枚举定义时的名字就需要使用一些魔法了。

magic_enum

因为C++本身不支持反射,或者说反射能力极弱,所以想反射我们必须自己实现一些东西,比如 UE 引擎就为C++写了一套自己的反射标签,而我们想获得枚举定义时的名字就需要自己记录了,因为编译后的枚举一般都转化成了整数,一个简单粗暴的想法是在定义时为每个枚举值同时指定一个同名字符串,构成map存储下来,不过我们不想每次都自己来做这件事,要是有人能帮忙就好了,这不它来了, magic_enum 就可以帮你实现这个愿望。

简单介绍

magic_enum 是一个单头文件的开源库,使用方便,可以轻松帮你实现打印枚举值定义时名字的需求,另外除了可以实现这个功能,还可以根据字符串生成枚举值,根据整数生成枚举值,获取枚举值数组,获取枚举值和名字对应的数字组等等,简直是一个封装了枚举操作的宝库。

具体使用

直接引用头文件 magic_enum.hpp,然后调用函数 magic_enum::enum_name(enum_xxx) 即可:

#include <iostream>
#include "magic_enum.hpp"

enum class WeekDay
{
    WD_SUNDAY = 0,
    WD_MONDAY,
    WD_TUESDAY,
    WD_WEDNESDAY,
    WD_THURSDAY,
    WD_FRIDAY,
    WD_SATURDAY,
};

int main()
{
    WeekDay day = WeekDay::WD_MONDAY;

    std::cout << "enum value: " << static_cast<std::underlying_type<WeekDay>::type>(day) << "\n";
    std::cout << "enum name:  " << magic_enum::enum_name(day) << "\n";

    return 0;
}

编译运行如下:

$ g++ testenum.cpp -std=c++17 && ./a.out
enum value: 1
enum name:  WD_MONDAY

原理简述

很神奇对不对,其实枚举值转换成字符串这一步,是是利用了函数模板和 __PRETTY_FUNCTION__ 组合使用获得到的,也就是对 __PRETTY_FUNCTION__ 进行截取得到的字符串。

__PRETTY_FUNCTION__ 在预编译阶段会替换成带有参数的函数名,比如 constexpr auto magic_enum::detail::n() [with E = WeekDay; E e = WD_MONDAY] 从中截取出 WD_MONDAY 就可以了。

局限性

为了实现从字符串到枚举值的转换,这个库的内部定义了一个整数范围,默认从-128到128,用于遍历查找字符串对应的枚举值是多少,并且在代码中加了 static_assert 来判断范围,如果超过了这个范围就会报编译错误,这个范围可以通过修改源码中的 MAGIC_ENUM_RANGE_MINMAGIC_ENUM_RANGE_MAX 重新编译来修改,在这个范围之外还有个最大值 std::numeric_limits<std::uint16_t>::max 的限制。

这个最大限制也是可以改的,不过我尝试把 MAGIC_ENUM_RANGE_MAX 改到上限值 32767 之后编译时间明显变成,编译过程变得异常的慢,单个文件编译30秒,所以不建议把这个值调太大。

对比一下不使用 magic_enum 和使用它之后生成的汇编代码,从100多行扩充到1000多行,利用 type_traits 生成了大量的函数:

...
    .type   _ZN10magic_enum6detail7names_vI7WeekDayEE, @gnu_unique_object
    .size   _ZN10magic_enum6detail7names_vI7WeekDayEE, 112
_ZN10magic_enum6detail7names_vI7WeekDayEE:
    .quad   9
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_0EEE
    .quad   9
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_1EEE
    .quad   10
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_2EEE
    .quad   12
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_3EEE
    .quad   11
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_4EEE
    .quad   9
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_5EEE
    .quad   11
    .quad   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_6EEE
    .weak   _ZN10magic_enum6detail11enum_name_vI7WeekDayLS2_0EEE
...

简化与改进

其实我最想要的还是通过枚举值转化转化成字符串名称的功能,可以将这个开源库简化一下,仅保留这个功能,这样也不会有范围限制了,感觉这个库为了实现从字符串到枚举值转换背负了太多,去掉它会很清爽。

总结

  • magic_enum 是一个开源的、单头文件的、枚举操作工具箱
  • magic_enum 可以实现枚举值到字符串、字符串到枚举值、获取所有枚举名等多种操作
  • magic_enum 本身对枚举值有范围限制,默认是 [-128, 128], 可通过 MAGIC_ENUM_RANGE_MINMAGIC_ENUM_RANGE_MAX 修改
  • 不建议将 magic_enum 默认枚举范围改的太大,这会明显拖慢编译时间

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

世界上有那么多美好,不要跟自己过不去,总是揪着那些角落里的肮脏不放。我们无法选择抓到什么牌,但可以决定怎么把已经抓到手的牌打出去,摆烂是一天,奋斗也是一天,究竟要怎么做,取决于你自己~

相关文章:

  • 只问耕耘,不问收获,其实收获却在耕耘中
  • 一个月黑风高的夜晚紧急完成gitlab服务器数据迁移
  • SVN如何删除文件名包含空格的文件
  • std::uniform_real_distribution的一个bug引发的服务器崩溃
  • 参考开源项目实现一个简易的C++枚举转字符串的函数
  • git查看历史记录及修改内容
  • rm -rf 真是删库跑路的一把好手
  • 智能指针(三):weak_ptr浅析
  • float的精度和取值范围
  • linux环境下常用的打包、压缩、解压命令(tar、gzip、bzip2、zip)
  • MySQL数据库导入、导出、复制表、重命名表
  • Python操作Excel工作簿(\*.xlsx)
  • java对接银联商务公众号+服务窗支付(1)
  • java对接银联商务公众号+服务窗支付(2)
  • java对接银联商务公众号+服务窗支付(3)
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • ES2017异步函数现已正式可用
  • Github访问慢解决办法
  • Java方法详解
  • Laravel 菜鸟晋级之路
  • Python进阶细节
  • ReactNative开发常用的三方模块
  • Vue组件定义
  • WePY 在小程序性能调优上做出的探究
  • 算法系列——算法入门之递归分而治之思想的实现
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • ​configparser --- 配置文件解析器​
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • "无招胜有招"nbsp;史上最全的互…
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2)Java 简介
  • (2.2w字)前端单元测试之Jest详解篇
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (十六)串口UART
  • (十三)Flask之特殊装饰器详解
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • (转)重识new
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • 、写入Shellcode到注册表上线
  • .form文件_一篇文章学会文件上传
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NetCore项目nginx发布
  • .NET导入Excel数据
  • /*在DataTable中更新、删除数据*/
  • :not(:first-child)和:not(:last-child)的用法
  • @DataRedisTest测试redis从未如此丝滑
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)