Почему std :: packaged_task & lt; void () & gt; недействительный?

Используя 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 (), которая ведет себя не так, как ожидается.

5

Решение

Это ошибка в MSVC2012. Существует довольно много ошибок в реализации библиотеки потоков, которая поставляется с MSVC2012. Я опубликовал частичный список в своем блоге, сравнивая его с моей коммерческой библиотекой Just :: Thread: http://www.justsoftwaresolutions.co.uk/news/just-thread-v1.8.0-released.html

5

Другие решения

Это работает в 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 как ваше возвращаемое значение?

3

Проблема все еще существует в 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
2
По вопросам рекламы [email protected]