我正在非常静态的环境中进行编程,并希望尽可能以最佳方式概括问题/代码,使其干净并避免使用任何样板代码。这是我的情况;我正在开发一个位于程序和扩展之间的修改系统,其中扩展将转发API调用。当我的修改被程序加载时,我收到一个指向完全由函数指针组成的表的指针。
struct APITable
{
void (*MouseClick)(int, int);
void (*MouseLeave)(bool);
int (*MouseRet)(float, int);
// And about a 200 more
// ......
};
在这个函数中,我设置回调函数/指针,指向我自己(即apiTable->MouseClick = &MyMouseClick;
)。我正在尝试扩展此框架(因为它一次只允许一次修改)来支持多个插件。这是通过加载其他插件(作为库)然后将所有回调(例如MouseClick
)转发到加载的插件来完成的。这是一个例子;
void MyMouseClick(int x, int y)
{
bool blockOriginal = false;
// Iterate over all plugins
if(plugin_function_is_defined_pre)
blockOriginal = call_plugin_callback_pre(x, y);
if(!blockOriginal)
EngineMouseClick(x, y); // This is the programs "engine" function, which I have to call if I want normal execution flow
// Iterate over all plugins
if(plugin_function_is_defined_post)
call_plugin_callback_post(x, y);
}
这是一个非常简化的程序,但我认为它可以告诉所有需要讲述的内容。由于我有200多个函数,我无法复制和粘贴所有这些样板代码。正常过程可能是#define
,一个用于void
函数,一个用于具有返回值的函数。虽然这有效,但我肯定更喜欢另一种解决方案(由于C ++是一种静态类型的语言,这可能是不可能的。)
重点是;我想以干净有效的方式概括这个过程,避免任何样板代码。值得一提的是,函数可以覆盖原始函数返回值,在回调函数中未声明为void。
所以要把它剥去骨头:Program->MyExtension->Plugins&Engine
注意:我不想要使用除C ++之外的任何语言,并在必要时使用C ++ 11功能!
编辑:如果感兴趣,这是我的修改由程序加载的方式:
extern "C" ModLoad(APITable * apiTable)
{
apiTable->MouseClick = &MyMouseClick;
apiTable->MouseLeave = &MyMouseLeave;
// And so on
// ...
}
答案 0 :(得分:3)
这可能是不可能的,因为C ++是一种静态类型语言
如果只有C ++有一种静态类型的方式来编写可以为不同参数定制的通用代码,那么可能是某种模板工具? ; - )
N.B。我不知道你打算如何处理返回值或blockOriginal
或回调的意图,所以这只是一个草图。
template<typename Res, typename... Args>
Res call_plugin_func(Enum funcID, Res (*origFunc)(Args...), Args... args)
{
Res res = Res();
bool blockOriginal = false;
// Iterate over all plugins, looking for defs of funcID
if(plugin_function_is_defined_pre)
blockOriginal = call_plugin_callback_pre(args...);
if(!blockOriginal)
res = origFunc(args...);
// Iterate over all plugins
if(plugin_function_is_defined_post)
call_plugin_callback_post(args...);
return res;
}
template<typename... Args>
void call_plugin_func(Enum funcID, void (*origFunc)(Args...), Args... args)
{
bool blockOriginal = false;
// Iterate over all plugins, looking for defs of funcID
if(plugin_function_is_defined_pre)
blockOriginal = call_plugin_callback_pre(args...);
if(!blockOriginal)
origFunc(args...);
// Iterate over all plugins
if(plugin_function_is_defined_post)
call_plugin_callback_post(args...);
}
void MyMouseClick(int x, int y)
{
call_plugin_func(ID_MyMouseClick, &EngineMouseClick, x, y);
}
(需要两个函数模板,因为一个返回的void具有不同的主体,它不能将res
声明为类型void
。)