c++ - 泛化 C++ 模式

标签 c++ linux templates gcc c++11

我在一个非常静态的环境中编程,希望以尽可能最好的方式概括问题/代码,使其干净并避免任何样板代码。这是我的情况;我正在开发一个位于程序扩展 之间的修改系统,其中扩展将转发 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
 // ...
}

最佳答案

which might not be possible since C++ is a statically typed language

要是 C++ 有一种静态类型的方式来编写可以针对不同参数进行自定义的通用代码就好了,也许是某种模板工具? ;-)

注意我不知道您打算如何处理返回值,也不知道 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 类型。)

关于c++ - 泛化 C++ 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10690591/

相关文章:

c# - 如何从 C++/C# 调用此 DLL 函数

linux shell流重定向直接运行命令列表

linux - 如何编辑 PYTHONPATH?

php - 如何在 Blade foreach循环中获取迭代次数

c++ - 模板方法和模板类 C++

templates - 模板化成员函数的地址

c++ - 如果服务器未运行,async_connect 成功

c++ - 线程安全三角测量库

c++ - 动态分配数组的大小

linux - 管道传输时,没有此类文件或目录。每个命令分别工作,但在管道传输时则不行