How to create packaged_task with parameters?

Following this great tutorial for futures, promises, and packaged tasks, I got to the point where I wanted to prepare my own task

#include <iostream> #include <future> using namespace std; int ackermann(int m, int n) { // might take a while if(m==0) return n+1; if(n==0) return ackermann(m-1,1); return ackermann(m-1, ackermann(m, n-1)); } int main () { packaged_task<int(int,int)> task1 { &ackermann, 3, 11 }; // <- error auto f1 = task1.get_future(); thread th1 { move(task1) }; // call cout << " ack(3,11):" << f1.get() << endl; th1.join(); } 

As far as I can decrypt the gcc-4.7.0 error message, it expects arguments differently? But how? I am trying to shorten the error message:

 error: no matching function for call to 'std::packaged_task<int(int, int)>::packaged_task(<brace-enclosed initializer list>)' note: candidates are: std::packaged_task<_Res(_ArgTypes ...)>::---<_Res(_ArgTypes ...)>&&) --- note: candidate expects 1 argument, 3 provided ... note: cannot convert 'ackermann' (type 'int (*)(int, int)') to type 'std::allocator_arg_t' 

Is my option the way I provide parameters for ackermann incorrectly? Or is this the wrong template parameter? I do not give parameters 3,11 create a thread, right?

Update other failed options:

 packaged_task<int()> task1 ( []{return ackermann(3,11);} ); thread th1 { move(task1) }; packaged_task<int()> task1 ( bind(&ackermann,3,11) ); thread th1 { move(task1) }; packaged_task<int(int,int)> task1 ( &ackermann ); thread th1 { move(task1), 3,11 }; 

hmm ... is it me or is it beta gcc?

+7
source share
2 answers

First, if you declare std::packaged_task to accept arguments, you must pass them to operator() , not the constructor. In one thread, you can:

 std::packaged_task<int(int,int)> task(&ackermann); auto f=task.get_future(); task(3,11); std::cout<<f.get()<<std::endl; 

To do the same with the thread, you must move the task to the stream and pass arguments too:

 std::packaged_task<int(int,int)> task(&ackermann); auto f=task.get_future(); std::thread t(std::move(task),3,11); t.join(); std::cout<<f.get()<<std::endl; 

Alternatively, you can link the arguments just before you build the task, in which case the task itself now has a signature that takes no arguments:

 std::packaged_task<int()> task(std::bind(&ackermann,3,11)); auto f=task.get_future(); task(); std::cout<<f.get()<<std::endl; 

Again you can do this and pass it to the stream:

 std::packaged_task<int()> task(std::bind(&ackermann,3,11)); auto f=task.get_future(); std::thread t(std::move(task)); t.join(); std::cout<<f.get()<<std::endl; 

All these examples should work (and do both with g ++ 4.6, and with MSVC2010 and just :: thread the implementation of the thread library). If this is not the case, then there is an error in the compiler or library. For example, the library shipped with g ++ 4.6 cannot process transferred objects only for moving, such as from std::packaged_task to std::thread (and thus cannot process the 2nd and 4th examples), since it uses std::bind as part of the implementation, and that the implementation of std::bind incorrectly requires the arguments to be copied.

+16
source

Since you start the thread with no arguments, you expect the task to start without arguments, as if task1() . Therefore, the signature you want to support is not int(int, int) , but int() . This in turn means that you must pass a functor compatible with this signature to the std::packaged_task<int()> constructor. Try:

 packaged_task<int()> task1 { std::bind(&ackermann, 3, 11) }; 

Another possibility:

 packaged_task<int(int,int)> task1 { &ackermann }; auto f1 = task1.get_future(); thread th1 { move(task1), 3, 11 }; 

because the constructor std::thread can take arguments. Here the functor that you pass to it will be used as if task1(3, 11) .

+3
source

All Articles