跟我学c++高级篇——基础类型和POD结构体反射

一、基础类型反射

在前面以枚举体和函数进行了反射的实践,在其中也提到过,其实更应该进行反射的是类(结构体)。毕竟现在以面向对象编程基本已经普及,类(结构体)的应用几乎已经是无法避免的。所以对类(后面再提到类即包含结构体)的反射,其实应用的范围会更大。
对基础类型和POD类型的结构体进行反射,一般就是下面的情况:
1、对名称进行反射来动态获取和创建对象
2、对结构体变量的反射
这里只是POD类型的结构体,复杂的在后面再进行分析,当然这里也包含简单类。

二、实现机制

在前面反复进行反射的分析说明时,其实可以发现,反射实现常用的机制还是比较多的,但一般来说应用的比较多的就是使用模板和宏配合来实现。当然在具体的实现过程中可能需要一些具体的编译器或者辅助库的实现。另外在c++新标准下也提供了一些方法比如可以使用std::tuple来实现类的反射。
其实原理仍然是前面分析过的文章中的思路,即获取名称字符串与结构体之间的映射,其成员(变量)需要进行遍历注册。这样就可以在后面的代码中利用字符串来搞定这些对象获取及动态创建对象等。
这里需要再次说明的是:
1、是否需要侵入式处理
2、是否开销最小甚至是零开销
3、是否反射完全,即包括私有数据等是否可以得到
这三个条件是实现一个好的反射框架的前提。

三、实现

下面看一个初步的实现:

#pragma once
#include <string>
#include <array>
#include <stddef.h>
#include <iostream>typedef unsigned int uint32;struct Type {std::string typeName;size_t size;
};//获得结构体成员类型信息
template<typename T>Type* GetFieldType();
#define GET_OBJECT_TYPE(TYPE) \
template<> \
Type* GetFieldType<TYPE>() { \
static Type t; \t.typeName = #TYPE; \t.size = sizeof(TYPE); \return &t; \
};\

//成员反射信息
struct Member {Type* t;std::string name;size_t offset;
};
constexpr int ARRAY_NUM = 4;// 存储结构体的相关成员
struct ClassArray {std::array<Member, ARRAY_NUM> members;
};//遍历获得类或结构体的成员信息
template<typename T>
const ClassArray* GetClass();
#define BEGIN_MEMBERS_FOR(CLASS)  \
template<> \
const ClassArray* GetClass<CLASS> () { \using ClassType = CLASS; \static ClassArray cArray; \enum { BASE = __COUNTER__ }; \

#define OBJECT_MEMBER(NAME)  \enum { NAME##ID = __COUNTER__ - BASE - 1}; \cArray.members[NAME##ID].t = GetFieldType<decltype(ClassType::NAME)>();\cArray.members[NAME##ID].name = { #NAME };  \cArray.members[NAME##ID].offset = offsetof(ClassType, NAME);\

#define END_MEMBERSS \return &cArray; \
};\

//获得类型信息宏处理
GET_OBJECT_TYPE(char)
GET_OBJECT_TYPE(short)
GET_OBJECT_TYPE(int)
GET_OBJECT_TYPE(uint32)struct Data {int id;short len;char sex;uint32 size;
};//处理结构体的反射
BEGIN_MEMBERS_FOR(Data)
OBJECT_MEMBER(id);
OBJECT_MEMBER(len);
OBJECT_MEMBER(sex);
OBJECT_MEMBER(size);
END_MEMBERSSint main()
{auto x = GetClass<Data>();std::cout<<"TestStruct:"<<std::endl;for (auto &x :x->members){std::cout<<x.name<<",offset:"<<x.offset<<",type:"<<x.t->typeName<<std::endl;}return 0;
}

上面有两个宏需要注意,一个是__COUNTER__,一个是offsetof,前者是GNU的的一扩展,用来处理得到一个唯一键值;后者则是通过偏移量来获得类或结构体内成员的位置(也可以反过来理解)。
上面的代码其实很容易理解,注释写得比较清晰了,这里再简单的说明一下:
1、首先定义两个信息类:一个是基础的Type类,用来获得类型的相关信息,如名字等;另外一个是Member类,用来处理成员的相关信息
2、通过宏GET_OBJECT_TYPE来得到具体的类型信息,这个用来哪个就需要注册一个
3、通过宏OBJECT_MEMBER来得到成员信息并和刚刚得到的类型信息绑定
4、利用模板的显示实例化来实现不同的信息的具体处理
其实上面的代码只是一个基础的版本,如果不习惯使用宏的,可以将成员函数等宏实现改成普通的静态函数来实现。但是完全不使用宏,可能操作起来还是有些看起来不方便。这个根据个人的喜好自己斟酌。

四、std::tuple的实现

这个在这里简单介绍一下,回头在后续再展开分析。在前边的“面向切片编程”中,提到了使用tuple_element可以获得std::tuple中的类型。而在反射中,不就是一个类型获取的过程么?

