如何简化EnTT事件注册:通过函数指针推导事件类型
简化EnTT事件注册的实现方案
完全可以实现你想要的简化写法,核心是通过模板元编程从函数指针里自动提取事件类型,不用手动指定Event模板参数。下面是具体实现步骤和代码:
核心思路
利用模板推导机制,编写辅助模板解析函数指针的签名,提取出其中的事件参数类型,再自动调用EnTT的sink和connect接口。
具体实现
1. 编写类型提取辅助模板
这个模板负责从函数指针中提取事件类型(假设函数的第一个参数就是事件类型):
// 基础模板,用于匹配不同函数签名 template<typename Func> struct EventTypeFromFunc; // 特化:匹配普通函数(参数为const Event&) template<typename Event> struct EventTypeFromFunc<void(*)(const Event&)> { using type = Event; }; // 特化:匹配类成员函数(参数为const Event&) template<typename Class, typename Event> struct EventTypeFromFunc<void(Class::*)(const Event&)> { using type = Event; }; // 别名模板,简化类型提取的写法 template<typename Func> using EventTypeFromFunc_t = typename EventTypeFromFunc<Func>::type;
2. 实现简化的registerEvent函数
基于上面的类型提取模板,写出两种调用方式的函数:
方式一:运行时传入函数指针
#include <entt/entt.hpp> template<typename Func> void registerEvent(entt::dispatcher& dispatcher, Func func) { // 自动提取事件类型 using Event = EventTypeFromFunc_t<Func>; dispatcher.sink<Event>().connect(func); }
方式二:编译期指定函数指针(模板参数形式)
template<auto Func> void registerEvent(entt::dispatcher& dispatcher) { using Event = EventTypeFromFunc_t<decltype(Func)>; dispatcher.sink<Event>().connect<Func>(); }
使用示例
// 定义事件类型 struct MyEvent {}; struct AnotherEvent {}; // 普通事件处理函数 void OnMyEvent(const MyEvent&) { // 处理逻辑 } // 类成员事件处理函数 class MySystem { public: void OnAnotherEvent(const AnotherEvent&) { // 处理逻辑 } }; int main() { entt::dispatcher dispatcher; MySystem system; // 调用方式1:传入函数指针 registerEvent(dispatcher, &OnMyEvent); // 调用方式2:模板参数指定函数指针 registerEvent<&OnMyEvent>(dispatcher); // 成员函数的注册(需要绑定实例) registerEvent(dispatcher, std::bind(&MySystem::OnAnotherEvent, &system)); // 或者扩展成员函数专用版本(见下方补充) }
补充:成员函数直接注册的扩展
如果想更简洁地注册成员函数,可以添加重载:
template<typename Class, typename Event> void registerEvent(entt::dispatcher& dispatcher, void(Class::*func)(const Event&), Class* instance) { dispatcher.sink<Event>().connect(func, instance); } // 使用示例 registerEvent(dispatcher, &MySystem::OnAnotherEvent, &system);
注意事项
- 如果你的事件处理函数参数不是
const Event&(比如值传递、非const引用),需要对应修改EventTypeFromFunc的特化模板,匹配对应的函数签名。 - 确保EnTT版本支持你使用的
connect重载,不同版本的EnTT在接口细节上可能略有差异。
内容的提问来源于stack exchange,提问作者confused cmake user
相关产品推荐
相关产品推荐

