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)
如何查看端口占用,各平台 一、背景 如何查看端口占用?网上很多,但大多直接丢出命令,没有任何解释关于如何查看命令的输出 所谓 “查端口占用”,即查看某个端口是否被某个程序占用,如果有,被哪…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
【字节拥抱开源】字节团队开源视频模型 ContentV: 有限算力下的视频生成模型高效训练
本项目提出了ContentV框架,通过三项关键创新高效加速基于DiT的视频生成模型训练: 极简架构设计,最大化复用预训练图像生成模型进行视频合成系统化的多阶段训练策略,利用流匹配技术提升效率经济高效的人类反馈强化学习框架&#x…...
