C++实现enum反射,类似magic_enum,支持enum classes
C++实现enum反射,类似magic_enum,支持enum classes
有一个
enum EnumTest { a = 1, b, c };
首先我们想实现
template <typename T, T N>
std::string GetEnumName() {return __PRETTY_FUNCTION__;
}
这样打印
GetEnumName<EnumTest,static_cast<EnumTest>(2)>()
出来的就是
std::string GetEnumName() [with T = EnumTest; T N = b; std::string = std::__cxx11::basic_string<char>]
对于这个字符串,我们只需要知道; T N = 后面跟的内容是啥就实现了我们的目标
但是我们不想像这样把参数写在模板了,而是想用一个函数直接传参
也就是想实现
template <typename T, T N>
std::string GetEnumNameImp() {std::string tmp = __PRETTY_FUNCTION__;auto first = tmp.find("T N = ");first += 6;auto end = tmp.find(";", first);return std::string(tmp, first, end - first);
}template <typename T>
std::string GetEnumName(T n) {return GetEnumNameImp<T,n>();
}
但是这样有问题,因为n是变量,无法传入模板。
那可以考虑这样写:
template <typename T>
std::string GetEnumName(T n) {if (n == 1) return GetEnumNameImp<T, T(1)>();if (n == 2) return GetEnumNameImp<T, T(2)>();if (n == 3) return GetEnumNameImp<T, T(3)>();
}
这样子可以保证传入模板的是常量并且可以动态判断了
到这里我们其实已经可以实现反射了。
但是很显然这个代码有那么一个问题:函数这样只能判断有限个数值,如果有更多数值呢,写无限个if吗
我们需要简化一下这个代码,让它能够自动执行完这么多个if,那么if的开始和结束呢?
没有特别好的方法做判断,我们只能先预定定义好开始和结束,比如Magic Enum 默认定义的就是-128~+128
开始实现代码
首先需要介绍一种模板for循环的小trick
template <int begin, int end, typename F> typename std::enable_if<begin == end>::type TemplateForLoop(const F &fun) { fun.template call<begin>(); } template <int begin, int end, typename F> typename std::enable_if<begin != end>::type TemplateForLoop(const F &fun) { fun.template call<begin>(); TemplateForLoop<begin + 1, end>(fun); }struct TestClass { template <int N> void call() const {std::cout << "N=" << N << std::endl; } };在这里使用模板递归调用fun函数,并把begin传入到fun中
使用:
TestClass<10,20>(TestClass());就会循环打印[10,20]注意这里的begin和end是左闭右闭的,如果需要左闭右开,可以在
begin==end时不执行fun
有了模板for循环,接来下就比较简单了
// enum imp
namespace detail {// Enum value must be greater or equals than G_CONFIG_ENUM_RANGE_MIN. By default
// G_CONFIG_ENUM_RANGE_MIN = -128. If need another min range for all enum types
// by default, redefine the macro G_CONFIG_ENUM_RANGE_MIN.
#if !defined(G_CONFIG_ENUM_RANGE_MIN)
#define G_CONFIG_ENUM_RANGE_MIN -128
#endif// Enum value must be less or equals than G_CONFIG_ENUM_RANGE_MAX. By default
// G_CONFIG_ENUM_RANGE_MAX = 128. If need another max range for all enum types
// by default, redefine the macro G_CONFIG_ENUM_RANGE_MAX.
#if !defined(G_CONFIG_ENUM_RANGE_MAX)
#define G_CONFIG_ENUM_RANGE_MAX 128
#endifstatic_assert(G_CONFIG_ENUM_RANGE_MAX < std::numeric_limits<int>::max(),"G_CONFIG_ENUM_RANGE_MAX must be less than INT_MAX.");static_assert(G_CONFIG_ENUM_RANGE_MIN > std::numeric_limits<int>::min(),"G_CONFIG_ENUM_RANGE_MIN must be greater than INT_MIN.");template <typename T, T N>
inline std::string GetEnumNameImp() {
#if defined(__GNUC__) || defined(__clang__)std::string tmp = __PRETTY_FUNCTION__;auto first = tmp.find("T N = ");first += 6;auto end = tmp.find(";", first);return std::string(tmp, first, end - first);
#elif defined(_MSC_VER)// TODO: add support for msvc
#else
#endif
}template <int begin, int end, typename F>
typename std::enable_if<begin == end>::type TemplateForLoop(const F &fun) {fun.template call<begin>();
}
template <int begin, int end, typename F>
typename std::enable_if<begin != end>::type TemplateForLoop(const F &fun) {fun.template call<begin>();TemplateForLoop<begin + 1, end>(fun);
}template <typename T>
struct GetEnumClass {std::string &str_;int n_;GetEnumClass(int n, std::string &str) : n_(n), str_(str) {}template <int N>void call() const {if (n_ == N) {str_ = detail::GetEnumNameImp<T, T(N)>();}}
};} // detail for enum imptemplate <typename T, int min = G_CONFIG_ENUM_RANGE_MIN,int max = G_CONFIG_ENUM_RANGE_MAX>
inline std::string GetEnumName(T n) {std::string str;gxt::detail::TemplateForLoop<min, max>(gxt::detail::GetEnumClass<T>(static_cast<int>(n), str));if (str.empty()) {throw std::runtime_error("\nenum out of range\n");}return str;
}template <typename T, int min = G_CONFIG_ENUM_RANGE_MIN,int max = G_CONFIG_ENUM_RANGE_MAX>
inline int GetNameEnum(std::string name) {std::string str;for (int i = G_CONFIG_ENUM_RANGE_MIN; i <= G_CONFIG_ENUM_RANGE_MAX; i++) {gxt::detail::TemplateForLoop<G_CONFIG_ENUM_RANGE_MIN,G_CONFIG_ENUM_RANGE_MAX>(gxt::detail::GetEnumClass<T>(static_cast<int>(i), str));if (!str.empty()) { // solve bug that use class enumauto find = str.find("::");if (find != std::string::npos) {find += 2;str = std::string(str, find);}}if (!str.empty() && str == name) {return i;}}throw std::runtime_error("\nenum out of range\n");return 0;
}
相关文章:
C++实现enum反射,类似magic_enum,支持enum classes
C实现enum反射,类似magic_enum,支持enum classes 有一个 enum EnumTest { a 1, b, c };首先我们想实现 template <typename T, T N> std::string GetEnumName() {return __PRETTY_FUNCTION__; }这样打印 GetEnumName<EnumTest,static_cast…...
机器学习与模式识别作业----决策树属性划分计算
文章目录 1.决策树划分原理1.1.特征选择1--信息增益1.2.特征选择2--信息增益比1.3.特征选择3--基尼系数 2.决策树属性划分计算题2.1.信息增益计算2.2.1.属性1的信息增益计算2.2.2.属性2的信息增益计算2.2.3.属性信息增益比较 2.2.信息增益比计算2.3.基尼系数计算 1.决策树划分原…...
爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会
标题:爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会 网址:https://fgw.sh.gov.cn/fgw-interaction-front/biz/projectApproval/home MD5加密:ca7f5c978b1809d15a4b228198814253 需求文档 采集数据如下所示: 解决反爬思路 这里只提供解决思路,解决反爬,…...
网络代理技术的威力:保障安全、保护隐私
在如今高度互联的数字时代,网络代理技术正在崭露头角,为网络工程师和普通用户提供了保障网络安全和隐私的强大工具。本文将深入探讨Socks5代理、IP代理以及它们在网络安全、爬虫开发和HTTP协议中的关键作用。 1. Socks5代理:多功能的网络中继…...
【STM32 中断】
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 STM32中断 前言一、STM32的中断如何?如何管理这么复杂的中断?实际优先级如下怎么使用呢? 二、使用步骤1.引入库函数先分组,怎么…...
TensorFlow入门(十二、分布式训练)
1、按照并行方式来分 ①模型并行 假设我们有n张GPU,不同的GPU被输入相同的数据,运行同一个模型的不同部分。 在实际训练过程中,如果遇到模型非常庞大,一张GPU不够存储的情况,可以使用模型并行的分布式训练,把模型的不同部分交给不同的GPU负责。这种方式存在一定的弊端:①这种方…...
在React中,什么是props(属性)?如何向组件传递props?
聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...
java 每种设计模式的作用,与应用场景
文章目录 前言java 每种设计模式的作用,与应用场景 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差,实在白嫖的话࿰…...
Appium问题及解决:打开Appium可视化界面,点击搜索按钮,提示inspectormoved
打开Appium可视化界面,点击搜索按钮,提示inspectorMoved,那么如何解决这个问题呢? 搜索了之后发现,由于高版本Appium(从1.22.0开始)的服务和元素查看器分离,所以还需要下载Appium In…...
android 不同进程之间数据传递
1.handler android.os.Message是定义一个Messge包含必要的描述和属性数据,并且此对象可以被发送给android.os.Handler处理。属性字段:arg1、arg2、what、obj、replyTo等;其中arg1和arg2是用来存放整型数据的;what是用来保存消息标…...
一个完整的初学者指南Django-part1
源自:https://simpleisbetterthancomplex.com/series/2017/09/04/a-complete-beginners-guide-to-django-part-1.html 一个完整的初学者指南Django - 第1部分 介绍 今天我将开始一个关于 Django 基础知识的新系列教程。这是一个完整的 Django 初学者指南。材料分为七…...
SpringBoot和Hibernate——如何提高数据库性能
摘要:本文由葡萄城技术团队发布。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 前言 在软件开发领域,性能是重中之重。无论您是构建小型 Web 应用程序还是大型企业系统…...
五分钟Win11安装安卓(Android)子系统
十分钟,完成win11安装安卓子系统 Step1、地区设置为美国 Wini 进入设置页面,选择时间和语言-语言和区域- 区域-美国 Step2 安装 Windows Subsystem for Android™ with Amazon Appstore 访问如下连接,install即可 安卓子系统 Step3 安…...
基于LSTM-Adaboost的电力负荷预测的MATLAB程序
微❤关注“电气仔推送”获得资料(专享优惠) 主要内容: LSTM-AdaBoost负荷预测模型先通过 AdaBoost集成算法串行训练多个基学习器并计算每个基学习 器的权重系数,接着将各个基学习器的预测结果进行线性组合,生成最终的预测结果。代码中的LST…...
GLTF纹理贴图工具让模型更逼真
1、如何制作逼真的三维模型? 要使三维模型看起来更加逼真,可以考虑以下几个方面: 高质量纹理:使用高分辨率的纹理贴图可以增强模型的细节和真实感。选择适合模型的高质量纹理图像,并确保纹理映射到模型上的UV坐标正确…...
HttpServletResponse对象
1.介绍 在Servlet API中,定义了一个HttpServletResponse接口,它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为状态行、响应消息头、消息体三部分,因此,在HttpServletResponse接口中定义…...
在SSL中进行交叉熵学习的步骤
在半监督学习(Semi-Supervised Learning,SSL)中进行交叉熵学习通常包括以下步骤: 准备标注数据和未标注数据 首先,你需要准备带有标签的标注数据和没有标签的未标注数据。标注数据通常是在任务中手动标记的ÿ…...
10月TIOBE榜Java跌出前三!要不我转回C#吧
前言 Java又要完了,又要没了,你没看错,10月编程语言榜单出炉,Java跌出前三,并且即将被C#超越,很多资深人士预测只需两个月,Java就会跌出前五。 看到这样的文章,作为一名Java工程师我…...
优盘中毒了怎么办?资料如何恢复
在现代社会中,优盘成为我们日常生活与工作中必备的便携式存储设备。然而,正是由于其便携性,优盘也成为病毒感染的主要目标之一。本篇文章将帮助读者了解如何应对优盘中毒的情况,以及如何恢复因病毒感染丢失的资料。 ▶优盘为什么…...
如何查看端口占用(windows,linux,mac)
如何查看端口占用,各平台 一、背景 如何查看端口占用?网上很多,但大多直接丢出命令,没有任何解释关于如何查看命令的输出 所谓 “查端口占用”,即查看某个端口是否被某个程序占用,如果有,被哪…...
FCEUX终极指南:从怀旧游戏到专业调试的完整NES模拟器教程
FCEUX终极指南:从怀旧游戏到专业调试的完整NES模拟器教程 【免费下载链接】fceux FCEUX, a NES Emulator 项目地址: https://gitcode.com/gh_mirrors/fc/fceux FCEUX是一款功能强大的开源NES模拟器,让你在现代电脑上完美重温经典红白机游戏。无论…...
硬件答辩问题总结
一、电源纹波是什么,为什么LDO的小,DCDC的大1.电源纹波电源纹波 是指直流电源输出电压上叠加的 交流波动成分,表现为电压在理想直流值附近上下波动。2.LDO 纹波小原理LDO 内部是一个 调整管(可变电阻) 串联在输入和输出…...
从电磁炉到户外电源:拆解单相SVPWM如何让你的逆变器更安静、更高效
从电磁炉到户外电源:单相SVPWM如何实现静音与高效的双重突破当你深夜用电磁炉煮面时,是否曾被突然的蜂鸣声吓一跳?或是发现户外电源给设备充电时,散热风扇的噪音盖过了山林鸟鸣?这些常见问题背后,隐藏着一个…...
HFSS仿真结果怎么看?一文读懂S参数与电场图,让你的T型波导分析不再迷茫
HFSS仿真结果深度解析:从S参数到电场图的工程实践指南面对HFSS仿真生成的复杂数据图表,许多工程师常陷入"看得见数据却读不懂含义"的困境。本文将带您穿透数据表象,掌握T型波导性能分析的核心方法论。1. S参数:波导性能…...
【DeepSeek测试用例生成实战指南】:20年QA专家亲授5大高覆盖率生成模式与3个避坑红线
更多请点击: https://codechina.net 第一章:DeepSeek测试用例生成的核心价值与适用边界 DeepSeek系列大模型在代码理解与生成任务中展现出显著的上下文建模能力,其测试用例生成功能并非通用“黑盒测试器”,而是聚焦于**单元级、函…...
森优时铁锌维发根养黑用三个月真实效果实测:内服营养养黑的客观测评
"森优时铁锌维发根养黑用三个月真实效果实测显示,针对压力、熬夜引发的早白问题,通过内服补充毛囊所需营养的方式,多数使用者能感受到发根韧性提升、新生发色素沉淀改善,整体改善效果因人而异,合规的营养补充是目…...
2026论文降AI怎么挑?亲测好用工具附免费降AI指南
“您的论文AIGC率为42%,超出学校30%的合格线,请修改后重新提交。”赶毕业论文的同学这段时间估计没少收到这样的提醒。2026年知网、万方、维普等主流平台的AI检测算法持续迭代,把AI生成内容改到符合学校要求,已经成了毕业生的刚需…...
翻译 GDB 官方文档
翻译 GDB 官方文档项目地址官方文档地址下载源码包编译html运行翻译程序项目地址 https://github.com/shootercheng/gdb-translate.git 项目结构 $ tree -L 1 . ├── cmd ├── go.mod ├── input ├── internal ├── LICENSE ├── output ├── README.md ├─…...
Unity UI交互进阶:手把手教你打造一个支持单击、双击、长按的万能按钮组件
Unity UI交互进阶:手把手教你打造一个支持单击、双击、长按的万能按钮组件在游戏开发中,UI交互的流畅性和多样性直接影响玩家的游戏体验。想象一下,当你在开发一个RPG游戏的背包系统时,需要实现道具的单击查看详情、双击快速使用、…...
Sora 2 MOV导出画质崩坏真相:HDR10元数据丢失、BT.2020色域截断、帧率标志位误写——3大隐性缺陷紧急修复方案
更多请点击: https://intelliparadigm.com 第一章:Sora 2 MOV导出画质崩坏的系统性认知 Sora 2 在生成高保真视频后,导出为 MOV 格式时频繁出现色度抽样失真、动态范围压缩、帧间伪影加剧等现象,其本质并非单一环节失效ÿ…...
