如何将invoke_all中lambda的返回值打包为std::tuple?
实现返回std::tuple的invoke_all模板函数
要实现将所有模板参数传入的lambda应用于给定参数,并将返回值打包为std::tuple,可以根据C++版本选择不同的可靠实现方案:
C++17及以上版本(推荐:折叠表达式)
利用C++17的折叠表达式和std::invoke(支持任意可调用对象),可以写出简洁高效的代码:
#include <tuple> #include <functional> // 用于std::invoke template <typename... Callables, typename... Args> auto invoke_all(Args&&... args) { // 对每个可调用对象传入参数并调用,将所有返回值打包为tuple return std::make_tuple( std::invoke(std::declval<Callables>(), std::forward<Args>(args)...)... ); }
使用示例
#include <iostream> int main() { auto add = [](int a, int b) { return a + b; }; auto multiply = [](int a, int b) { return a * b; }; auto results = invoke_all<decltype(add), decltype(multiply)>(2, 3); // 输出:5, 6 std::cout << std::get<0>(results) << ", " << std::get<1>(results) << std::endl; return 0; }
C++11/14兼容版本(递归拼接tuple)
如果需要兼容更早的C++标准,可以通过递归模板拼接tuple的方式实现:
#include <tuple> #include <utility> // 递归终止条件:无待调用对象时返回空tuple template <typename... Args> std::tuple<> invoke_all(Args&&...) { return std::tuple<>{}; } // 递归处理:先调用第一个可调用对象,再拼接剩余对象的调用结果 template <typename FirstCallable, typename... RemainingCallables, typename... Args> auto invoke_all(Args&&... args) -> decltype( std::tuple_cat( std::make_tuple(std::declval<FirstCallable>()(std::forward<Args>(args)...)), invoke_all<RemainingCallables...>(std::forward<Args>(args)...) ) ) { return std::tuple_cat( std::make_tuple(std::declval<FirstCallable>()(std::forward<Args>(args)...)), invoke_all<RemainingCallables...>(std::forward<Args>(args)...) ); }
常见错误分析
你遇到的两种问题通常源于包展开的语法误用:
- 返回tuple大小为1:大概率是未对模板参数包
Callables...完成完整展开,比如std::make_tuple内的调用表达式末尾遗漏了...,导致仅生成单个元素的tuple。 - 包展开语法编译失败:可能是将展开符
...放在了错误位置(如括号外侧而非表达式末尾),或是在C++17之前尝试使用折叠表达式这类不兼容的语法。
内容的提问来源于stack exchange,提问作者Ralph Zhang
相关产品推荐
相关产品推荐

