C++函数式事件驱动框架:注册模板函数指针为默认事件动作
看起来你已经把核心的事件分发逻辑跑通了,给未注册事件加通用默认动作这个需求非常合理——既能避免未处理事件导致的异常,又能统一兜底逻辑。下面我给你一套具体的实现方案,完全贴合你说的函数式风格和模板化通用默认动作的需求:
实现C++函数式事件驱动框架的通用默认动作
1. 定义通用默认动作模板
先写一个通用的模板函数作为默认动作的基础实现,它可以适配任意事件类型,你可以根据需求修改兜底逻辑(比如打印日志、记录监控、抛出警告等):
#include <iostream> #include <typeinfo> template<typename EventType> void defaultEventAction(const EventType& event) { // 通用默认逻辑:输出事件类型信息,可按需扩展 std::cout << "[Default Action] Handling unregistered event type: " << typeid(EventType).name() << std::endl; }
2. 改造驱动类,添加默认动作注册机制
你的驱动类需要维护两套映射:一套是已注册的事件-动作,另一套是事件类型对应的默认动作。通过模板方法完成注册,并在分发时优先使用自定义动作,没有则 fallback 到默认动作:
#include <unordered_map> #include <typeindex> #include <functional> #include <stdexcept> class EventDriver { private: // 存储自定义事件动作:用type_index作为事件类型的唯一标识 std::unordered_map<std::type_index, std::function<void(const void*)>> customActions_; // 存储默认事件动作 std::unordered_map<std::type_index, std::function<void(const void*)>> defaultActions_; // 辅助工具:将强类型函数转换为类型擦除的通用函数 template<typename EventType> std::function<void(const void*)> wrapAction(std::function<void(const EventType&)> action) { return [action](const void* eventPtr) { action(*static_cast<const EventType*>(eventPtr)); }; } public: // 原有:注册自定义事件动作 template<typename EventType> void registerAction(std::function<void(const EventType&)> action) { customActions_[std::type_index(typeid(EventType))] = wrapAction(action); } // 新增:注册指定事件类型的默认动作,默认使用通用模板 template<typename EventType> void registerDefaultAction(std::function<void(const EventType&)> action = defaultEventAction<EventType>) { defaultActions_[std::type_index(typeid(EventType))] = wrapAction(action); } // 事件分发核心逻辑 template<typename EventType> void dispatchEvent(const EventType& event) { const auto typeIdx = std::type_index(typeid(EventType)); // 优先使用自定义动作 auto customIt = customActions_.find(typeIdx); if (customIt != customActions_.end()) { customIt->second(&event); return; } // 没有自定义动作则尝试默认动作 auto defaultIt = defaultActions_.find(typeIdx); if (defaultIt != defaultActions_.end()) { defaultIt->second(&event); return; } // 若连默认动作都没注册,可选择抛出异常或静默忽略 throw std::runtime_error("No action or default action registered for this event type"); } };
3. 使用示例
下面是一个简单的使用场景,展示自定义动作、默认动作的注册和事件分发:
// 定义示例事件类 class MouseClickEvent { public: int x, y; MouseClickEvent(int x_, int y_) : x(x_), y(y_) {} }; class KeyPressEvent { public: char key; KeyPressEvent(char k) : key(k) {} }; int main() { EventDriver driver; // 给鼠标点击事件注册自定义动作 driver.registerAction<MouseClickEvent>([](const MouseClickEvent& e) { std::cout << "[Custom Action] Mouse clicked at (" << e.x << ", " << e.y << ")\n"; }); // 给键盘按下事件注册通用默认动作 driver.registerDefaultAction<KeyPressEvent>(); // 分发已注册自定义动作的事件 driver.dispatchEvent(MouseClickEvent(150, 250)); // 分发只有默认动作的事件 driver.dispatchEvent(KeyPressEvent('S')); return 0; }
4. 可选扩展:全局默认动作
如果希望所有未注册的事件都使用同一个兜底逻辑,而不是按类型单独注册,可以给驱动类添加全局默认动作的支持:
// 在EventDriver类中新增成员和方法 private: std::function<void(const std::type_index&, const void*)> globalDefaultAction_; public: void setGlobalDefaultAction(std::function<void(const std::type_index&, const void*)> action) { globalDefaultAction_ = std::move(action); } // 修改dispatchEvent中的兜底逻辑: else { if (globalDefaultAction_) { globalDefaultAction_(typeIdx, &event); } else { throw std::runtime_error("No action, default action, or global default action registered"); } }
对应的全局默认动作可以这样设置:
driver.setGlobalDefaultAction([](const std::type_index& type, const void*) { std::cout << "[Global Default] Handling unregistered event: " << type.name() << std::endl; });
内容的提问来源于stack exchange,提问作者shajen
相关产品推荐
相关产品推荐

