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; }
关键说明
- 移除std::function依赖:通过直接解析lambda的
operator()成员函数,避免了类型擦除开销和不必要的依赖。 - 修复隐式转换:包装器不强制元组类型严格匹配lambda参数的衰减类型,而是通过
std::is_invocable_v约束确保参数兼容;配合std::forward和std::apply完美转发,让临时对象(如const char*)能正常转换为const std::string&。 - 支持mutable lambda:添加对应的
lambda_traits特化即可兼容mutable修饰的lambda。
内容的提问来源于stack exchange,提问作者Gene
相关产品推荐
相关产品推荐

