如何优雅的写C++代码(简单函数反射实现二)

1.反射函数的调用接口(getMethodField)

#define DECLARE_REFLECT_METHOD(CLASS, ...)        \
DEFINE_METHOD_MAP                                 \
sp<_MethodField> getMethodField(std::string name) \
{                                                 \
    auto method = __reflect_methods__[name];      \
    return MethodField::New(method, this);        \
}                                                 \
IMPLE_REFLECT_FUNCTION_DETECT(CLASS, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__)

getMethodField和java的反射方法类似,就是根据函数名字来从map表里面找到这个函数。

2.__reflect_methods__表结构:

//反射函数表
#define DEFINE_METHOD_MAP std::map<std::string,void *> __reflect_methods__;

//对象构造时,将反射函数类放入表中
#define DEFINE_GENERAL_ADD_METHOD(CLASS, METHOD)                                 \
template <typename ClassType, typename ReturnType, typename... Args>             \
void __add_method_##METHOD(ReturnType (ClassType::*)(Args...), std::string name) \
{                                                                                \
    __reflect_methods__[name] = (void *)(new reflect_##METHOD<Args...>(this));   \
}

//每个函数对应一个反射函数类
#define DEFINE_GENERAL_ADD_METHOD(CLASS, METHOD)                                 \
template <typename ClassType, typename ReturnType, typename... Args>             \
void __add_method_##METHOD(ReturnType (ClassType::*)(Args...), std::string name) \
{                                                                                \
    __reflect_methods__[name] = (void *)(new reflect_##METHOD<Args...>(this));   \
}

因为函数的入参和各种各样,无法定义一个统一的模板父类,所以这里粗暴的用void*来存储,使用的时候再强制转换会对应的反射函数类。

3.反射函数类基类

template<typename ...Args>
class __reflect_base__:public _Object {
public:
    virtual MethodResult call() = 0;

    template<typename ...Args2>
    MethodResult execution(Args2... args) {
        params = std::make_tuple(args...);
        return call();
    }

protected:
    std::tuple<Args...> params;
};

所有的反射函数都会自动生成一个基于__reflect_base__的反射函数类(最后存放在__reflect_methods__中),这个基类主要对外提供一个execution的函数(类似java反射的invoke),将可变参数转换成tuple,传递给子类(具体的反射函数类)。

4.反射函数类实现

template <typename... Args>                                                             \
class reflect_##METHOD : public __reflect_base__<Args...>                               \
{                                                                                       \
public:                                                                                 \
    reflect_##METHOD(_##CLASS *p) : pthis(p)                                            \
    {                                                                                   \
    }                                                                                   \
    MethodResult call()                                                                 \
    {                                                                                   \
        auto f = [&](auto &&...args) {                                                  \
            return pthis->METHOD(args...);                                              \
        };                                                                              \
        if constexpr (!__is_void_function__(&_##CLASS::METHOD))                         \
        {                                                                               \
            return MethodResult::New(std::apply(f, __reflect_base__<Args...>::params)); \
        }                                                                               \
        if constexpr (__is_void_function__(&_##CLASS::METHOD))                          \
        {                                                                               \
            std::apply(f, __reflect_base__<Args...>::params);                           \
            return nullptr;                                                             \
        }                                                                               \
    }                                                                                   \
                                                                                        \
private:                                                                                \
    _##CLASS *pthis;                                                                    \
};

这里主要关键点时要区分处函数是void还是非void,void函数不需要返回值,所以我们通过向上返回null来表示。其他函数的返回值存放在MethodResult的std::any类型中。确定是否是void函数使用了模板方法:

template <typename ClassType,typename ReturnType,typename... Args>
constexpr bool __is_void_function__(ReturnType (ClassType::*)(Args...)) {
    return false;
}

template <typename ClassType,typename... Args>
constexpr bool __is_void_function__(void (ClassType::*)(Args...)) {
    return true;
}

此外,如果是指用if判断,编译时是不会做判断的,导致可能出现函数类型不匹配等问题(模板会将同一种情况在if和非if的分支里都编译,结果就出错了),这里用了C++17的一个新语法特性(if constexpr),要求编译时就进行计算。

5.释放

由于我们__reflect_methods__里面存放的数据在析构的时候需要释放。但是由于__reflect_methods__里面我们存放的是void*数据,所以不能直接delete,需要转化为原来的类,所以我们为每个反射函数定义了一个释放类,这个释放类实际上是通过传入的函数类型来转化会需要释放分指针:

#define DEFINE_METHOD_CLASS(CLASS, METHOD)                                              \
template <typename ClassType, typename ReturnType, typename... Args>                    \
void __delete_method_##METHOD(ReturnType (ClassType::*)(Args...))                       \
{                                                                                       \
    void *p = __reflect_methods__[#METHOD];                                             \
    reflect_##METHOD<Args...> *v = (reflect_##METHOD<Args...> *)p;                      \
    delete v;                                                                           \
}                                                                                       \

使用如下:

void __release_reflect_method__()           \
{                                           \
    __delete_method_##M1(&_##CLASS::M1);    \
}                                           \

下面是一个函数反射使用的例子,个人觉得还可以吧。哈哈哈哈。

#include <stdio.h>
#include "Object.hpp"
#include "String.hpp"
#include "ReflectMethod.hpp"
#include "TestLog.hpp"
#include <any>

using namespace obotcha;

DECLARE_CLASS(testReflect_1) {
public:
    int test1() {
        return 1;
    }
    
    int test2(int v) {
        return v + 1;
    }
    
    int test3(int v,int j) {
        return v + j;
    }
    
    int test4(int v,int j,int k) {
        return v + j + k;
    }

    void test5(int v,int j,int *p) {
        *p = v + j;
    }

    DECLARE_REFLECT_METHOD(testReflect_1,test1,test2,test3,test4,test5)
};

void testReflect_Int_int_int() {
    Object t = (Object)testReflect_1::New();
    auto method = t->getMethodField("test1");
    auto result = method->execute();
    if(result->get<int>() != 1) {
        TEST_FAIL("testReflect_Int_int_int case1");
    }
    
    auto method2 = t->getMethodField("test2");
    auto result2 = method2->execute(100);
    if(result2->get<int>() != 101) {
        TEST_FAIL("testReflect_Int_int_int case2");
    }
    
    auto method3 = t->getMethodField("test3");
    auto result3 = method3->execute(1,2);
    if(result3->get<int>() != 3) {
        TEST_FAIL("testReflect_Int_int_int case3");
    }

    auto method4 = t->getMethodField("test4");
    auto result4 = method4->execute(1,2,3);
    if(result4->get<int>() != 6) {
        TEST_FAIL("testReflect_Int_int_int case4");
    }

    auto method5 = t->getMethodField("test5");
    int k = -1;
    method5->execute(1,2,&k);
    if(k != 3) {
        TEST_FAIL("testReflect_Int_int_int case5");
    }
    
    TEST_OK("testReflect_Int_int_int case100");
}

所以总结下来,整个反射实现的流程如下

1.生成流程:

DECLARE_REFLECT_METHOD(Class,Method1)->生成Method1的反射类->初始化时存入__reflect_methods__表中。

2.调用流程:

从__reflect_methods__表中找到对应的类->将可变参数转换成tuple->触发execute

Obotcha对应项目:

GitHub - wangsun1983/Obotcha: Tool library writen by C++17

相关实现:

Obotcha/lang/include/ReflectMethod.hpp at master · wangsun1983/Obotcha · GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值