推广C ++模式

时间:2012-05-21 18:27:42

标签: 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
 // ...
}

1 个答案:

答案 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。)