1

私は非常に静的な環境でプログラミングを行っており、問題/コードを可能な限り最善の方法で一般化し、クリーンにしてボイラープレート コードを回避したいと考えています。これは私の場合です。プログラム拡張機能の間に位置する変更システムを開発しています。拡張機能は API 呼び出しを転送します。変更内容がプログラムによって読み込まれると、関数ポインターだけで構成されるテーブルへのポインターを受け取ります。

struct APITable
{
 void (*MouseClick)(int, int);
 void (*MouseLeave)(bool);
 int (*MouseRet)(float, int);
 // And about a 200 more
 // ......
};

この関数では、コールバック関数/ポインターを自分自身 (つまりapiTable->MouseClick = &MyMouseClick;) を指すように設定します。複数のプラグインをサポートするために、このフレームワークを拡張しようとしています (一度に 1 つの変更しか許可されないため)。これは、追加のプラグインを (ライブラリとして) ロードし、ロードされたプラグインにすべてのコールバック ( など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、1 つはvoid関数用で、もう 1 つは戻り値を持つ関数用です。これはうまくいきますが、別の解決策を選ぶことは間違いありません (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 を返すものは別の本体を持っているため、2 つの関数テンプレートが必要です。これはrestype であると宣言できませんvoid。)

于 2012-05-21T18:39:10.673 に答える