C++实现编译器静态反射配合json自动序列化

StaticReflect

在C++中,反射(Reflection)并不是语言原生支持的特性。但在某些场景下,比如序列化、对象打印、GUI编辑等,我们确实需要能够遍历一个类的成员变量。本文将介绍如何通过宏和模板技术,实现一个轻量级的成员变量反射机制。

本文使用CPP的宏+模板实现了对结构体成员/函数的静态反射,配合json库,实现自动序列化。

设计目标

我们希望达到这样的使用效果:

// 方式一:在结构体内部使用(侵入式)
struct Student {
    int age;
    std::string name;
    REFLECT(age, name);  // 内部
};

// 方式二:在结构体外部使用(非侵入式)
struct Teacher {
    int id;
    std::string title;
};
REFLECT_TYPE(Teacher, id, title);  // 外部

我们想要获取结构体的各个成员的名称,那我们就要以一种方式告诉结构体都有哪些成员,让这些内容“存储”起来,即REFLECT_TYPEREFLECT_TYPE的作用。

实现

基本引入

我们以侵入式的反射为例。

侵入式就是直接在结构体的内部进行修改定义,插入一些内容,实现反射。

#define REFLECT__TYPE_PER_MEMBER_PTR(x) func(#x, &This::x);

#define REFLECT(...)                                                           \
    template <class This, class Func>                                          \
    static constexpr void foreach_members_ptr(Func &&func) {                   \
        REFLECT__PP_FOREACH(REFLECT__PER_MEMBER_PTR, __VA_ARGS__)              \
    };

先直接看侵入式预处理生成的结果:

struct Student {
    int age;
    std::string name;

    void ff() {
        std::cout << "hello world" << std::endl;
    }

    template <class This, class Func> static constexpr void foreach_members_ptr(Func &&func) { func("age", &This::age); func("name", &This::name); };;
};

我们在结构体内部使用了REFLECT宏生成了对应的模板函数,函数模板参数分别是This,指示当前类型,第二个模板参数是Func,传入参数接受一个Func类型的函数,对结构体的每一个成员统一实行func操作。

注意模板第一个参数名是This,目的是对于宏REFLECT__TYPE_PER_MEMBER_PTR中替换过程中,对于类型名保持一致,同理,REFLECT宏的func和REFLECT__TYPE_PER_MEMBER_PTR替换文本的func保持一致。

#define REFLECT__TYPE_PER_MEMBER_PTR(x) func(#x, &This::x);

