C++中能否通过模板实现适配不同监听器接口的通用事件收集器?
解决方案
完全可以实现通用的收集器逻辑,核心思路是通过模板封装通用的事件存储、访问逻辑,配合少量宏适配不同监听器的虚函数名,彻底消除重复代码。
1. 通用基类模板实现
首先封装所有收集器共用的事件存储、查询逻辑,这部分和具体监听器、虚函数名无关:
#include <vector> template <typename EventT> class EventCollectorBase { public: const std::vector<EventT>& events() const { return m_events; } protected: std::vector<EventT> m_events; };
2. 宏定义自动生成收集器类
由于不同监听器的虚函数名是编译期标识符,无法通过模板直接操作,我们用一个极简的宏来自动生成对应收集器的重写逻辑:
#define DEFINE_EVENT_COLLECTOR(CollectorName, ListenerT, EventT, CallbackFuncName) \ class CollectorName : public ListenerT, public EventCollectorBase<EventT> \ { \ private: \ void CallbackFuncName(const EventT& event) override { \ m_events.emplace_back(event); \ } \ }
3. 使用方式
新增对应监听器的收集器仅需一行代码,完全不需要重复编写类结构:
// 生成ListenerA对应的事件收集器 DEFINE_EVENT_COLLECTOR(EventACollector, ListenerA, EventA, onEventA); // 生成ListenerB对应的事件收集器 DEFINE_EVENT_COLLECTOR(EventBCollector, ListenerB, EventB, onEventB);
使用逻辑和你之前手写的收集器完全一致:
// 测试使用示例 EventACollector a_collector; // 注册到事件触发模块 test_module.register_listener(&a_collector); // 触发事件后读取收集结果 for (const auto& event : a_collector.events()) { // 执行测试断言、分析逻辑 ASSERT_EQ(event.id, expected_id); }
补充说明
如果不想使用宏,也可以通过模板特化的方式实现,只是每次需要手动写重写方法的逻辑:
// 通用收集器模板 template <typename ListenerT, typename EventT> class EventCollector : public ListenerT, public EventCollectorBase<EventT> {}; // 特化实现ListenerA的回调 template <> void EventCollector<ListenerA, EventA>::onEventA(const EventA& event) override { m_events.emplace_back(event); }
内容的提问来源于stack exchange,提问作者nyarlathotep108
相关产品推荐
相关产品推荐

