IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 用不到300行代码让C++在几乎不修改原来代码的情况下实现简单的反射与序列化 -> 正文阅读

[Python知识库]用不到300行代码让C++在几乎不修改原来代码的情况下实现简单的反射与序列化

C++自己并没有反射和序列化
而很多相关的实现代码非常复杂,而且含有大量模板和宏
比如这样的
在这里插入图片描述
(无意冒犯,只是拿来举例,代码的作者还是很棒帮的,后面写了更棒的反射代码)
反射的注册部分写得很复杂,如果我有一个已经写了很多的项目,那么涉及到的代码改动会非常大
而且很多都用了很多非常黑科技的模板技巧眼花缭乱的,满篇都是decltype,auto,constexpr,typeid
当然毕竟人家可以实现编译期反射,我这个不能。
但是从某种意义上来说,我觉得是可以的,只要想办法搞个编译期的unordered_map
所以在国庆节期间在家琢磨了一下如何实现一个使用起来简洁明了的反射
以及序列化和反序列化(反射一个很大的用途不就是干这个哈哈哈)
因为当前的主要目的其实是实现序列化和反序列化,所以暂时没有对成员函数进行反射
(即通过字符串来调用成员函数,这里会涉及到函数重载的问题,暂时还没想好解决办法)
目前还没有认真的进行debug和优化,只是暂时性的实现了简单的功能o( ̄▽ ̄)ブ
反正分享一个小demo,大家看看就好啦,代码采用了c++14的语法
首先看看我的代码实际使用上的简洁性:

#include<iostream>
#include"lang/reflectable.h"  //反射的实现,实现了序列化,反序列化还待补充
struct TestA:Reflectable //步骤1:继承Reflectable
{
	TestA(int x=10,float y=12,std::string z="sjf"):x(x),y(y),z(z),t(new int(123456))
	{}
	Config get_config() //步骤2:实现方法 get_config
	{    
		Config config=Reflectable::get_config(this);//类似python中config=super(xxx,self).get_config()
		config.update({                             //添加属性,Config可以看成一个哈希表
			{"x",x},                                //此处同样模仿了python的dict格式
			{"y",y},                               
			{"z",z},
			{"t",t}
		});
		return config;
	}
	int x;
	float y;
	std::string z;
	int*t;
}; 
struct TestB:Reflectable
{
	TestB(){x=nullptr);}
	Config get_config()
	{
		Config config=Reflectable::get_config(this);
		config.update({ 
			{"x",x},
			{"y",y}
		});
		return config;
	}
	int*x;   
	TestA y; //稍微复杂一点的情况,Test*y的情况这个暂时没处理
};
using namespace std;
int main()
{
	Reflectable::Regist<TestA,TestB>(); //步骤3,简单的注册一下,不注册就不会生成相关信息,直到调用一次get_config 
	try                                 //以及如果后续不调用get_config(),就不会生成反射相关的信息
	{                                   //所以并不是继承Reflectable就一定生成反射
		auto a=*(TestA*)Reflectable::get_instance("TestA"); //调用构造函数,没有参数被传递
		TestB b; 
		Reflectable::set_field(a,"x",2020);   //通过字符串给成员变量赋值
		Reflectable::set_field(a,"y",12.5f);
		Reflectable::set_field(a,"z",std::string("test"));
		Reflectable::set_field(a,"t",new int(45));
	
		cout<<a.x<<" "<<Reflectable::get_field<int>(a,"x")<<endl;  //输出成员变量
		cout<<a.y<<" "<<Reflectable::get_field<float>(a,"y")<<endl;
	    cout<<a.z<<" "<<Reflectable::get_field<std::string>(a,"z")<<endl;
	    cout<<*a.t<<" "<<*Reflectable::get_field<int*>(a,"t")<<endl;       //指针 
	
		cout<<a.get_config().serialized_to_string(); //序列化 
		cout<<"---------------------------------------\n";
		cout<<b.get_config().serialized_to_string();
	}
	catch(exception&e)
	{
		cout<<e.what();
	}
}

输出结果如下:
在这里插入图片描述

把null替换为None,放进python中能够正常运行,说明序列化后的格式没问题
在这里插入图片描述

不过跟python的json序列化的结果有一点出入
就是json里面只有字符串是双引号括起来的,我这里全括起来了
这是因为在当前反射的代码下暂时是不能得到更详细的(是否是字符串)的类型信息
得新写一个序列化的类别Serializable:public Reflectable 来解决(先占坑)
代码实现思路:
首先程序调用

	Reflectable::Regist<TestA,TestB>(); //初始化 

