1

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

1 回答 1

3

这可能是不可能的,因为 C++ 是一种静态类型语言

如果只有 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为 type void。)

于 2012-05-21T18:39:10.673 回答