Как мне создать packaged_task с параметрами? - PullRequest
8 голосов
/ 26 сентября 2011

После этого превосходного урока для фьючерсов , обещаний и упакованных заданий Я пришел к тому, что хотел подготовитьсобственная задача

#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();
}

Насколько я могу расшифровать сообщение об ошибке 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'

Мой вариант, как я предоставляю параметры для 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  };

хмм ... это яили это бета-gcc?

Ответы [ 2 ]

18 голосов
/ 26 сентября 2011

Во-первых, если вы объявляете 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;

Чтобы сделать то же самое с потоком, вы должны переместить задачу в поток и также передать аргументы:

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;

Кроме того, вы можете связать аргументы непосредственно перед созданием задачи, и в этом случае сама задача теперь имеет подпись, которая не принимает аргументов:

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

Опять же, вы можете сделать этои передать его в поток:

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;

Все эти примеры должны работать (и работают как с g ++ 4.6, так и с MSVC2010 и моей just :: thread реализацией библиотеки потоков),Если что-то не так, то есть ошибка в используемом вами компиляторе или библиотеке.Например, библиотека, поставляемая с g ++ 4.6, не может обрабатывать передаваемые объекты только для перемещения, такие как std::packaged_task до std::thread (и, следовательно, не обрабатывает 2-й и 4-й примеры), так как она использует std::bind в качестве детали реализации,и что реализация std::bind неправильно требует, чтобы аргументы были копируемыми.

3 голосов
/ 26 сентября 2011

Поскольку вы запускаете поток без аргументов, вы ожидаете, что задача будет запущена без аргументов, как если бы использовалось task1(). Следовательно, подпись, которую вы хотите поддержать, не int(int, int), а int(). В свою очередь это означает, что вы должны передать функтор, совместимый с этой подписью, конструктору std::packaged_task<int()>. Попробуйте:

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

Другая возможность:

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

, потому что конструктор std::thread может принимать аргументы. Здесь функтор, который вы передаете ему, будет использоваться, как если бы использовался task1(3, 11).

...