这个类的实现如下

#include<cxxabi.h>
#define GET_TYPE_NAME(type)\
abi::__cxa_demangle(typeid(type).name(),0,0,0) //得到完整的类型名称

template<typename T,typename ...Args>
struct Reflectable::Regist
{
	Regist()
	{
		T object;
		object.get_config();//必须调用get_config,才能建立类型信息,所以这里必须先调用一次config在运行时获得类型信息 
		Reflectable::default_constructors[GET_TYPE_NAME(T)]=[](void)->void* //记录默认构造函数 
		{
			return (void*)(new T());
		};
		Regist<Args...>();
	}
};

template<typename T>
struct Reflectable::Regist<T>
{
	Regist()
	{
		T object;
		object.get_config();
		Reflectable::default_constructors[GET_TYPE_NAME(T)]=[](void)->void* //默认构造函数 
		{
			return (void*)(new T());
		};
	}
};

就是循环把每个类都创建一个实例,然后调用get_config方法
第一次get_config会额外把属性的类型信息等记录下来,后续调用就只是得到一个Config字典
Reflectable::default_constructors是一个哈希表,记录构造函数,不一定是无参构造函数或者默认构造函数,反正是一个可以不传参数的构造函数

	using ClassName=std::string;
	static std::unordered_map<ClassName,std::function<void*(void)>>default_constructors;

接下来就是get_config里面的事情

	Config get_config()
	{
		Config config=Reflectable::get_config(this);
		config.update({
			{"x",x},
			{"y",y},
			{"z",z},
			{"t",t}
		});
		return config;
	}

Regist里面调用了T(Reflectable的子类)的get_config,然后子类又先调用了父类Reflectableget_config
Reflect的声明如下

struct Reflectable
{
	template<typename T,typename ...Args>
	struct Regist;
	template<typename T>
	struct Regist<T>;
	template<typename T>
	Config get_config(const T*object)const;//得到T的类型信息和名称,判断T类型的属性键值对是否建立,没有建立就建立(只建立一次) 
	template<typename ClassType,typename FieldType>
	static void set_field(ClassType&object,std::string field_name,FieldType&&data);//设置属性值,因为已经有类型信息,所以不需要调用constructor[type]里面的函数来构造 
	template<typename ClassType,typename FieldType>
	static void set_field(ClassType&object,std::string field_name,FieldType*data);//注意:并不会处理原来的指针指向的地址空间 
	template<typename FieldType,typename ClassType>
	static FieldType&get_field(ClassType&object,std::string field_name); 
	static void*get_instance(std::string class_name);
private:	
	using ClassName=std::string;
	using FieldName=std::unordered_map<std::string,std::pair<std::string,std::size_t>>;
	static std::unordered_map<ClassName,FieldName>field;//(类名称,方法名称)->(转化为字符串的属性值,地址偏移量)
	static std::unordered_map<ClassName,std::function<void(void*,void*)>>assigns;//反序列化用,暂不管
	static std::unordered_map<ClassName,std::function<void*(void)>>default_constructors;//构造函数
};
//三个静态属性记录了所有class和他的所有属性的值(字符串形式)和地址偏移量
//相比于记录每个类的每个属性地址,其实只需要记录每一个属性的地址偏移量
//然后所有对象都可以用对象+地址偏移量来访问属性

get_config方法实现如下:

template<typename T>
Config Reflectable::get_config(const T*object)const
{
	std::string class_name=GET_TYPE_NAME(T);//获得类名称
	Config config(
		field.find(class_name)==field.end()?&field[class_name]:nullptr,object);//如果不存在就创建,否则不做操作,这样保证field[class_name]只会被初始化一次
	config.update({{"class_name",class_name}});//把类型自己的名称加入到config中
	return config;
}

这个函数里面做的事情就是把自己的类型信息记录,然后将field[class_name]地址传入进行初始化
如果已经被初始化了,就跳过
接下来看config_update,Reflectable对象只记录字符串和函数指针,但不参与这些信息的获取
Config声明如下:

