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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:45:06