现有Event类运行正常,如何实现可传任意类型参数的模板Event类?
实现支持任意类型参数的Event类
嘿,针对你的需求,我有个更优雅的解决方案——把Event改成模板类,结合std::optional处理可选参数场景,完全不用固定结构体,也不用在无参数时硬传0。下面是具体的实现思路和代码:
核心思路
- 把Event设计成模板类,用模板参数
T指定要传递的参数类型; - 用
std::optional<T>存储参数,天然支持“无参数”的场景(此时optional为空); - 保留原有的通知/等待逻辑,同时添加带参数的
notify重载,以及安全的参数获取接口; - 针对
void类型做特化,让无参数场景的使用更简洁。
完整实现代码
#include <mutex> #include <condition_variable> #include <optional> #include <utility> template <typename T = void> class Event { public: Event() : _signalled(false) {} // 无参数通知(兼容不需要传参的场景) void notify() { std::unique_lock<std::mutex> lock(_mutex); _signalled = true; _condvar.notify_all(); } // 带参数的通知,支持移动语义避免拷贝 void notify(T param) { std::unique_lock<std::mutex> lock(_mutex); _param = std::move(param); _signalled = true; _condvar.notify_all(); } // 等待事件触发,返回是否携带了参数 bool wait() { std::unique_lock<std::mutex> lock(_mutex); _condvar.wait(lock, [this] { return _signalled; }); return _param.has_value(); } // 获取参数(调用前务必确保wait返回true,或者事件已触发) const T& get_param() const { return _param.value(); } // 重置事件状态,允许重复使用 void reset() { std::unique_lock<std::mutex> lock(_mutex); _signalled = false; _param.reset(); } private: bool _signalled; std::mutex _mutex; std::condition_variable _condvar; std::optional<T> _param; }; // 针对void类型的特化,完全不需要存储参数,简化无参场景 template <> class Event<void> { public: Event() : _signalled(false) {} void notify() { std::unique_lock<std::mutex> lock(_mutex); _signalled = true; _condvar.notify_all(); } void wait() { std::unique_lock<std::mutex> lock(_mutex); _condvar.wait(lock, [this] { return _signalled; }); } void reset() { std::unique_lock<std::mutex> lock(_mutex); _signalled = false; } private: bool _signalled; std::mutex _mutex; std::condition_variable _condvar; };
使用示例
#include <string> #include <thread> #include <iostream> #include <chrono> int main() { // 无参数的Event,直接用Event<void> Event<void> void_event; std::thread t1([&]() { std::this_thread::sleep_for(std::chrono::seconds(1)); void_event.notify(); std::cout << "无参事件已通知\n"; }); void_event.wait(); std::cout << "收到无参事件\n"; t1.join(); // 传递int类型参数的Event Event<int> int_event; std::thread t2([&]() { std::this_thread::sleep_for(std::chrono::seconds(1)); int_event.notify(42); std::cout << "带int参数的事件已通知(参数42)\n"; }); if (int_event.wait()) { std::cout << "收到int参数:" << int_event.get_param() << "\n"; } t2.join(); // 传递自定义字符串类型的Event Event<std::string> str_event; std::thread t3([&]() { std::this_thread::sleep_for(std::chrono::seconds(1)); str_event.notify("Hello Event!"); std::cout << "带字符串参数的事件已通知\n"; }); if (str_event.wait()) { std::cout << "收到字符串参数:" << str_event.get_param() << "\n"; } t3.join(); return 0; }
为什么这是更优的方案?
- 完全支持任意类型:不管是基础类型、自定义结构体还是STL容器,都能无缝作为参数传递;
- 无参数场景零冗余:通过
Event<void>特化,不用传空值或0,直接调用无参接口,代码更清爽; - 线程安全有保障:保留了你原有的互斥锁+条件变量逻辑,多线程环境下使用没问题;
- 灵活度拉满:既支持带参数触发,也支持无参数触发,还能通过
reset()重复使用事件。
如果你的场景里永远都需要传递参数,也可以去掉std::optional,强制要求每次notify都传参——但std::optional的方式显然更灵活,完美贴合你“支持任意类型+兼容无参数”的需求。
内容的提问来源于stack exchange,提问作者user9589156
相关产品推荐
相关产品推荐

