C++模板参数包场景下packaged_task构造函数参数为何变为引用?
关于std::packaged_task构造函数报错的问题解析
先来看你提供的代码:
#include <future> template <class F, class... Args> void do_something(F f, Args... args) { using return_type = typename std::result_of<F(Args...)>::type; // 为何下方代码报错? std::packaged_task<return_type(Args...)> task(f, args...); } int func(int a, int b) { return a + b; } int main() { do_something(func, 1, 2); }
编译时触发的错误如下:
error: no matching function for call to 'std::packaged_task<int(int, int)>::packaged_task(int (*&)(int, int), int&, int&)'
8 | std::packaged_task<return_type(Args...)> task(f, args...);
咱们拆解两个核心问题:为什么参数会变成引用?以及代码到底错在哪?
一、为什么参数会被推导成引用类型?
你疑惑的Args...明明是int、int,但传递给构造函数时却变成了int&、int&,这和左值与转发引用的推导规则有关:
- 在模板函数
do_something里,f和args...都是函数的形参,不管你传入的实参是左值还是右值,形参本身都是左值(可以被取地址的对象)。 std::packaged_task的构造函数是一个模板构造函数,签名大致是这样的:
这里的template <class F> explicit packaged_task(F&& f);F&&是转发引用(通用引用),当你传递左值给它时,模板参数F会被推导为左值引用类型。所以你的函数指针f会被推导为int(*&)(int,int)(函数指针的左值引用),args里的两个int会被推导为int&,这就是错误提示里引用类型的来源。
二、真正的错误根源:用错了packaged_task的构造方式
这才是关键!std::packaged_task的构造函数只需要接收可调用对象本身,不需要提前传入调用参数!它的作用是把可调用对象包装起来,之后你可以通过task(args...)的方式触发执行,或者交给线程异步执行。
修正后的代码应该是这样的:
#include <future> template <class F, class... Args> void do_something(F f, Args... args) { using return_type = typename std::result_of<F(Args...)>::type; // 只传入可调用对象f,用std::move避免拷贝(可选但推荐) std::packaged_task<return_type(Args...)> task(std::move(f)); // 如果需要立即执行,直接调用task并传入参数 task(args...); // 还可以获取future来获取执行结果 auto result_future = task.get_future(); } int func(int a, int b) { return a + b; } int main() { do_something(func, 1, 2); }
补充:如果想提前绑定参数怎么办?
如果你希望把可调用对象和参数提前绑定在一起,不需要后续传参,可以用std::bind或者lambda表达式,再把绑定后的对象传给packaged_task:
#include <future> #include <functional> template <class F, class... Args> void do_something(F f, Args... args) { using return_type = typename std::result_of<F(Args...)>::type; // 用bind绑定函数和参数 auto bound_func = std::bind(f, args...); // 此时packaged_task的签名是return_type(),因为不需要再传参数 std::packaged_task<return_type()> task(std::move(bound_func)); // 直接调用,无需传参 task(); } int func(int a, int b) { return a + b; } int main() { do_something(func, 1, 2); }
内容的提问来源于stack exchange,提问作者Jaebum
相关产品推荐
相关产品推荐

