Нужен ли std :: packaged_task аргумент конструктора CopyConstructible?

У меня есть этот минимальный нерабочий пример кода

#include <future>

int main()
{
auto intTask = std::packaged_task<int()>( []()->int{ return 5; } );
std::packaged_task<void()> voidTask{ std::move(intTask) };
}

Почему он не компилируется (на gcc 4.8.1)? Я подозреваю, причина в том, что std::packaged_task хранит лямбда внутри std::function который нуждается в CopyConstructible аргумент. Тем не мение, std::packaged_task только для перемещения. Это ошибка? Что стандарт говорит об этом? по моему мнению std::packaged_task не нужно CopyConstructible аргумент, но MoveConstructible аргумента должно быть достаточно.

Кстати когда я заменю std::packaged_task<int()> от std::packaged_task<void()> все компилируется нормально.

GCC 4.8.1 выдает мне это сообщение об ошибке:

In file included from /usr/include/c++/4.6/future:38:0,
from ../cpp11test/main.cpp:160:
/usr/include/c++/4.6/functional: In static member function 'static void        std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = std::packaged_task<int()>, std::false_type = std::integral_constant<bool, false>]':
/usr/include/c++/4.6/functional:1652:8:   instantiated from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = std::packaged_task<int()>]'
/usr/include/c++/4.6/functional:2149:6:   instantiated from 'std::function<_Res(_ArgTypes ...)>::function(_Functor, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor = std::packaged_task<int()>, _Res = void, _ArgTypes = {}, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function<void()>::_Useless]'
/usr/include/c++/4.6/bits/shared_ptr_base.h:410:4:   instantiated from 'std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc, _Args&& ...) [with _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.6/bits/shared_ptr_base.h:518:8:   instantiated from 'std::__shared_count<_Lp>::__shared_count(std::_Sp_make_shared_tag, _Tp*, const _Alloc&, _Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.6/bits/shared_ptr_base.h:987:35:   instantiated from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.6/bits/shared_ptr.h:317:64:   instantiated from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}, _Tp = std::__future_base::_Task_state<void()>]'
/usr/include/c++/4.6/bits/shared_ptr.h:535:39:   instantiated from 'std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Alloc = std::allocator<std::__future_base::_Task_state<void()> >, _Args = {std::packaged_task<int()>}]'
/usr/include/c++/4.6/bits/shared_ptr.h:551:42:   instantiated from 'std::shared_ptr<_Tp1> std::make_shared(_Args&& ...) [with _Tp = std::__future_base::_Task_state<void()>, _Args = {std::packaged_task<int()>}]'
/usr/include/c++/4.6/future:1223:66:   instantiated from 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(_Fn&&) [with _Fn = std::packaged_task<int()>, _Res = void, _ArgTypes = {}]'
../cpp11test/main.cpp:165:61:   instantiated from here
/usr/include/c++/4.6/functional:1616:4: error: use of deleted function 'std::packaged_task<_Res(_ArgTypes ...)>::packaged_task(std::packaged_task<_Res(_ArgTypes ...)>&) [with _Res = int, _ArgTypes = {}, std::packaged_task<_Res(_ArgTypes ...)> = std::packaged_task<int()>]'
/usr/include/c++/4.6/future:1244:7: error: declared here

ОБНОВИТЬ: Я написал следующую тестовую программу. Это, кажется, подтверждает предположение, что причина отсутствует CopyConstructability, Опять же, каковы требования к типу объекта, из которого std::packaged_task может быть построен?

#include <future>

struct Functor {
Functor() {}
Functor( const Functor & ) {} // without this line it doesn't compile
Functor( Functor && ) {}
int operator()(){ return 5; }
};

int main() {
auto intTask = std::packaged_task<int()>( Functor{} );
}

3

Решение

В самом деле, packaged_task имеет только движущийся конструктор (30.6.9 / 2):

template <class F> explicit packaged_task(F&& f);

Тем не менее, ваша проблема заключается в explicit конструктор. Так напишите это так:

std::packaged_task<int()> pt([]() -> int { return 1; });

Полный пример:

#include <future>
#include <thread>

int main()
{
std::packaged_task<int()> intTask([]() -> int { return 5; } );
auto f = intTask.get_future();
std::thread(std::move(intTask)).detach();
return f.get();
}
2

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

Нет, ты просто не можешь сдвинуть packaged_task<int ()> в packaged_task<void ()>, Эти типы не связаны и не могут быть назначены или созданы для перемещения друг от друга. Если вы по какой-то причине действительно хотите это сделать, вы можете «проглотить» результат int () лайк этот

0

В стандарте (начиная с N3690) ничего явно не говорится о требованиях типа F в

template <class R, class... ArgTypes>
template <class F>
packaged_task<R(ArgTypes...)>::packaged_task(F&& f);

(см. 30.6.9.1) Однако в нем говорится, что

Вызывая копию f должен вести себя так же, как призывая f,

и что этот вызов может бросить

любые исключения, сгенерированные конструктором копирования или перемещения f, или же std::bad_alloc если память
для внутренних структур данных не может быть выделено.

Это подразумевает, что тип F должен быть не менее MoveConstructible, или же CopyConstructible, если ссылка на lvalue передана функции.

Следовательно, это не ошибка, просто это не указано точно. Чтобы решить проблему положить std::packaged_task<int()> в std::packaged_task<void()> просто заверните первый в shared_ptr как это:

#include <future>
#include <memory>

int main()
{
auto intTask = std::make_shared<std::packaged_task<int()>>(
[]()->int{ return 5; } );
std::packaged_task<void()> voidTask{ [=]{ (*intTask)(); } };
}
0
По вопросам рекламы [email protected]