アプリケーション用のプラグインAPIインターフェースをプログラミングしています。プラグインは、実行時に共有ライブラリとしてロードされます。次のようなインターフェイスを介してアプリケーションAPIにアクセスできます。
class IPluginAPI
{
public:
virtual bool IsPluginsLoaded(void) = 0;
virtual bool IsHookingEnabled(void) = 0;
// And about 50 more methods
};
MouseClick
プラグインは、特定のイベント(などMouseScroll
)を「リッスン」するように要求できます。これらの関数は、合計で300を超えるさまざまなイベントを構成します。通常、私は次のようなことをします。
extern "C" void SetEventHooks(APITable& table)
{
table.MouseClick = &PluginMouseClickEvent;
table.MouseMove = &PluginMouseMoveEvent;
}
関数SetEventHooks
はプラグインライブラリ内にあり、アプリケーションから呼び出されますが、プラグインは関数をポイントすることで目的の関数をリッスンできます。これは私が使用したい方法ではありませんが、代わりにある種の抽象化を提供したいと思います。これは私が念頭に置いていたものです:
// Interface IPluginAPI supplies a 'SetEventHook` method such as
void SetEventHook(HookID id, void * callback);
この場合HookID
、すべての関数IDを含む強い型の列挙型です。
enum class HookID
{
MouseClick,
MouseMove,
// ...
};
したがって、プラグインはこの関数を使用してイベントをリッスンします。
pluginAPI->SetEventHook(ID::MouseClick, &myCallback);
このアプローチの問題は、タイプセーフではなく、テンプレートを直接使用できないことです(これは実行時にライブラリとして実行されるため)。イベントごとに300の異なる関数を公開したくありません(例SetHookMouseMove(void (*)(int, int))
など)。私の最後のアイデアは、プラグインにはこのタイプを安全にするユーティリティテンプレート関数があるということですが、これを簡単な方法で(ボイラープレートコードなしで)実装する方法がわかりません。
template <typename T>
SetEventHook(HookID id, T callback)
{
if(typeof(T) == decltype(/* function type of the ID */))
gPluginAPI->SetEventHook(id, callback);
else static_assert("INVALID FUNCTION TYPE");
}
簡単に言えば、完全な関数テーブルや各イベントの300を超えるメソッドを公開せずに、プラグインが動的なタイプセーフな方法で特定のイベントにフックできるようにするにはどうすればよいですか?
注:簡略化のために関数ポインターを使用しましたが、使用したいstd::function