class Config//本身是一个键值对,但在每一个类型第一次调用的时候生成运行时的一些反射相关的信息 
{            //***field_info应该由Reflect对象负责管理,这里不应该删除指针*** 
public:
	Config(){}
	template<typename T>
	Config(std::unordered_map<std::string,std::pair<std::string,std::size_t>>*field_info,T*object);
	//在第一次被调用的时候,需要去创建类型信息,field_info记录属性名称->(类型名称,地址偏移量),记录类型在后续反序列化中需要用到 
	std::string serialized_to_string(bool first_nested_layer=true)const;      //序列化为字符串  
	std::string&operator[](const std::string&key); //键值对 
	void update(const std::initializer_list<ConfigPair>&pairs);
	/*
		添加变量对,这时候ConfigPair中会记录下类型信息,可以在运行时创建好反序列化时候需要对应的还原函数 
		config.update({
			{"namea",this->name1},
			{"name2",this->name2}
	    });
	*/
private:
	std::unordered_map<std::string,std::string>config;
	std::unordered_map<std::string,std::pair<std::string,std::size_t>>*field_info;//field_info只提供基本类型的还原函数,其他的直接调用from_config递归还原(反序列化阶段) 
	std::size_t class_header_address;
	std::size_t class_size;
};

Config::Config实现:

template<typename T>
Config::Config(std::unordered_map<std::string,std::pair<std::string,std::size_t>>*field_info,T*object): //在第一次被调用的时候,需要去创建类型信息 
	field_info(field_info),                                                                             //为后面的反序列化做准备 
	class_header_address((std::size_t)(object)),                                                        //field_info只提供基本类型的还原函数,其他的直接调用from_config递归还原
	class_size(sizeof(T))
	{}

在这里Config对象获得了对象地址和对象指针大小
Config::update实现:

void Config::update(const std::initializer_list<ConfigPair>&pairs)//添加变量对,config.update({{"namea",this->name1},{"name2",this->name2}});
{
	for(auto&it:pairs)
	{
		config[it.key]=it.value;
		if(field_info!=nullptr)                                //只被创建一次 c
		{
			(*field_info)[it.key].first=it.type;               //用于from_config中间接通过字符串得到类型信息 
			(*field_info)[it.key].second=it.address-this->class_header_address; //地址偏移量,用来访问成员变量 
		}
	}
}

这里就成功拿到了type和offset信息
记录类型信息是为了反序列化,把Json字符串还原为对象,Json字符串中并没有类型信息,况且也是通过字符串来遍历属性并还原,所以需要把类型信息记录下来,具体而言是在上面的assign中完成赋值
以及还未实现的字符串反序列化为对应类型的变量

啊说了这么多,其实这一堆几乎都是为了让代码使用起来更友好
具体的功能实现都在ConfigPair里面了o( ̄▽ ̄)ブ

struct ConfigPair
{
public:
	template<typename T>
	ConfigPair(std::string name,const T&object);
	std::string key;    //成员变量名称,与声明的名称对应 
	std::string value;  //成员函数的值转化为字符串的结果(如果是基本类型,则直接转化为字符串,否则为嵌套字典结构) 
	std::string type;   //类型,typeid(type).name(),相当于记录下类型了,runtime时反序列化会用到 
	std::size_t address;//地址,后面将用来计算成员变量地址偏移量,反序列化的时候通过(void*)(对象地址+偏移量)来访问成员变量 
private:
	template<typename T>
	struct has_member_get_config //编译期检测是否有成员函数get_config,如果value=true,说明该类型是支持序列化的非基本类型(实现了get_config方法) 
	{
	    template<typename U>
	        static auto Check(int)->decltype(std::declval<U>().get_config(),std::true_type());
	    template<typename U>
	        static std::false_type Check(...);
	    static constexpr int value = std::is_same<decltype(Check<T>(0)),std::true_type>::value;
	};
	template<typename T>
	using serializable_type=typename std::enable_if<has_member_get_config<T>::value,T>::type;  //可序列化非基本类型 
	template<typename T>
	using fundamental_type=typename std::enable_if<std::is_fundamental<T>::value,T>::type;     //基本类型 
	template<typename T>
	using std_string_type=typename std::enable_if<std::is_same<T,std::string>::value,T>::type; //字符串 
	template<typename T> 
	using remove_pointer=typename std::remove_pointer<T>::type;                                //移除指针 
	template<typename T>
	using ptr_fundamental_type=typename std::enable_if<std::is_pointer<T>::value&std::is_fundamental<remove_pointer<T>>::value,T>::type;//基本类型的指针
	template<typename T>
	using unsupported_type=typename std::enable_if<not(                                        //其他类型 
		std::is_same<fundamental_type<T>,T>::value|
		std::is_same<std_string_type<T>,T>::value|
		std::is_same<ptr_fundamental_type<T>,T>::value|
		std::is_same<serializable_type<T>,T>::value
	),T>::type;
	template<typename T>
	static auto get_config_string(const fundamental_type<T>&field);//基本类型 
	template<typename T>
	static auto get_config_string(const std_string_type<T>&field);//std::string 
	template<typename T>
	static auto get_config_string(const ptr_fundamental_type<T>&field);//基本类型的指针 
	template<typename T>
	static auto get_config_string(const serializable_type<T>&field);//基本类型的指针 
	template<typename T>
	static auto get_config_string(const unsupported_type<T>&field);//其他 
};

