我正在为应用程序编写插件 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);
这种方法的问题是它不是类型安全的,我不能直接使用模板(因为这是在运行时作为库完成的)。我不想为每个事件(例如SetHookMouseMove(void (*)(int, int))
等等)公开 300 个不同的函数。我的最后一个想法是,插件有一个实用模板函数,它使这种类型安全,但我不确定如何以简单的方式实现它(并且没有样板代码):
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