如何让C++编译器区分std::function<void()>与std::function<asio::awaitable<void>()>参数?
解决思路
方法1:模板参数推导+编译期分支
放弃直接用std::function作为参数类型,改用模板参数接收回调,通过编译期判断区分回调类型,彻底避免隐式转换的干扰:
#include <type_traits> #include <asio.hpp> template<typename Func> void register_callback(Func&& func) { using ReturnType = decltype(std::forward<Func>(func)()); if constexpr (std::is_convertible_v<ReturnType, asio::awaitable<void>>) { // 处理异步可等待回调的逻辑,例如用co_spawn执行 co_spawn(get_executor(), std::forward<Func>(func), asio::detached); } else if constexpr (std::is_same_v<ReturnType, void>) { // 处理普通无返回值回调的逻辑 std::forward<Func>(func)(); } else { static_assert(false, "仅支持返回void或asio::awaitable<void>的回调"); } }
这种方式会在编译期推导原始回调的真实类型,不会触发std::function的隐式转换,能精准区分两种回调类型。
方法2:添加显式标签参数
给两个重载函数增加不同的标签参数,要求调用者显式指定回调类型,从根源上避免误用:
#include <functional> #include <asio.hpp> struct awaitable_tag {}; struct void_tag {}; void register_callback(std::function<asio::awaitable<void>()> cb, awaitable_tag) { // 处理异步可等待回调 co_spawn(get_executor(), std::move(cb), asio::detached); } void register_callback(std::function<void()> cb, void_tag) { // 处理普通无返回值回调 cb(); }
调用时必须显式传入标签:
// 调用异步回调版本 register_callback(my_awaitable_cb, awaitable_tag{}); // 调用普通回调版本 register_callback(my_void_cb, void_tag{});
编译器不会自动转换std::function类型,完全杜绝意外传入错误类型的情况。
方法3:SFINAE+类型萃取
通过自定义类型萃取判断回调返回值,结合std::enable_if实现重载筛选:
#include <type_traits> #include <functional> #include <asio.hpp> template<typename Func> struct is_awaitable_callback { static constexpr bool value = std::is_convertible_v<decltype(std::declval<Func>()()), asio::awaitable<void>>; }; // 匹配返回asio::awaitable<void>的回调 template<typename Func> std::enable_if_t<is_awaitable_callback<Func>::value> register_callback(Func&& cb) { co_spawn(get_executor(), std::forward<Func>(cb), asio::detached); } // 匹配返回void且不是awaitable的回调 template<typename Func> std::enable_if_t<std::is_same_v<decltype(std::declval<Func>()()), void> && !is_awaitable_callback<Func>::value> register_callback(Func&& cb) { std::forward<Func>(cb)(); }
这种方式和方法1逻辑类似,都是利用编译期类型判断,确保只有匹配类型的回调能进入对应重载。
内容的提问来源于stack exchange,提问作者vipcxj
相关产品推荐
相关产品推荐