这里面涉及到很多跟类型相关的模板,分为基本类型,基本类型的指针,Reflectable子类(实现了get_config方法),Reflectable子类指针,std::string,其他不支持的类型,然后处理方式上有所差异
类似int float之类的基本类型,变为字符串是很容易的

template<typename T>
auto ConfigPair::get_config_string(const fundamental_type<T>&field)//基本类型 
{
	std::ostringstream oss;
	oss<<field;
	return oss.str();
}
template<typename T>
auto ConfigPair::get_config_string(const ptr_fundamental_type<T>&field)//基本类型的指针 
{
	if(field==nullptr) //空指针 
		return std::string("null"); 
	std::ostringstream oss;
	oss<<*field;
	return oss.str();
}

对于Reflectable子类,递归之

template<typename T>
auto ConfigPair::get_config_string(const serializable_type<T>&field)//可序列化的非基本类型 
{
	std::ostringstream oss;
	return ((T)field).get_config().serialized_to_string(false);
}

ConfigPair::ConfifPair

template<typename T>
ConfigPair::ConfigPair(std::string name,const T&object):
	key(name), //名称
	value(ConfigPair::get_config_string<T>(object)), //转化为字符串的值
	type(GET_TYPE_NAME(T)), //类型对应的字符串
	address((std::size_t)&object) //地址,用来计算地址偏移量
	{}

这里的构造函数是模板函数,所以可以在编译器捕获到成员变量的类型信息
也就是

		config.update({
			{"x",x},
			{"y",y},
			{"z",z},
			{"t",t}
		});

实际上应该是

		config.update(std::initializer_list<ConfigPair>({
			ConfigPair({"x",x}),
			ConfigPair({"y",y}),
			ConfigPair({"z",z}),
			ConfigPair({"t",t})
		)});

每一行其实调用了不同的构造函数,因此类型信息得以被记录下来
同样不同的类型采用不同的序列化和反序列化
整个问题就解决了,可以在原来的代码的基础上添加少量修改,就很方便的实现了序列化
至于Config这个"字典"转化为字符串,这就简单很多了,直接遍历输出就行

std::string Config::serialized_to_string(bool first_nested_layer)const //序列化的内容,后面会移动到Serializable::xxx() 
{
	std::ostringstream oss;
	if(first_nested_layer)
	{
		oss<<"{\n";
		for(auto&it:config)
			oss<<"\""<<it.first<<"\":"<<it.second<<",\n";
		oss<<"}\n";
	}
	else
	{
		oss<<"{";
		for(auto&it:config)
			oss<<"\""<<it.first<<"\":"<<it.second<<",";
		oss<<"}";
	}
	return oss.str();
}

完结撒花!

以下是完整的源码
main.cpp