对于一个x,替换为func(#x,&This::x)。#x 会得到x的字符串,#age会被替换为“age”。

比如我们传入REFLECT的age,经过REFLECT__TYPE_PER_MEMBER_PTR替换,替换为func("age",&This::age).

这里的REFLECT__PP_FOREACH的作用是,对于传入的每个参数,都进行统一的REFLECT__PER_MEMBER_PTR操作。比如

// 初始
REFLECT__PP_FOREACH(REFLECT__PER_MEMBER_PTR,age,name)
// 处理后
REFLECT__PER_MEMBER_PTR(age) REFLECT__PER_MEMBER_PTR(name)

这里结合我们需要传入的func,替换REFLECT__PER_MEMBER_PTR为

func(#age,&This::age) func(#name,&This::name)

结合传入的类型以Student为例

func(#age,&Student::age) func(#name,&Student::name)
func("age",&Student::age) func("name",&Student::name)

那么如何实现REFLECT__PP_FOREACH呢?

REFLECT__PP_FOREACH的实现

一开始我们可能会想写出如下:

#define REFLECT__PP_FOREACH(f, ...)                                            \
		f(__VA_ARGS__)

但是这样直接将可变的参数传入了函数f中类似f(1,2,3,4,5...)而不是我们需要的f(1) f(2) f(3)...

但是如果是确定参数个数的话就很容易写了,比如

#define REFLECT__PP_FOREACH_1(f, _1) f(_1)
#define REFLECT__PP_FOREACH_2(f, _1, _2) f(_1) f(_2)
#define REFLECT__PP_FOREACH_3(f, _1, _2, _3) f(_1) f(_2) f(_3)
...

但是如果有更多个参数呢?很简单,一个一个写出来..别笑,因为boost的反射库也是这么实现的.

#define REFLECT__PP_FOREACH_1(f, _1) f(_1)
#define REFLECT__PP_FOREACH_2(f, _1, _2) f(_1) f(_2)
#define REFLECT__PP_FOREACH_3(f, _1, _2, _3) f(_1) f(_2) f(_3)
#define REFLECT__PP_FOREACH_4(f, _1, _2, _3, _4) f(_1) f(_2) f(_3) f(_4)
#define REFLECT__PP_FOREACH_5(f, _1, _2, _3, _4, _5)                           \
    f(_1) f(_2) f(_3) f(_4) f(_5)
#define REFLECT__PP_FOREACH_6(f, _1, _2, _3, _4, _5, _6)                       \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6)
#define REFLECT__PP_FOREACH_7(f, _1, _2, _3, _4, _5, _6, _7)                   \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7)
#define REFLECT__PP_FOREACH_8(f, _1, _2, _3, _4, _5, _6, _7, _8)               \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8)
#define REFLECT__PP_FOREACH_9(f, _1, _2, _3, _4, _5, _6, _7, _8, _9)           \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9)
#define REFLECT__PP_FOREACH_10(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10)     \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10)
#define REFLECT__PP_FOREACH_11(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)                           \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)
#define REFLECT__PP_FOREACH_12(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12)                      \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12)
#define REFLECT__PP_FOREACH_13(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13)                 \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13)
#define REFLECT__PP_FOREACH_14(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14)            \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14)
#define REFLECT__PP_FOREACH_15(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15)       \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15)
#define REFLECT__PP_FOREACH_16(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16)  \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16)
#define REFLECT__PP_FOREACH_17(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17)                                         \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17)
#define REFLECT__PP_FOREACH_18(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17, _18)                                    \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18)
#define REFLECT__PP_FOREACH_19(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17, _18, _19)                               \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19)
#define REFLECT__PP_FOREACH_20(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17, _18, _19, _20)                          \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20)

我们这里提前写出了20个参数及以内的宏处理定义。

但是现在的问题是,如何确定参数__VA_ARGS__的个数,才能选择对应的宏定义。比如5个参数就选择REFLECT__PP_FOREACH_5.

我们确定可变参数的参数个数的实现如下:

#define REFLECT__PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,   \
    _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...)                       \
    N

#define REFLECT__PP_NARGS(...)                                                 \
    REFLECT__PP_NARGS_IMPL(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12,    \
        11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

我们以当有5个参数的时候为例,REFLECT__PP_NARGS(n1,n2...n5)->REFLECT__PP_NARGS_IMPL(n1,n2...n5,20,19,18,17...1)。
对于REFLECT__PP_NARGS_IMPL,如果没有参数,那么前二十个参数正好对抵了20,19,18,17...1,N为空
但如果__VA_ARGS__有5个,那么传入REFLECT__PP_NARGS_IMPL的那20,19,18...1就会被顶到右侧5个单位
那么这样的话,5就正好顶到了N的位置,我们就能得知参数的个数为5.

REFLECT\_\_PP_NARGS(n1,n2,n3,n4,n5) -> n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,n18,n19,n2
REFLECT\_\_PP_NARGS_IMPL(n1,n2,n3,n4,n5,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
我们把上面的实际和下面的参数进行比对,我们发现N正好被顶到和5相对应的位置,那么返回参数个数N,即是5.
REFLECT__PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,_12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...)  N

知道参数的话,我们根据共同的宏前缀REFLECT__PP_FOREACH_再连接个数,就是对应个数参数的宏处理函数。

#define REFLECT__PP_CONCAT_2(x, y) x##y
#define REFLECT__PP_CONCAT(x, y) REFLECT__PP_CONCAT_2(x, y)

下面之所以分为CONCAT_1和CONCAT_2多次连接,是因为##会阻止宏展开,多次嵌套可以先展开参数最后连接

// 错误:一次CONCAT
#define CONCAT(x, y) x##y
/*
	一开始CONCAT(REF,FLECT)的时候,REF和FLECT并没有展开,而是直接被##连接在一起
	比如CONCAT(REFLECT__PP_FOREACH_,REFLECT__PP_NARGS(__VA_ARGS__))->REFLECT__PP_FOREACH_REFLECT__PP_NARGS(__VA_ARGS__)
	很奇怪对吧,没有按照设想将N求出5,然后和REFLECT__PP_FOREACH_前缀连接
*/

// 正确:两次CONCAT
#define CONCAT_2(x, y) x##y
#define CONCAT(x, y) CONCAT_2(x, y)
/*
	使用CONCAT嵌套CONCAT_2宏之后,传入参数:CONCAT(REFLECT__PP_FOREACH_,REFLECT__PP_NARGS(__VA_ARGS__))
	这时候根据定义CONCAT还需要替换为CONCAT_2的定义,但是传入对应的参数x,y的时候需要求值,所以REFLECT__PP_NARGS(__VA_ARGS__)就会被求值得出5.这时候传入CONCAT_2(REFLECT__PP_FOREACH_,5)
	最后得出REFLECT__PP_FOREACH_5
*/

至此,根据可变参数确定参数个数求出对应宏函数定义并且调用的代码如下:

REFLECT__PP_CONCAT(REFLECT__PP_FOREACH_, REFLECT__PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__)

替换为

REFLECT__PP_FOREACH_5(f,__VA_ARGS__)

那么我们的REFLECT__PP_FOREACH宏是不是终于可以写成如下形式了?

#define REFLECT__PP_FOREACH(f,...) REFLECT__PP_CONCAT(REFLECT__PP_FOREACH_, REFLECT__PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__)

其实不然,原因和上面CONCAT_1和CONCAT_2的原因一样,可能是宏定义参数没有被展开,而是直接连接的原因。因此我们也和前者解决方法一样,套一层。

#define REFLECT__PP_EXPAND_2(...) __VA_ARGS__
#define REFLECT__PP_EXPAND(...) REFLECT__PP_EXPAND_2(__VA_ARGS__)
#define REFLECT__PP_FOREACH(f, ...)                                            \
    REFLECT__PP_EXPAND(REFLECT__PP_CONCAT(                                     \
        REFLECT__PP_FOREACH_, REFLECT__PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__))

至此REFLECT__PP_FOREACH宏完成。

使用

根据在结构内部宏定义生成的模板函数foreach_members_ptr,我们传入我们想要处理的函数,可以是lambda函数,但是参数要和宏定义func(#x, &This::x)相对应。

其中第一个参数传入的是const char*类型,实际就是我们传入REFLECT(age,name)中的age或者name经过宏#处理之后得到的字符串"age"或"name".

第二个参数就是结构体内部的对应名称x的值的指针。

struct Student {
    int age;
    std::string name;
    void ff() {
        std::cout << "hello world" << std::endl;
    }
    REFLECT(age, name);
};

template <typename T>
std::string serialize(T const &t) {
    Json::Value root;
    T::template foreach_members_ptr<T>([&](char const *key, auto &&value) { root[key] = t.*value; });
    return root.toStyledString();
}
/*
	这里这个侵入式的宏中,foreach_members_ptr是成员的模板函数,
	struct Student {
        template <typename T>
        static void func(T t) {}
	};
    Student::func<int>(10);  // 编译错误!
    如果这样的话,编译器会困惑:< 是小于号还是模板参数列表的开始?
    
    Student::template func<int>(10);  // 正确,告诉编译器:"func 是一个模板,后面的 < 是模板参数列表的开始"
*/

我们以jsoncpp为例,我们想要自动将结构体中所有的成员的名称和值序列化为json格式,,即键-值对结构。

那我们的处理就是将成员名称对应的字符串作为键,成员值作为值。

故传入函数

[&](char const *key, auto &&value) { 
    root[key] = t.*value; 
}

foreach_members_ptr根据传入的这个lambda函数,经过我们上述一系列的宏的替换,对每个成员执行这个lambda函数。

template <class This, class Func> 
static constexpr void foreach_members_ptr(Func &&func) { 
    func("age", &This::age); func("name", &This::name); 
};
--------------------------------->
template<class Student,Class Func>
static constexpr void foreach_members_ptr(Func&&func){
    [&root]("age",&Student::age){
        root["age"] = *&Student::age;
    };
    [&root]("name",&Student::name){
        root["name"] = *&Student::name;
    }
}
--------------------------------->
struct __lambda_unique_type {
    Json::Value& root;
    const Student& t;
    
    template<typename T>
    void operator()(char const *key, T &&value) const {
        root[key] = t.*value;  // value 是成员指针,t.*value 获取成员值
    }
} lambda{root, t};
--------------------------------->
struct {
    Json::Value& root;
    const Student& t;

    void operator()(char const *key, int Student::*ptr) const {
        root[key] = t.*ptr;  // age 是 int
    }

    void operator()(char const *key, std::string Student::*ptr) const {
        root[key] = t.*ptr;  // name 是 string
    }
} lambda{root, t};

非侵入式

实现和侵入式几乎一致,这里不做赘述。

#define REFLECT_TYPE(Type, ...)                                                \
    template <>                                                                \
    struct reflect::reflect_traits<Type> {                                     \
        using This = Type;                                                     \
        template <typename Func>                                               \
        static constexpr void foreach_members_ptr(Func &&func) {               \
            REFLECT__PP_FOREACH(REFLECT__TYPE_PER_MEMBER_PTR, __VA_ARGS__)     \
        }                                                                      \
    };

唯一的区别在于非侵入的话,我们就需要定义成外部的全局的一个模板结构体reflect_traits,内部实现一个针对Type的成员函数foreach_members_ptr

使用的话就是如下

template <typename T>
std::string serialize2(T const &t) {
    Json::Value root;
    reflect::reflect_traits<T>::foreach_members_ptr(
        [&](char const *key, auto ptr) {
            using PtrType = decltype(ptr);
                root[key] = t.*ptr;
        });
    return root.toStyledString();
}

测试

#include "reflect.hpp"
#include <iostream>
#include <json/json.h>
#include <string>

struct Student {
    int age;
    std::string name;

    void ff() {
        std::cout << "hello world" << std::endl;
    }

    REFLECT(age, name);
};

REFLECT_TYPE(Student, age, name, ff);

template <typename T>
std::string serialize(T const &t) {
    Json::Value root;
    T::template foreach_members_ptr<T>(
        [&](char const *key, auto &&value) { root[key] = t.*value; });
    return root.toStyledString();
}

template <typename T>
std::string serialize2(T const &t) {
    Json::Value root;
    reflect::reflect_traits<T>::foreach_members_ptr(
        [&](char const *key, auto ptr) {
            using PtrType = decltype(ptr);

            if constexpr (std::is_member_function_pointer_v<PtrType>) {
                // 函数,只存函数名
                root[key] = std::string(key);

            } else {
                root[key] = t.*ptr;
            }
        });
    return root.toStyledString();
}

int main(int, char **) {
    Student student = {
        .age = 10,
        .name = "Tom",
    };
    std::string s = serialize(student);
    std::string s2 = serialize2(student);
    std::cout << s << std::endl;
    std::cout << s2 << std::endl;
}

{
    "age" : 10,
    "name" : "Tom"
}

{
    "age" : 10,
    "ff" : "ff",
    "name" : "Tom"
}

源代码

#pragma once

namespace reflect {

template <typename T>
struct reflect_traits { };

#define REFLECT__PP_FOREACH_1(f, _1) f(_1)
#define REFLECT__PP_FOREACH_2(f, _1, _2) f(_1) f(_2)
#define REFLECT__PP_FOREACH_3(f, _1, _2, _3) f(_1) f(_2) f(_3)
#define REFLECT__PP_FOREACH_4(f, _1, _2, _3, _4) f(_1) f(_2) f(_3) f(_4)
#define REFLECT__PP_FOREACH_5(f, _1, _2, _3, _4, _5)                           \
    f(_1) f(_2) f(_3) f(_4) f(_5)
#define REFLECT__PP_FOREACH_6(f, _1, _2, _3, _4, _5, _6)                       \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6)
#define REFLECT__PP_FOREACH_7(f, _1, _2, _3, _4, _5, _6, _7)                   \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7)
#define REFLECT__PP_FOREACH_8(f, _1, _2, _3, _4, _5, _6, _7, _8)               \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8)
#define REFLECT__PP_FOREACH_9(f, _1, _2, _3, _4, _5, _6, _7, _8, _9)           \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9)
#define REFLECT__PP_FOREACH_10(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10)     \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10)
#define REFLECT__PP_FOREACH_11(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11)                           \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)
#define REFLECT__PP_FOREACH_12(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12)                      \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11) f(_12)
#define REFLECT__PP_FOREACH_13(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13)                 \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13)
#define REFLECT__PP_FOREACH_14(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14)            \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14)
#define REFLECT__PP_FOREACH_15(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15)       \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15)
#define REFLECT__PP_FOREACH_16(                                                \
    f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16)  \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16)
#define REFLECT__PP_FOREACH_17(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17)                                         \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17)
#define REFLECT__PP_FOREACH_18(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17, _18)                                    \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18)
#define REFLECT__PP_FOREACH_19(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17, _18, _19)                               \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19)
#define REFLECT__PP_FOREACH_20(f, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10,     \
    _11, _12, _13, _14, _15, _16, _17, _18, _19, _20)                          \
    \f(_1) f(_2) f(_3) f(_4) f(_5) f(_6) f(_7) f(_8) f(_9) f(_10) f(_11)       \
        f(_12) f(_13) f(_14) f(_15) f(_16) f(_17) f(_18) f(_19) f(_20)

#define REFLECT__PP_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,   \
    _12, _13, _14, _15, _16, _17, _18, _19, _20, N, ...)                       \
    N

#define REFLECT__PP_NARGS(...)                                                 \
    REFLECT__PP_NARGS_IMPL(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12,    \
        11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define REFLECT__PP_CONCAT_2(x, y) x##y
#define REFLECT__PP_CONCAT(x, y) REFLECT__PP_CONCAT_2(x, y)
#define REFLECT__PP_EXPAND_2(...) __VA_ARGS__
#define REFLECT__PP_EXPAND(...) REFLECT__PP_EXPAND_2(__VA_ARGS__)
#define REFLECT__PP_FOREACH(f, ...)                                            \
    REFLECT__PP_EXPAND(REFLECT__PP_CONCAT(                                     \
        REFLECT__PP_FOREACH_, REFLECT__PP_NARGS(__VA_ARGS__))(f, __VA_ARGS__))

#define REFLECT__PER_MEMBER_PTR(x) func(#x, &This::x);
#define REFLECT__TYPE_PER_MEMBER_PTR(x) func(#x, &This::x);

#define REFLECT_TYPE(Type, ...)                                                \
    template <>                                                                \
    struct reflect::reflect_traits<Type> {                                     \
        using This = Type;                                                     \
        static constexpr bool has_member() {                                   \
            return true;                                                       \
        }                                                                      \
        template <typename Func>                                               \
        static constexpr void foreach_members_ptr(Func &&func) {               \
            REFLECT__PP_FOREACH(REFLECT__TYPE_PER_MEMBER_PTR, __VA_ARGS__)     \
        }                                                                      \
    };

#define REFLECT(...)                                                           \
    template <class This, class Func>                                          \
    static constexpr void foreach_members_ptr(Func &&func) {                   \
        REFLECT__PP_FOREACH(REFLECT__PER_MEMBER_PTR, __VA_ARGS__)              \
    };

}; // namespace reflect
posted @ 2026-03-21 10:41  大胖熊哈  阅读(8)  评论(0)    收藏  举报