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)
如何查看端口占用,各平台 一、背景 如何查看端口占用?网上很多,但大多直接丢出命令,没有任何解释关于如何查看命令的输出 所谓 “查端口占用”,即查看某个端口是否被某个程序占用,如果有,被哪…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