//#define DEBUG_TENSOR
//#define DEBUG_SHARED_DATA
#include<iostream>
#include"lang/reflectable.h"
struct TestA:Reflectable
{
	TestA(int x=10,float y=12,std::string z="sjf"):x(x),y(y),z(z),t(new int(123456))
	{}
	Config get_config()
	{
		Config config=Reflectable::get_config(this);
		config.update({
			{"x",x},
			{"y",y},
			{"z",z},
			{"t",t}
		});
		return config;
	}
	int x;
	float y;
	std::string z;
	int*t;
}; 
struct TestB:Reflectable
{
	TestB(){x=nullptr;}
	Config get_config()
	{
		Config config=Reflectable::get_config(this);
		config.update({
			{"x",x},
			{"y",y}
		});
		return config;
	}
	int*x;
	TestA y;
};
using namespace std;  
int main() 
{
	Reflectable::Regist<TestA,TestB>(); //初始化   
	try
	{
		auto a=*(TestA*)Reflectable::get_instance("TestA"); //构造函数
		TestB b; 
		Reflectable::set_field(a,"x",2020);
		Reflectable::set_field(a,"y",12.5f);
		Reflectable::set_field(a,"z",std::string("test"));
		Reflectable::set_field(a,"t",new int(45));
	
		cout<<a.x<<" "<<Reflectable::get_field<int>(a,"x")<<endl;
		cout<<a.y<<" "<<Reflectable::get_field<float>(a,"y")<<endl;
	    cout<<a.z<<" "<<Reflectable::get_field<std::string>(a,"z")<<endl;
	    cout<<*a.t<<" "<<*Reflectable::get_field<int*>(a,"t")<<endl;       //指针 
	
		cout<<a.get_config().serialized_to_string(); //序列化 
		cout<<"---------------------------------------\n";
		cout<<b.get_config().serialized_to_string();
	}
	catch(exception&e)
	{
		cout<<e.what();
	}
}

configpair.h

#ifndef __CONFIGPAIR_H__
#define __CONFIGPAIR_H__
#include<string>
#include<typeinfo>
#include<sstream>
#include<string> 
#include<cxxabi.h>
#define GET_TYPE_NAME(type)\
abi::__cxa_demangle(typeid(type).name(),0,0,0)
struct ConfigPair
{
public:
	template<typename T>
	ConfigPair(std::string name,const T&object);
	std::string key;    //成员变量名称,与声明的名称对应 
	std::string value;  //成员函数的值转化为字符串的结果(如果是基本类型,则直接转化为字符串,否则为嵌套字典结构) 
	std::string type;   //类型,typeid(type).name(),相当于记录下类型了,runtime时反序列化会用到 
	std::size_t address;//地址,后面将用来计算成员变量地址偏移量,反序列化的时候通过(void*)(对象地址+偏移量)来访问成员变量 
private:
	template<typename T>
	struct has_member_get_config //编译期检测是否有成员函数get_config,如果value=true,说明该类型是支持序列化的非基本类型(实现了get_config方法) 
	{
	    template<typename U>
	        static auto Check(int)->decltype(std::declval<U>().get_config(),std::true_type());
	    template<typename U>
	        static std::false_type Check(...);
	    static constexpr int value = std::is_same<decltype(Check<T>(0)),std::true_type>::value;
	};
	template<typename T>
	using serializable_type=typename std::enable_if<has_member_get_config<T>::value,T>::type;  //可序列化非基本类型 
	template<typename T>
	using fundamental_type=typename std::enable_if<std::is_fundamental<T>::value,T>::type;     //基本类型 
	template<typename T>
	using std_string_type=typename std::enable_if<std::is_same<T,std::string>::value,T>::type; //字符串 
	template<typename T> 
	using remove_pointer=typename std::remove_pointer<T>::type;                                //移除指针 
	template<typename T>
	using ptr_fundamental_type=typename std::enable_if<std::is_pointer<T>::value&std::is_fundamental<remove_pointer<T>>::value,T>::type;//基本类型的指针
	template<typename T>
	using unsupported_type=typename std::enable_if<not(                                        //其他类型 
		std::is_same<fundamental_type<T>,T>::value|
		std::is_same<std_string_type<T>,T>::value|
		std::is_same<ptr_fundamental_type<T>,T>::value|
		std::is_same<serializable_type<T>,T>::value
	),T>::type;
	template<typename T>
	static auto get_config_string(const fundamental_type<T>&field);//基本类型 
	template<typename T>
	static auto get_config_string(const std_string_type<T>&field);//std::string 
	template<typename T>
	static auto get_config_string(const ptr_fundamental_type<T>&field);//基本类型的指针 
	template<typename T>
	static auto get_config_string(const serializable_type<T>&field);//基本类型的指针 
	template<typename T>
	static auto get_config_string(const unsupported_type<T>&field);//其他 
};
//只支持基本类型(int,double,...)及其指针形式,以及std::string 
//其他类型均认为是复合类型,从from_config中递归恢复,否则从constructors中找到合适的... 
template<typename T>
ConfigPair::ConfigPair(std::string name,const T&object):
	key(name),
	value(ConfigPair::get_config_string<T>(object)),
	type(GET_TYPE_NAME(T)),
	address((std::size_t)&object)
	{
	//	std::cout<<"name:"<<name<<" address:"<<&object<<std::endl;
	}
