You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

现有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:20:38