如何正确初始化std::stop_callback?相关C++回调注册问题
问题解答
1. 修正watch_dog类中std::stop_callback的初始化方式
原代码核心问题是**std::stop_callback是模板类,声明时必须指定回调类型**,且初始化需保证参数传递合规。以下是两种可行修正方案:
方案一:使用Lambda表达式(推荐)
Lambda可通过std::function<void()>适配,代码简洁直观:
#include <stop_token> #include <functional> #include <iostream> class watch_dog { public: watch_dog(std::stop_token token) : m_token(std::move(token)), m_callback(m_token, [this](){ callback_proc(); }) { } private: void callback_proc() { std::cout << "an operation has completed." << std::endl; } std::stop_token m_token; std::stop_callback<std::function<void()>> m_callback; };
方案二:保留std::bind,用decltype推导类型
通过decltype获取std::bind返回类型,提前定义类型别名:
#include <stop_token> #include <functional> #include <iostream> class watch_dog; // 提前推导bind的类型 using BindCallbackType = decltype(std::bind(&watch_dog::callback_proc, static_cast<watch_dog*>(nullptr))); class watch_dog { public: watch_dog(std::stop_token token) : m_token(std::move(token)), m_callback(m_token, std::bind(&watch_dog::callback_proc, this)) { } private: void callback_proc() { std::cout << "an operation has completed." << std::endl; } std::stop_token m_token; std::stop_callback<BindCallbackType> m_callback; };
注意:用std::move传递stop_token可避免不必要拷贝,提升效率。
2. 不使用std::stop_callback注册回调的方法
存在多种替代方式,核心是手动监听std::stop_token的停止请求:
- 轮询检查:在循环中调用
stop_token::stop_requested(),返回true时执行回调逻辑。 - 配合条件变量:使用
stop_token::wait()方法,该方法会在停止请求到来时返回,随后触发回调。示例:void listen_stop(std::stop_token token) { std::condition_variable_any cv; std::mutex mtx; std::unique_lock lock(mtx); // 等待停止请求 token.wait(cv, []{ return false; }); // 执行回调 std::cout << "Stop requested!" << std::endl; } - 自定义回调机制:维护回调函数列表,在独立线程中监听
stop_token,检测到停止请求时遍历执行所有回调。
3. 确定std::bind的类型以声明std::stop_callback
通过decltype推导std::bind的返回类型,步骤如下:
- 提前声明类,用
static_cast<watch_dog*>(nullptr)模拟this指针类型(类内部声明时无法直接使用this)。 - 定义类型别名存储推导结果:
class watch_dog; using BindType = decltype(std::bind(&watch_dog::callback_proc, static_cast<watch_dog*>(nullptr))); - 使用该别名声明
std::stop_callback成员:std::stop_callback<BindType> m_callback;
也可在构造函数中直接用decltype(std::bind(...))作为模板参数,但提前定义类型别名能保证类型在成员声明时可见,更稳妥。
内容的提问来源于stack exchange,提问作者Alexey Starinsky
相关产品推荐
相关产品推荐