template<typename T>
auto ConfigPair::get_config_string(const fundamental_type<T>&field)//基本类型 
{
	std::ostringstream oss;
	oss<<field;
	return oss.str();
}
template<typename T>
auto ConfigPair::get_config_string(const std_string_type<T>&field)//std::string 
{
	return field;
}
template<typename T>
auto ConfigPair::get_config_string(const ptr_fundamental_type<T>&field)//基本类型的指针 
{
	std::ostringstream oss;
	oss<<*field;
	return oss.str();
}
template<typename T>
auto ConfigPair::get_config_string(const serializable_type<T>&field)//可序列化的非基本类型 
{
	std::ostringstream oss;
	return ((T)field).get_config().serialized_to_string(false);
}
template<typename T>
auto ConfigPair::get_config_string(const unsupported_type<T>&field)//其他 
{
	return "<unsupported type>";
}		
#endif

config.h

#ifndef __CONFIG_H__
#define __CONFIG_H__
#include"configpair.h"
#include<unordered_map>
class Config//本身是一个键值对,但在每一个类型第一次调用的时候生成运行时的一些反射相关的信息 
{            //***field_info应该由Serializable对象负责清楚,这里不应该删除指针*** 
public:
	Config(){}
	template<typename T>
	Config(std::unordered_map<std::string,std::pair<std::string,std::size_t>>*field_info,T*object);
	//在第一次被调用的时候,需要去创建类型信息,field_info记录属性名称->(类型名称,地址偏移量),记录类型在后续反序列化中需要用到 
	std::string serialized_to_string(bool first_nested_layer=true)const;      //序列化为字符串  
	std::string&operator[](const std::string&key); //键值对 
	void update(const std::initializer_list<ConfigPair>&pairs);
	/* 添加变量对,这时候ConfigPair中会记录下类型信息,可以在运行时创建好反序列化时候需要对应的还原函数 
		config.update({
			{"namea",this->name1},
			{"name2",this->name2}
	    });
	*/
private:
	std::unordered_map<std::string,std::string>config;
	std::unordered_map<std::string,std::pair<std::string,std::size_t>>*field_info;//field_info只提供基本类型的还原函数,其他的直接调用from_config递归还原(反序列化阶段) 
	std::size_t class_header_address;
	std::size_t class_size;
};
template<typename T>
Config::Config(std::unordered_map<std::string,std::pair<std::string,std::size_t>>*field_info,T*object): //在第一次被调用的时候,需要去创建类型信息 
	field_info(field_info),                                                                             //为后面的反序列化做准备 
	class_header_address((std::size_t)(object)),                                                        //field_info只提供基本类型的还原函数,其他的直接调用from_config递归还原
	class_size(sizeof(T)){}
void Config::update(const std::initializer_list<ConfigPair>&pairs)//添加变量对,config.update({{"namea",this->name1},{"name2",this->name2}});
{
	for(auto&it:pairs)
	{
		config[it.key]=it.value;
		if(field_info!=nullptr)                                //只被创建一次 c
		{
			(*field_info)[it.key].first=it.type;               //用于from_config中间接通过字符串得到类型信息 
			(*field_info)[it.key].second=it.address-this->class_header_address; //地址偏移量,用来访问成员变量 
		}
	}
}
std::string&Config::operator[](const std::string&key) //键值对 
{
	return config[key];
}
std::string Config::serialized_to_string(bool first_nested_layer)const //序列化的内容,后面会移动到Serializable::xxx() 
{
	std::ostringstream oss;
	if(first_nested_layer)
	{
		oss<<"{\n";
		for(auto&it:config)
			oss<<"\""<<it.first<<"\":"<<it.second<<",\n";
		oss<<"}\n";
	}
	else
	{
		oss<<"{";
		for(auto&it:config)
			oss<<"\""<<it.first<<"\":"<<it.second<<",";
		oss<<"}";
	}
	return oss.str();
}
#endif

reflectable.h

