公开具有共享库的类型安全动态API
Exposing a type-safe dynamic API with a shared library
我正在为应用程序编程一个插件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
根据Kerrek的建议,您可以使用traits策略来解决您的问题。基本上,作为公共API的一部分,您必须包含为每个钩子id定义回调类型的结构。
// The default traits. If you don't want to have default traits comment body
// of this type out (including curly braces).
template <HookID id>
struct CallbackTraits
{
typedef void (*CallbackType)();
};
// Traits for MouseClick
template <>
struct CallbackTraits<HookID::MouseClick>
{
typedef void (*CallbackType)(int);
};
// Traits for MouseDoubleClick are the same
template <>
struct CallbackTraits<HookID::MouseDoubleClick> : CallbackTraits<HookID::MouseClick> {};
// Traits for MouseMove
template <>
struct CallbackTraits<HookID::MouseMove>
{
typedef void (*CallbackType)(int, int);
};
// actual hooking function
template <HookID id>
void SetEventHook(typename CallbackTraits<id>::CallbackType callback)
{
// do something with id and the callback
}
现在,您可以通过以下方式使用此API:
// handlers prototypes
void MouseClicked(int button);
void MouseMoved(int x, int y);
void SomeEvent();
int main()
{
// compiles ok
SetEventHook<HookID::MouseClick>(MouseClicked);
SetEventHook<HookID::MouseMove>(MouseMoved);
// won't compile - function signature incompatible
SetEventHook<HookID::MouseDoubleClick>(MouseMoved);
// will compile if you left default traits body uncommented
SetEventHook<HookID::HookWithNoTraitsDefined>(SomeEvent);
return 0;
}
我在这里上传了一个工作样本。
相关文章:
- 当我使用自定义类型创建动态数组时,即使使用字符串,它似乎也不起作用
- 具有自定义构造函数 (C++) 的类型的动态数组分配
- 创建类类型的动态分配数组,其中类不得具有默认构造函数
- 非类类型表达式的静态类型与动态类型之间的差异
- C++ 将抽象类型的动态分配对象传递给函数并存储在向量中
- 复合类型的动态数组
- 为表示一个或多个操作的C++函数的int参数寻找类型安全的替换
- 附加类型安全的子类std::string
- 什么是 c/c++ 中的类型安全
- 在模板类中使用'new'类型安全吗?
- 类型安全可变参数函数
- 用于验证类型的动态强制转换
- 类型安全 - all_of/ any_of/ none_of for std::tuple
- 如何在具有模板函数的类中使用类型安全的联合(变体)
- 将自动类型变量初始化为零.这种类型安全吗?
- 在 C++ 中强制实施类型安全,而无需使用额外的类
- 用于memcpy的类型安全C 包装器
- 以更健壮和类型安全的方式处理ASCII命令
- 是否有任何类型安全的、编译时检查的 printf 的实现
- 公开具有共享库的类型安全动态API