如何使用参数创建packaged_task?

tow*_*owi 8 c++ future packaged-task c++11

这个关于期货,承诺打包任务的优秀教程之后,我达到了我想要准备自己的任务的地步

#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();
}
Run Code Online (Sandbox Code Playgroud)

至于我可以解密gcc-4.7.0错误消息,它期望参数不同吗?但是怎么样?我尝试缩短错误消息:

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'
Run Code Online (Sandbox Code Playgroud)

我的变种是如何提供ackermann错误的参数的?或者它是错误的模板参数?我没有给3,11线程的创建参数,对吧?

更新其他不成功的变种:

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  };
Run Code Online (Sandbox Code Playgroud)

嗯...是我,还是beta-gcc?

Ant*_*ams 18

首先,如果您声明std::packaged_task接受参数,那么您必须将它们传递给operator(),而不是构造函数.在单个线程中,您可以这样做:

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

要对线程执行相同操作,必须任务移动到线程中,并传递参数:

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;
Run Code Online (Sandbox Code Playgroud)

或者,您可以在构造任务之前直接绑定参数,在这种情况下,任务本身现在具有不带参数的签名:

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

同样,您可以执行此操作并将其传递给线程:

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;
Run Code Online (Sandbox Code Playgroud)

所有这些示例都应该可行(并且可以使用g ++ 4.6和MSVC2010以及我的线程库的just :: thread实现).如果没有,那么您正在使用的编译器或库中存在错误.例如,库随克++ 4.6不能处理通过移动-仅作为对象,例如std::packaged_task,以std::thread(并因此无法处理的第二和第四实施例),因为它使用std::bind作为一个实现细节,并且该实现std::bind正确要求参数是可复制的.

  • 看一下`std :: bind`的要求,参数必须是可复制的.段落太长而无法在此粘贴,它是20.8.9.1.2函数模板bind [func.bind.bind]段落5.实际要求是存储的类型可以从传递的参数中移动构造和构造.虽然我确实记得GCC的一个错误的实施,确实需要CopyConstructible.(不是OP面临的问题.) (3认同)