#ifndef __REFLECT_H__
#define __REFLECT_H__
#include"config.h"
#include<functional>
struct Reflectable
{
	template<typename T,typename ...Args>
	struct Regist;
	template<typename T>
	struct Regist<T>;
	template<typename T>
	Config get_config(const T*object)const;//得到T的类型信息和名称,判断T类型的属性键值对是否建立,没有建立就建立(只建立一次) 
	template<typename ClassType,typename FieldType>
	static void set_field(ClassType&object,std::string field_name,FieldType&&data);//设置属性值,因为已经有类型信息,所以不需要调用constructor[type]里面的函数来构造 
	template<typename ClassType,typename FieldType>
	static void set_field(ClassType&object,std::string field_name,FieldType*data);//注意:并不会处理原来的指针指向的地址空间 
	template<typename FieldType,typename ClassType>
	static FieldType&get_field(ClassType&object,std::string field_name); 
	static void*get_instance(std::string class_name);
private:	
	using ClassName=std::string;
	using FieldName=std::unordered_map<std::string,std::pair<std::string,std::size_t>>;
	static std::unordered_map<ClassName,FieldName>field;
	static std::unordered_map<ClassName,std::function<void(void*,void*)>>assigns;
	static std::unordered_map<ClassName,std::function<void*(void)>>default_constructors;
};
std::unordered_map<std::string,std::unordered_map<std::string,std::pair<std::string,std::size_t>>>Reflectable::field;
std::unordered_map<std::string,std::function<void(void*,void*)>>Reflectable::assigns={//for fundamental
	{GET_TYPE_NAME(int),[](void*p,void*q){*(int*)p=*(int*)q;}},
	{GET_TYPE_NAME(float),[](void*p,void*q){*(float*)p=*(float*)q;}},
	{GET_TYPE_NAME(double),[](void*p,void*q){*(double*)p=*(double*)q;}},
	{GET_TYPE_NAME(char),[](void*p,void*q){*(char*)p=*(char*)q;}},
	{GET_TYPE_NAME(std::string),[](void*p,void*q){*(std::string*)p=*(std::string*)q;}},
};
std::unordered_map<std::string,std::function<void*(void)>>Reflectable::default_constructors;
template<typename T>
Config Reflectable::get_config(const T*object)const
{
	std::string class_name=GET_TYPE_NAME(T);
	Config config(
		field.find(class_name)==field.end()?&field[class_name]:nullptr,object);//如果不存在就创建,否则不做操作 
	config.update({{"class_name",class_name}});
	return config;
}
template<typename ClassType,typename FieldType>
void Reflectable::set_field(ClassType&object,std::string field_name,FieldType&&data)
{
	std::string class_name=GET_TYPE_NAME(ClassType);
	std::size_t offset=Reflectable::field[class_name][field_name].second;
	std::string type=Reflectable::field[class_name][field_name].first;
	*(FieldType*)((std::size_t)(&object)+offset)=data;
}
template<typename ClassType,typename FieldType>
void Reflectable::set_field(ClassType&object,std::string field_name,FieldType*data)//注意:并不会处理原来的指针指向的地址空间 
{
	std::string class_name=GET_TYPE_NAME(ClassType);
	std::size_t offset=Reflectable::field[class_name][field_name].second;
	std::string type=Reflectable::field[class_name][field_name].first;
	*(FieldType**)((std::size_t)(&object)+offset)=data;
}

template<typename FieldType,typename ClassType>
FieldType&Reflectable::get_field(ClassType&object,std::string field_name)
{
	std::string class_name=GET_TYPE_NAME(ClassType);
	std::size_t offset=Reflectable::field[class_name][field_name].second;
	std::string type=Reflectable::field[class_name][field_name].first;
	return *(FieldType*)((std::size_t)(&object)+offset);
}
void*Reflectable::get_instance(std::string class_name)
{
	return Reflectable::default_constructors[class_name]();
}
template<typename T,typename ...Args>
struct Reflectable::Regist
{
	Regist()
	{
		T object;
		object.get_config();//必须调用get_config,才能建立类型信息,所以这里必须先调用一次Reflectable的get_config 
		Reflectable::default_constructors[GET_TYPE_NAME(T)]=[](void)->void*{return (void*)(new T());}; //默认构造函数 
		Regist<Args...>();
	}
};
template<typename T>
struct Reflectable::Regist<T>
{
	Regist()
	{
		T object;
		object.get_config();
		Reflectable::default_constructors[GET_TYPE_NAME(T)]=[](void)->void* //默认构造函数 
		{
			return (void*)(new T());
		};
	}
};
#endif
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:14:15  更:2021-10-09 16:14:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 17:53:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码