创建允许轻松创建虚函数包装函数的 C++ 宏
Creating a C++ macro that allows for easy creation of virtual-function wrapper functions
我正在为一款旧游戏编写修改版本,并利用基本的逆向工程来实现我的目标。本质上,我一直在用自己的代码重新创建逆向工程游戏结构和界面的简单版本,将我的解决方案构建为共享对象并将其加载到游戏中。
我目前保持代码简单的解决方案是只在逆向工程接口的 "my versions" 中包含我需要的功能,为此我简单地写了一些类似的东西:
class GameManager {
public:
Game* GetGame();
Game* NextGame();
Game* PreviousGame();
int GameCount();
...
};
然后将函数实现为简单的包装器,通过虚方法中的索引调用原始函数 table。这样我就可以只包含我需要的等等
其中每一个基本上都包含 SomeType* SomeFunction(int param){ typedef thiscall blabla; call_vfunc(1,this,param); }
我想编写一个自动执行此过程的宏,一些简单易用的东西,例如 #define VFUNC(index, returnType, name, parameters)
。
我把它搞砸了,并做了几次失败的尝试来实现这个目标。最近的一个看起来像这样:
#define VFUNC(index, returnType, name, ...) returnType name(__VA_ARGS__) { return call_vfunc(index, this, ##__VA_ARGS__); }
这在函数不带任何参数时有效,但问题是一旦我引入参数(例如,写 VFUNC(12, int, someFunction, int someParam)
当我只想传递名称时,我最终传递了整个声明的参数。我一直在想一种方法,我可以把 (int a, int b, int c) 变成 (a,b,c) 这样我就可以把它们传递给 call_vfunc 但到目前为止我一无所有
TLDR: 我想写一个宏来自动创建这些虚函数 "wrapper functions".
谢谢。非常感谢任何帮助或指导 =)
如果我弄清楚了,我会及时通知您。
这是你的宏。
用法:
VFUNC(1, int, foo)
VFUNC_P(1, int, foo, (int,x))
VFUNC_P(1, int, foo, (int,x), (float,y))
实施:
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y
#define VA_COUNT(...) VA_COUNT_(__VA_ARGS__, 5, 4, 3, 2, 1,)
#define VA_COUNT_(p5, p4, p3, p2, p1, x, ...) x
#define FOR_EACH(macro, ...) CAT(FOR_EACH_, VA_COUNT(__VA_ARGS__))(macro, __VA_ARGS__)
#define FOR_EACH_1(m, p1 ) m p1
#define FOR_EACH_2(m, p1, p2 ) m p1 , m p2
#define FOR_EACH_3(m, p1, p2, p3 ) m p1 , m p2 , m p3
#define FOR_EACH_4(m, p1, p2, p3, p4 ) m p1 , m p2 , m p3 , m p4
#define FOR_EACH_5(m, p1, p2, p3, p4, p5) m p1 , m p2 , m p3 , m p4 , m p5
#define VFUNC_param_decl(type_, name_) ::std::enable_if_t<1, type_> name_
#define VFUNC_param_use(type_, name_) name_
#define VFUNC(index_, return_type_, name_) \
return_type_ name_() \
{ return call_vfunc(index_, this); }
#define VFUNC_P(index_, return_type_, name_, ...) \
return_type_ name_( FOR_EACH(VFUNC_param_decl, __VA_ARGS__) ) \
{ return call_vfunc(index_, this, FOR_EACH(VFUNC_param_use, __VA_ARGS__)); }
上面提供的简单实现有一些限制:
- 参数为 0 的函数有一个单独的宏。
- 您需要准备
O(n)
个样板宏,其中 n
是您要支持的函数参数的最大数量。上面的代码最多支持5个参数。
有一种方法可以解决这两个问题,但它需要更丑陋的宏。好像不太划算。
您可以重写这些宏以使用 Boost.Preprocessor 库。 (使用 BOOST_PP_VARIADIC_TO_SEQ
+ BOOST_PP_SEQ_FOR_EACH
或类似的东西。)
它可以让您摆脱样板文件(因为它将由图书馆提供)。
我正在为一款旧游戏编写修改版本,并利用基本的逆向工程来实现我的目标。本质上,我一直在用自己的代码重新创建逆向工程游戏结构和界面的简单版本,将我的解决方案构建为共享对象并将其加载到游戏中。
我目前保持代码简单的解决方案是只在逆向工程接口的 "my versions" 中包含我需要的功能,为此我简单地写了一些类似的东西:
class GameManager {
public:
Game* GetGame();
Game* NextGame();
Game* PreviousGame();
int GameCount();
...
};
然后将函数实现为简单的包装器,通过虚方法中的索引调用原始函数 table。这样我就可以只包含我需要的等等
其中每一个基本上都包含 SomeType* SomeFunction(int param){ typedef thiscall blabla; call_vfunc(1,this,param); }
我想编写一个自动执行此过程的宏,一些简单易用的东西,例如 #define VFUNC(index, returnType, name, parameters)
。
我把它搞砸了,并做了几次失败的尝试来实现这个目标。最近的一个看起来像这样:
#define VFUNC(index, returnType, name, ...) returnType name(__VA_ARGS__) { return call_vfunc(index, this, ##__VA_ARGS__); }
这在函数不带任何参数时有效,但问题是一旦我引入参数(例如,写 VFUNC(12, int, someFunction, int someParam)
当我只想传递名称时,我最终传递了整个声明的参数。我一直在想一种方法,我可以把 (int a, int b, int c) 变成 (a,b,c) 这样我就可以把它们传递给 call_vfunc 但到目前为止我一无所有
TLDR: 我想写一个宏来自动创建这些虚函数 "wrapper functions".
谢谢。非常感谢任何帮助或指导 =) 如果我弄清楚了,我会及时通知您。
这是你的宏。
用法:
VFUNC(1, int, foo)
VFUNC_P(1, int, foo, (int,x))
VFUNC_P(1, int, foo, (int,x), (float,y))
实施:
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y
#define VA_COUNT(...) VA_COUNT_(__VA_ARGS__, 5, 4, 3, 2, 1,)
#define VA_COUNT_(p5, p4, p3, p2, p1, x, ...) x
#define FOR_EACH(macro, ...) CAT(FOR_EACH_, VA_COUNT(__VA_ARGS__))(macro, __VA_ARGS__)
#define FOR_EACH_1(m, p1 ) m p1
#define FOR_EACH_2(m, p1, p2 ) m p1 , m p2
#define FOR_EACH_3(m, p1, p2, p3 ) m p1 , m p2 , m p3
#define FOR_EACH_4(m, p1, p2, p3, p4 ) m p1 , m p2 , m p3 , m p4
#define FOR_EACH_5(m, p1, p2, p3, p4, p5) m p1 , m p2 , m p3 , m p4 , m p5
#define VFUNC_param_decl(type_, name_) ::std::enable_if_t<1, type_> name_
#define VFUNC_param_use(type_, name_) name_
#define VFUNC(index_, return_type_, name_) \
return_type_ name_() \
{ return call_vfunc(index_, this); }
#define VFUNC_P(index_, return_type_, name_, ...) \
return_type_ name_( FOR_EACH(VFUNC_param_decl, __VA_ARGS__) ) \
{ return call_vfunc(index_, this, FOR_EACH(VFUNC_param_use, __VA_ARGS__)); }
上面提供的简单实现有一些限制:
- 参数为 0 的函数有一个单独的宏。
- 您需要准备
O(n)
个样板宏,其中n
是您要支持的函数参数的最大数量。上面的代码最多支持5个参数。
有一种方法可以解决这两个问题,但它需要更丑陋的宏。好像不太划算。
您可以重写这些宏以使用 Boost.Preprocessor 库。 (使用 BOOST_PP_VARIADIC_TO_SEQ
+ BOOST_PP_SEQ_FOR_EACH
或类似的东西。)
它可以让您摆脱样板文件(因为它将由图书馆提供)。