//利用变参模板和tuple的特性来获取指定的类型
template<typename ...Types>
class ProxyObjectTypes {public:template<std::size_t ID>struct GetType {using Type = typename std::tuple_element<ID, std::tuple<Types...>>::type;};
};
//C++11定义的方式:
template <std::size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;

那么,这就可以通过显示实例化不同的模板函数参数版本来处理不同的数据类型,是不是和上面的代码中的类似。其实使用模板处理反射类型大多也是这么个路子。那么就可以写一个getType的模板函数,通过decay(decltype)和if constexpr来在编译期得到想要的数据类型。
可以通过下面的这个判断来确定std::tuple中的类型是否为自己需要的数据类型。这样就可以安全的获得类型信息的数据类型,进而得到数据对象。

constexpr int count_first_falses() { return 0; }template <typename... T>
constexpr int count_first_falses(bool b, T... t)
{if (b){return 0;}else{return 1 + count_first_falses(t...);}
}template <typename E, typename... T>
decltype(auto) tuple_get_by_type(const std::tuple<T...>& tuple)    
{return std::get<count_first_falses((std::is_same<T, E>::value)...)>(tuple);
}decltype(auto) getType(const std::tuple<int,int> &t)
{return tuple_get_by_type(t);
}

如果只是单纯的想获得类型可以用下面的方法:


#include <string>
#include <tuple>template <typename T> T* getType() {  return nullptr;}
template <> int* getType<int>() { return new int; }
template <> std::string* getType<std::string>() { return new std::string; }int main()
{using T = std::tuple<int, std::string>;getType<std::tuple_element<0, T>::type>();getType<std::tuple_element_t<1, T>>();return 0;
}

代码不难,基本上看一下就能明白。

五、总结

由简入繁,从基本到深入总是需要一个过程,学习反射也是如此。写代码是为了把学习的知识验证一下,同时可以更加深刻的理解知识。开发者们经常遇到这种场景,几行简单的代码,琢磨半天也确定不了什么意思,但是上机一调试,就恍然大悟。这就是侯捷教师的那句话“源码之前,了无秘密”。
反射还是有些难度的,所以这个系列会慢慢增加。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/621200.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高斯Hack算法

背景 刷leetcode时&#xff0c;碰到一题需要求解n个bit中选择m个bit的所有组合集&#xff0c;我只想到了递归求解&#xff0c;没啥问题&#xff0c;但是在官方题解中看到了牛逼的方法(Gospers Hack)&#xff0c;故记录一下。 4bit中2个1的情况 0011b0101b0110b1001b1010b1100b…

基于协同过滤的零食推荐系统

介绍 协同过滤算法&#xff1a;协同过滤是推荐系统中比较常用的算法之一&#xff0c;其核心思想是寻找用户之间的相似性&#xff0c;通过发现用户之间的共性&#xff0c;向用户推荐可能喜欢的商品或服务。Python Django Vue&#xff1a;Django 是一个基于 Python 的 Web 开发框…

模型的权值平均的原理和Pytorch的实现

一、前言 模型权值平均是一种用于改善深度神经网络泛化性能的技术。通过对训练过程中不同时间步的模型权值进行平均&#xff0c;可以得到更宽的极值点&#xff08;optima&#xff09;并提高模型的泛化能力。 在PyTorch中&#xff0c;官方提供了实现模型权值平均的方法。 这里…

遥感类SCI期刊_一区二区汇总

IEEE Geoscience And Remote Sensing Magazine(Ieee地球科学与遥感杂志) h-index:19 CiteScore:17.80 1区 IEEE Geoscience and Remote Sensing Magazine | IEEE Xplore Remote Sensing Of Environment(环境遥感) h-index:238 CiteScore:24.80 1区 https://www.scienced…

深度学习15—(迁移学习)冻结和解冻神经网络模型的参数

冻结与解冻代码&#xff1a; def freeze_net(net):if not net:returnfor p in net.parameters():p.requires_grad Falsedef unfreeze_net(net):if not net:returnfor p in net.parameters():p.requires_grad True 这段代码定义了两个函数&#xff1a;freeze_net 和 unfree…

webview全屏处理,即插即用

去年双十一有个直播的需求&#xff0c;听起来很简单&#xff0c;技术也都很成熟&#xff0c;但是真的开始实现后&#xff0c;还是有不少坑的&#xff0c;首先第一个uc内核不支持webRTC协议&#xff0c;需要重新开发chrome内核的webview&#xff0c;其次webview全屏处理、悬浮窗…

PYTHON通过跳板机巡检CENTOS的简单实现

实现的细节和引用的文件和以前博客记录的基本一致 https://shaka.blog.csdn.net/article/details/106927633 差别在于,这次是通过跳板机登陆获取的主机信息,只记录差异的部份 1.需要在跳板机相应的路径放置PYTHON的脚本resc.py resc.py这个脚本中有引用的文件(pm.sh,diskpn…

