一种更通用的编译期反射

来源:互联网 发布:防止微信屏蔽分享域名 编辑:程序博客网 时间:2024/05/01 02:26

magic_get编译期反射的局限性

magic_get可以实现编译期获取pod类型,是以一种“无痕”的方式实现的,即无需宏、特殊标记、专门工具。看起来确实很精妙,不过也存在一些局限性,比如只能支持pod类型,不能获取反射类型的字段名,也不支持遍历访问对象字段。这些局限性导致magic_get无法在更广泛的环境下应用。

一种更通用的编译期反射方法

基本的反射功能应该包括根据索引获取字段,根据索引获取字段名,遍历对象的所有字段,支持所有类型的对象。
一种更通用的编译期反射应该支持下面这些。

struct city_t{    int id;    double num;};REFLECTION(city_t, id,num);struct person_t{    int id;    double num;    city_t city;};REFLECTION(person_t, id,num,city);int main(){    city_t city = {20, 3.5};    person_t p = {1,2.5,city};    //get filed name by index    constexpr auto filed_name = get_name<person_t, 1>();     //get value by index    auto val = get<1>(p);    //apply algorithm to every member of struct    for_each(p, [](auto& v, size_t I)    {        v*=10;        std::cout<< v <<std::endl;    }); }

这种编译期反射有几个优点:使用简单,通用,接口完备,支持所有类型的对象而不仅仅是pod类型,非侵入式。

存在的不足之处在于需要定义一个宏,这个非侵入式的宏是用来获取对象的元数据的,是不可少的。magic_get之所以不需要定义宏,是因为利用了pod类型内存连续的特殊性,可以直接转换为内存连续的tuple。虽然这个tuple提供了元数据,但是这个元数据是有缺陷的,即只有字段值而没有其他信息。而定义宏的方式则提供了丰富而完整的元数据信息,会更通用和方便。

由于这种编译期反射方式把对象元数据和元数据的操作分离了,所以用户可以基于这个通用的编译期反射做自己感兴趣的事情。

编译期反射可以用来做什么

编译期反射非常适合用来做ORM引擎和序列化/反序列化引擎,以ORM为例,我们可以基于反射来做多种数据库的ORM,比如sqlite, mysql, postgresql,oracle,sqlserver等数据库。有了ORM之后使用起来会非常方便,给用户提供简单通用的接口,把数据库差异、对象和实体相互转换等繁琐的细节都屏蔽了。以基于编译期反射实现sqlite的ORM为例:

struct person{    int id;    char* name;    int age;    blob address;};REFLECTION(person, id,name,age,address);int main(){    dbng db; //sqlite数据库对象    int result = db.create_database("test.db");    const char* create_tb = "create table if not exists person(id integer, name text, age integer, address blob);";    result = db.exceute(create_tb);    //插入数据,参数平铺方式    const char* insert_person = "insert into person(id,name,age,address) values(?,?,?,?);";    db.excecute(insert_person, 2, "jim", 30, blob{"zhuhai", 6});    //插入数据,对象方式,通过编译期反射实现对象到实体的映射    person p = {3, "mike", 40, blob{"zhuhai", 6}};    db.excecute(insert_person, p);    //数据查询,通过编译期反射实现实体到对象的映射    const char* query_all = "select * from person";    db.query<person>(query_all);    //查询部分数据,由于查询的字段是任意组合,所以需要使用tuple来作为任意实体到对象的映射          const char* query_some = "select name, age from person";    db.query<std::tuple<char*, int>>(query_some);}

从上面的例子可以看到,基于编译期反射实现的ORM接口非常简单、通用和强大,你几乎可以用这几个接口做任何事。即使对于其他数据库,接口仍然保持不变,这将会极大地提高数据库开发效率和降低数据库开发的难度,这就是编译期反射的威力!

关于编译期反射的实现原理和ORM的实现原理敬请关注即将开始的purecpp社区第一期技术公开课!

0 0
原创粉丝点击