如何从std::async任务返回std::tuple?如何启动返回std::tuple的成员函数作为std::async任务?
关于std::async返回std::tuple及调用类成员函数的问题解答
1. 如何从std::async任务返回std::tuple?
其实这个操作和返回普通数据类型没太大区别——std::async会自动把std::tuple包装进std::future中,你只需要通过future.get()获取到返回的tuple,再用std::get<索引>来访问其中的元素就行。
举个简单的示例:
#include <iostream> #include <future> #include <tuple> #include <vector> #include <numeric> // 普通函数,返回std::tuple std::tuple<long, double> calculate_stats(const std::vector<int>& nums) { long sum = std::accumulate(nums.begin(), nums.end(), 0L); double avg = static_cast<double>(sum) / nums.size(); return std::make_tuple(sum, avg); } int main() { std::vector<int> data = {1,2,3,4,5}; // 用std::async启动任务,得到future对象 auto fut = std::async(std::launch::async, calculate_stats, data); // 获取返回的tuple auto [sum, avg] = fut.get(); // C++17结构化绑定,更直观 // 或者用std::get访问(兼容旧标准): // long sum = std::get<0>(fut.get()); // double avg = std::get<1>(fut.get()); std::cout << "Sum: " << sum << ", Average: " << avg << std::endl; return 0; }
这里要注意:如果用C++17及以上,用结构化绑定可以直接解构tuple,代码更简洁;如果是旧标准,就用std::get<N>来逐个提取元素。
2. 如何将返回std::tuple的类成员函数作为std::async任务启动?
类成员函数和普通函数的区别在于,它需要一个类实例(即this指针)作为隐含的第一个参数。所以在调用std::async时,你需要明确传递类对象的引用(或指针),再指定成员函数的地址,最后传成员函数的参数。
另外,我注意到你提供的Foo类代码里有个小问题:成员函数calc中,if块里重新定义了sum和avg局部变量,这会覆盖外层的变量,导致最终返回的是初始的0和0.0。我先修正这个问题,再给完整示例:
#include <iostream> #include <future> #include <tuple> #include <vector> #include <numeric> class Foo { bool calc_enabled; // 重命名成员变量,避免和成员函数名冲突 public: Foo(bool b) : calc_enabled(b) {} // 修正后的成员函数:不再定义局部同名变量 std::tuple<long, double> calc(const std::vector<int>& a) { long sum = 0; double avg = 0.0; if (calc_enabled) { sum = std::accumulate(a.begin(), a.end(), 0L); avg = static_cast<double>(sum) / a.size(); } return std::make_tuple(sum, avg); } }; int main() { Foo foo(true); std::vector<int> data = {10,20,30,40}; // 方式1:传递类对象的引用(用std::ref包装,避免拷贝) auto fut1 = std::async(std::launch::async, &Foo::calc, std::ref(foo), data); // 方式2:传递类对象的指针 auto fut2 = std::async(std::launch::async, &Foo::calc, &foo, data); // 获取结果 auto [sum1, avg1] = fut1.get(); std::cout << "Sum (ref): " << sum1 << ", Average (ref): " << avg1 << std::endl; auto [sum2, avg2] = fut2.get(); std::cout << "Sum (ptr): " << sum2 << ", Average (ptr): " << avg2 << std::endl; return 0; }
这里的关键点:
- 成员函数的地址要写
&Foo::calc(必须加&,不能省略) - 传递类对象时,如果你想让async任务使用原对象(而不是拷贝),要用
std::ref(foo)或者直接传指针&foo;如果传值的话,会拷贝一个新的Foo对象,任务操作的是拷贝后的对象。 - 同样,获取返回的tuple后,用结构化绑定或
std::get来提取元素即可。
内容的提问来源于stack exchange,提问作者Peter Abraham
相关产品推荐
相关产品推荐

