构建简单的C++运行时反射类型系统

2014/04/05 12:01
阅读数 1K

《运行期构建C++类型系统》这篇文章中,我构建了一套简单的运行期C++类型系统,当时提到了它的应用场景有字符串映射到类型,本篇文章展示的是它的简单实现。

Metadata.h

#ifndef METADATA_H
#define METADATA_H


#include <assert.h>


#include <vector>
#include <string>
using namespace std;


/*
 * 成员变量的元数据
 */
struct FieldMetadata
{
	// 成员变量的名称
	string name;

	// 成员变量的类型
	string type;

	// 成员变量的地址
	size_t offset;

	FieldMetadata(string name, string type, size_t offset)
	{
		this->name = name;
		this->type = type;
		this->offset = offset;
	}
};


/*
 * 声明结构体类型
 */
#define Declare_Struct(class_type) \
private: \
 \
typedef class_type this_class; \
 \
template<int N> class Init_I \
{ \
public: \
	Init_I(vector<FieldMetadata>& metas) \
	{} \
}; \


/*
 * 定义结构体变量
 */
#define Define_Field(var_index, var_type, var_name) \
public: \
 \
var_type var_name; \
 \
private: \
 \
template<> class Init_I<var_index> \
{ \
public: \
	Init_I(vector<FieldMetadata>& metas) \
	{ \
		FieldMetadata fmd(#var_name, typeid(var_type).name(), offsetof(this_class, var_name)); \
		metas.insert(metas.begin(), fmd); \
	} \
}; \


/*
 * 定义结构体元数据
 */
#define Define_Metadata(var_count) \
public: \
 \
static vector<FieldMetadata> fieldinfo; \
 \
private: \
 \
template<int N> class CallInits \
{ \
public: \
	CallInits(vector<FieldMetadata>& metas) \
	{ \
		Init_I<N> in(metas); \
		CallInits<N-1> ci(metas); \
	} \
}; \
 \
template<> class CallInits<1> \
{ \
public: \
	CallInits(vector<FieldMetadata>& metas) \
	{ \
		Init_I<1> in(metas); \
	} \
}; \
 \
static vector<FieldMetadata> Init() \
{ \
	vector<FieldMetadata> fmd; \
	CallInits<var_count> ci(fmd); \
	return fmd; \
} \


/*
 * 实现结构体类型
 */
#define Implement_Struct(class_type) \
vector<FieldMetadata> class_type::fieldinfo = class_type::Init(); \


typedef unsigned char byte;


/*
 * 解析字符串到类型
 */
template<typename _T>
class ParaseToType
{
private:

	/*
	 * 内存值拷贝
	 */
	void CopyValueOnMemory(byte* memvalue, string type, string strvalue)
	{
		int off = strvalue.find('=');
		string name = strvalue.substr(0, off);
		string value = strvalue.substr(off + 1);

		if (type.compare(typeid(int).name()) == 0)
		{
			int vl = atoi(value.c_str());
			memcpy(memvalue, &vl, sizeof(int));
		}
		else if (type.compare(typeid(double).name()) == 0)
		{
			double vl = atof(value.c_str());
			memcpy(memvalue, &vl, sizeof(double));
		} 
		else if (type.compare(typeid(string).name()) == 0)
		{
			string* strmem = (string*)memvalue;
			strmem->append(value);
		}
		else
		{
			/*
			 * Only support the following types
			 * int, double, std::string
			 */
			assert(false);
		}
	}

public:

	/*
	 * 字符串的格式:"a=5;b=6.0f;c=766666666hhhhhgfdd"
	 */
	bool Parase(_T& t, string strvalue)
	{
		int stroffset = 0;

		for (auto iter = _T::fieldinfo.begin(); iter != _T::fieldinfo.end(); iter++)
		{
			int newoffset = strvalue.find(';', stroffset);
			string ty = strvalue.substr(stroffset, newoffset - stroffset);
		
			byte* th = (((byte*)&t) + (*iter).offset);
			CopyValueOnMemory(th, (*iter).type, ty);

			stroffset = newoffset + 1;
		}

		return true;
	}

};


#endif /*METADATA_H*/

Test.h

#pragma once


#include "Metadata.h"


struct Test
{
	Declare_Struct(Test)


	Define_Field(1, int, a)


	Define_Field(2, double, b)


	Define_Field(3, string, c)


	Define_Metadata(3)

};

Test.cpp

#include "Test.h"


Implement_Struct(Test)

main.cpp

#include "Test.h"
#include <assert.h>


template<typename _T> void PrintFieldInfo()
{
	printf("struct size : %d \n", sizeof(_T));
	printf("fieldinfo size : %d \n", _T::fieldinfo.size());
	printf("struct layout : \n");
	for (auto iter = _T::fieldinfo.begin(); iter != _T::fieldinfo.end(); iter++)
	{
		printf("%s, %s, %d \n", (*iter).name.c_str(), (*iter).type.c_str(), (*iter).offset);
	}
}


void main()
{
 	PrintFieldInfo<Test>();

	Test test;
	ParaseToType<Test>().Parase(test, "a=5;b=6.0f;c=766666666hhhhhgfdd");
	printf("a = %d, b = %f, c = %s \n", test.a, test.b, test.c.c_str());
}


展开阅读全文
打赏
0
11 收藏
分享
加载中
更多评论
打赏
0 评论
11 收藏
0
分享
返回顶部
顶部