查询速度提升15倍!银联商务基于 Apache Doris 的数据平台升级实践

本文导读&#xff1a; 在长期服务广大规模商户的过程中&#xff0c;银联商务已沉淀了庞大、真实、优质的数据资产数据&#xff0c;这些数据不仅是银联商务开启新增长曲线的基础&#xff0c;更是进一步服务好商户的关键支撑。为更好提供数据服务&#xff0c;银联商务实现了从 H…

EI级 | Matlab实现VMD-TCN-LSTM变分模态分解结合时间卷积长短期记忆神经网络多变量光伏功率时间序列预测

EI级 | Matlab实现VMD-TCN-LSTM变分模态分解结合时间卷积长短期记忆神经网络多变量光伏功率时间序列预测 目录 EI级 | Matlab实现VMD-TCN-LSTM变分模态分解结合时间卷积长短期记忆神经网络多变量光伏功率时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【E…

Springboot3新特性:开发第一个 GraalVM 本机应用程序(完整教程)

在讲述之前&#xff0c;各位先自行在网上下载并安装Visual Studio 2022&#xff0c;安装的时候别忘了勾选msvc 概述&#xff1a;GraalVM 本机应用程序&#xff08;Native Image&#xff09;是使用 GraalVM 的一个特性&#xff0c;允许将 Java 应用程序编译成本机二进制文件&am…

AI-数学-高中-5.求函数解析式(4种方法)

原作者视频&#xff1a;函数】3函数解析式求法&#xff08;易&#xff09;_哔哩哔哩_bilibili 1.已知函数类型-待定系数法&#xff1a;先用待定系数法把一次或二次函数一般表达式写出来&#xff1b;再用“要变一起变”左右两边同时替换&#xff0c;计算出一般表达式的常数&…

18、golang时间管理

时间 时间是非常重要的&#xff0c;离开了时间&#xff0c;几乎没有哪个生产环境数据能够有意义。 在Go语言中&#xff0c;时间定义为Time结构体。 package mainimport ("fmt""time" )func main() {var t time.Now()fmt.Println(t) fmt.Printf("%…

【嵌入式-裸机开发】kermit工具安装使用

安装ckermit sudo apt-get install ckermit配置kermit vim ~/.mykermrc set line /dev/ttyS0 set speed 115200 set carrier-watch off set handshake none set flow-control none robust set file type bi…

ZZULIOJ 1121: 电梯

题目描述 在某一高层建筑内只有一部电梯&#xff0c;当你按下一个数时&#xff0c;电梯会运行到那一层。已知电梯每上升一层需6秒&#xff0c;下降一层需4秒&#xff0c;在需要停留的那层停留5秒。现有N个整数组成的一个需求列表&#xff0c;电梯将依次响应&#xff0c;电梯从…

树的高度C++(dfs)

树是一种特殊的图结构&#xff0c;有根树是一个有固定根的树。 现在给定一棵有根树&#xff0c;编程求出树中所有节点到指定的根节点最远距离。 输入格式 第一行是两个整数 N,M&#xff0c;表示数的顶点数和根节点的编号。接下来 N−1 行&#xff0c;每行两个整数 u,v&#xf…

SpringIOC之support模块GenericGroovyApplicationContext

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

商务外语MR混合现实仿真情景实训教学

MR混合现实技术是一种将虚拟世界与真实世界相结合的技术。通过MR设备&#xff0c;我们可以将虚拟的场景、人物、物品等元素实时地呈现在真实的环境中&#xff0c;实现真实与虚拟的完美融合。在商务外语的实训教学中&#xff0c;MR技术可以为我们提供丰富的场景资源&#xff0c;…

【c++】利用嵌套map创建多层树结构

通常树的深度都大于1&#xff0c;即树有多层&#xff0c;而树结构又可以用c的map容器来实现&#xff0c;所以&#xff0c;本文给出了一种多层树结构的实现思路&#xff0c;同时也给出了相应的c代码。 整体思路概述 首先定义一个节点类Node类&#xff0c;要包括children&#x…

FineBI实战项目一(17):热门商品Top10分析开发

点击新建组件&#xff0c;创建热门商品Top10组件。 选择柱状图&#xff0c;拖拽cnt&#xff08;总数&#xff09;到横轴&#xff0c;拖拽goodName到纵轴。 选择排序规则。 修改横轴和纵轴的标签名称 切换到仪表板&#xff0c;拖拽组件到仪表板 效果如下&#xff1a;

运维信创:驱动数字化转型,塑造企业未来之篇章

随着信息技术的迅猛发展&#xff0c;数字化转型已成为企业生存和发展的必由之路。在数字化转型的过程中&#xff0c;运维作为企业IT的重要组成部分&#xff0c;其信创成熟度直接关系到数字化转型的进程。本文将深入探讨运维的信创&#xff0c;分析其与信创的区别、技术成熟度、…