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

C++23中移除std::function实现lambda包装器并修复隐式转换问题

C++23 Lambda包装器实现:移除std::function依赖并修复隐式转换问题

一、移除std::function依赖的lambda参数推导

无需借助std::function做类型擦除,直接解析lambda的operator()成员函数即可提取参数类型:

#include <tuple>
#include <type_traits>

// 基础模板,推导lambda的operator()类型
template<typename T>
struct lambda_traits : lambda_traits<decltype(&T::operator())> {};

// 针对默认const lambda的特化
template<typename Lambda, typename Ret, typename... Args>
struct lambda_traits<Ret (Lambda::*)(Args...) const> {
    using result_type = Ret;
    // 原始参数类型的元组
    using raw_args_tuple = std::tuple<Args...>;
    // 衰减后的参数类型元组(按需使用)
    using decayed_args_tuple = std::tuple<std::decay_t<Args>...>;
};

// 针对mutable lambda的特化(可选)
template<typename Lambda, typename Ret, typename... Args>
struct lambda_traits<Ret (Lambda::*)(Args...)> {
    using result_type = Ret;
    using raw_args_tuple = std::tuple<Args...>;
    using decayed_args_tuple = std::tuple<std::decay_t<Args>...>;
};

// 别名模板简化调用
template<typename T>
using lambda_raw_args_tuple_t = typename lambda_traits<T>::raw_args_tuple;

template<typename T>
using lambda_decayed_args_tuple_t = typename lambda_traits<T>::decayed_args_tuple;

二、实现支持隐式转换的lambda包装器

包装器核心逻辑是存储lambda实例,接受任意可转换为lambda参数的元组,通过std::apply完成参数解包与调用,确保隐式转换生效:

#include <functional> // 用于std::invoke

template<typename Lambda>
class lambda_wrapper {
    Lambda lambda_;

public:
    explicit lambda_wrapper(Lambda&& lambda) noexcept
        : lambda_(std::forward<Lambda>(lambda)) {}

    // 接受任意兼容的元组,用std::is_invocable_v确保参数可转换
    template<typename Tuple>
    requires std::is_invocable_v<Lambda, decltype(std::get<std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<Tuple>>>{}>(std::forward<Tuple>(std::declval<Tuple>()))...)>
    auto operator()(Tuple&& args) const {
        return std::apply(lambda_, std::forward<Tuple>(args));
    }
};

// 工厂函数简化包装器创建
template<typename Lambda>
auto make_lambda_wrapper(Lambda&& lambda) noexcept {
    return lambda_wrapper<std::decay_t<Lambda>>(std::forward<Lambda>(lambda));
}

三、测试验证

以下代码验证const std::string&参数的隐式转换场景:

#include <iostream>
#include <string>

int main() {
    // 定义带const std::string&参数的lambda
    auto print_and_sum = [](const std::string& str, int num) {
        std::cout << "String: " << str << ", Number: " << num << "\n";
        return str.size() + num;
    };

    // 创建包装器
    auto wrapper = make_lambda_wrapper(print_and_sum);

    // 传入tuple{"abc", 100},const char*自动隐式转换为std::string
    auto result = wrapper(std::make_tuple("abc", 100));
    std::cout << "Result: " << result << "\n";

    // 直接传入临时tuple
    wrapper(std::tuple{"hello", 200});

    return 0;
}

关键说明

  1. 移除std::function依赖:通过直接解析lambda的operator()成员函数,避免了类型擦除开销和不必要的依赖。
  2. 修复隐式转换:包装器不强制元组类型严格匹配lambda参数的衰减类型,而是通过std::is_invocable_v约束确保参数兼容;配合std::forward和std::apply完美转发,让临时对象(如const char*)能正常转换为const std::string&。
  3. 支持mutable lambda:添加对应的lambda_traits特化即可兼容mutable修饰的lambda。

内容的提问来源于stack exchange,提问作者Gene

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 08:34:59