当Lambda返回值为void时,如何用其结果调用另一个Lambda?
处理返回void的Lambda的Pipeline调用问题
这个问题确实挺常见的——当你想用一个返回void的Lambda的「执行结果」(其实是没有返回值)去触发另一个Lambda时,常规的传参逻辑直接就卡壳了,毕竟void类型没法作为参数传递。不过咱们可以通过模板元编程实现一个通用的pipeline工具,既能处理void返回值的特殊情况,也能支持你提到的tuple展开传参需求,下面就一步步来实现它。
第一步:定义tuple类型判断工具
首先咱们需要一个元编程工具来判断某个类型是不是std::tuple,后续用来处理tuple展开的逻辑:
#include <tuple> #include <type_traits> #include <utility> // 判断是否为tuple类型的辅助元函数 template<typename T> struct is_tuple : std::false_type{}; template<typename... T> struct is_tuple<std::tuple<T...>> : std::true_type{}; // 简化版的constexpr变量,方便代码中直接使用 template<typename T> constexpr bool is_tuple_v = is_tuple<T>::value;
第二步:实现分情况的辅助调用逻辑
接下来要写核心的辅助调用函数,通过SFINAE根据第一个Lambda的返回类型,分三种情况处理:
- 返回
void:执行第一个Lambda后直接调用第二个Lambda,无需传参 - 返回
tuple:将tuple展开后传入第二个Lambda - 返回普通值:直接把结果传给第二个Lambda
// 辅助调用函数1:处理第一个Lambda返回void的情况 template<typename S, typename T> auto invoke_pipeline(S&& source, T&& target) -> std::enable_if_t<std::is_void_v<decltype(std::forward<S>(source()))>> { std::forward<S>(source)(); std::forward<T>(target)(); } // 内部辅助函数:负责展开tuple并调用第二个Lambda template<typename T, typename Tuple, std::size_t... Idx> auto invoke_with_tuple(T&& target, Tuple&& tuple, std::index_sequence<Idx...>) { return std::forward<T>(target)(std::get<Idx>(std::forward<Tuple>(tuple))...); } // 辅助调用函数2:处理第一个Lambda返回tuple的情况 template<typename S, typename T> auto invoke_pipeline(S&& source, T&& target) -> std::enable_if_t<!std::is_void_v<decltype(std::forward<S>(source()))> && is_tuple_v<decltype(std::forward<S>(source()))>> { auto result = std::forward<S>(source)(); return invoke_with_tuple( std::forward<T>(target), std::move(result), std::make_index_sequence<std::tuple_size_v<decltype(result)>>{} ); } // 辅助调用函数3:处理普通返回值的情况 template<typename S, typename T> auto invoke_pipeline(S&& source, T&& target) -> std::enable_if_t<!std::is_void_v<decltype(std::forward<S>(source()))> && !is_tuple_v<decltype(std::forward<S>(source()))>> { auto result = std::forward<S>(source)(); return std::forward<T>(target)(std::move(result)); }
第三步:实现最终的pipeline函数
最后咱们把两个Lambda打包成tuple捕获,返回一个新的Lambda,执行时调用上面的辅助逻辑:
// 最终的pipeline函数:生成组合后的Lambda template<typename S, typename T> constexpr decltype(auto) pipeline(S&& source, T&& target) { return [callables = std::make_tuple(std::forward<S>(source), std::forward<T>(target))]() mutable { return invoke_pipeline(std::get<0>(std::move(callables)), std::get<1>(std::move(callables))); }; }
示例代码演示
咱们用三种场景测试一下这个工具:
#include <iostream> int main() { // 场景1:第一个Lambda返回void auto void_lambda = []() { std::cout << "执行返回void的Lambda\n"; }; auto print_lambda = []() { std::cout << "执行第二个Lambda\n"; }; auto pipeline_void = pipeline(void_lambda, print_lambda); pipeline_void(); // 场景2:第一个Lambda返回普通值 auto add_lambda = []() { return 3 + 5; }; auto multiply_lambda = [](int val) { return val * 2; }; auto pipeline_normal = pipeline(add_lambda, multiply_lambda); std::cout << "普通返回值结果:" << pipeline_normal() << "\n"; // 场景3:第一个Lambda返回tuple auto tuple_lambda = []() { return std::make_tuple(10, 20); }; auto sum_tuple_lambda = [](int a, int b) { return a + b; }; auto pipeline_tuple = pipeline(tuple_lambda, sum_tuple_lambda); std::cout << "Tuple展开结果:" << pipeline_tuple() << "\n"; return 0; }
运行后会输出:
执行返回void的Lambda 执行第二个Lambda 普通返回值结果:16 Tuple展开结果:30
内容的提问来源于stack exchange,提问作者Andreas Loanjoe
相关产品推荐
相关产品推荐

