Используя MSVC2012,
Следующий код будет скомпилирован и запущен, как и ожидалось
std::packaged_task< int() > task( []()->int{ std::cout << "hello world" << std::endl; return 0; } );
std::thread t( std::move(task) );
t.join();
в то время как следующий код не сможет скомпилировать и запустить
std::packaged_task< void() > task( [](){ std::cout << "hello world" << std::endl; } );
std::thread t( std::move(task) );
t.join();
Почему это так?
Редактировать:
В качестве обходного пути можно использовать std :: обещание, чтобы получить std :: future для функции, которая возвращает void
std::promise<void> promise;
auto future = promise.get_future();
std::thread thread( [](std::promise<void> &p){ std::cout << "hello world" << std::endl; p.set_value(); }, std::move(promise) );
future.wait();
Обратите внимание, что в библиотеке vs2012 есть ошибка с std :: thread, которая заставляет вас передавать обещание в виде ссылки на l-значение и перемещать обещание, оно не будет компилироваться, если вы передадите обещание по значению или r- значение ссылки. Предположительно, это связано с тем, что реализация использует std :: bind (), которая ведет себя не так, как ожидается.
Это ошибка в MSVC2012. Существует довольно много ошибок в реализации библиотеки потоков, которая поставляется с MSVC2012. Я опубликовал частичный список в своем блоге, сравнивая его с моей коммерческой библиотекой Just :: Thread: http://www.justsoftwaresolutions.co.uk/news/just-thread-v1.8.0-released.html
Это работает в gcc 4.7.2:
#include <thread>
#include <future>
#include <iostream>
int main() {
std::packaged_task< void() > task( [](){ std::cout << "hello world" << std::endl; } );
std::thread t( std::move(task) );
t.join();
std::packaged_task< int() > task2( []()->int{ std::cout << "hello world" << std::endl; return 0; } );
std::thread t2( std::move(task2) );
t2.join();
}
Вместе с археологией @WhozCraig подразумевается, что это, вероятно, ошибка в MSVC2012.
Чтобы обойти это, попробуйте использовать struct Nothing {};
или же nullptr_t
как ваше возвращаемое значение?
Проблема все еще существует в MSVS 2013RC, но я сделал этот временный патч, пока MS исправляет его. Это специализация packaged_task для void (…), поэтому я предлагаю поместить это в файл заголовка и включить его после стандартных заголовков. Обратите внимание, что make_ready_at_thread_exit () не реализована, а некоторые функции не были полностью протестированы, используйте в ваш собственный риск.
namespace std {
template<class... _ArgTypes>
class packaged_task<void(_ArgTypes...)>
{
promise<void> _my_promise;
function<void(_ArgTypes...)> _my_func;
public:
packaged_task() {
}
template<class _Fty2>
explicit packaged_task(_Fty2&& _Fnarg)
: _my_func(_Fnarg) {
}
packaged_task(packaged_task&& _Other)
: _my_promise(move(_Other._my_promise)),
_my_func(move(_Other._my_func)) {
}
packaged_task& operator=(packaged_task&& _Other) {
_my_promise = move(_Other._my_promise);
_my_func = move(_Other._my_func);
return (*this);
}
packaged_task(const packaged_task&) = delete;
packaged_task& operator=(const packaged_task&) = delete;
~packaged_task() {
}
void swap(packaged_task& _Other) {
_my_promise.swap(_Other._my_promise);
_my_func.swap(_Other._my_func);
}
explicit operator bool() const {
return _my_func != false;
}
bool valid() const {
return _my_func != false;
}
future<void> get_future() {
return _my_promise.get_future();
}
void operator()(_ArgTypes... _Args) {
_my_func(forward<_ArgTypes>(_Args)...);
_my_promise.set_value();
}
void reset() {
swap(packaged_task());
}
};
}; // namespace std