Converting std :: function and std :: packaged_task

I am trying to move std::packaged_task to std::vector from std::function<void()> because std::packaged_task has void operator()( ArgTypes... args ) overloaded, it should be converted to std::function<void()> , yes?

This does not compile on both MSVC and Clang, MSVC complains that it cannot convert void to int, clang complains about the remote copy instance for std::packaged_task , should the version of std::vector::push_back be translated here? what happens is this a mistake?

 int main () { std::vector<std::function<void()>> vec; std::packaged_task<int()> task( [] { return 100; } ); vec.push_back( std::move(task) ); } 

Here are the critical template error messages for clang

 In file included from main.cpp:1: In file included from /usr/bin/../lib/c++/v1/iostream:38: In file included from /usr/bin/../lib/c++/v1/ios:216: In file included from /usr/bin/../lib/c++/v1/__locale:15: In file included from /usr/bin/../lib/c++/v1/string:434: In file included from /usr/bin/../lib/c++/v1/algorithm:594: /usr/bin/../lib/c++/v1/memory:2236:15: error: call to deleted constructor of 'std::__1::packaged_task<int ()>' __first_(_VSTD::forward<_Args1>(get<_I1>(__first_args))...) ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/bin/../lib/c++/v1/memory:2414:15: note: in instantiation of function template specialization 'std::__1::__libcpp_compressed_pair_imp<std::__1::packaged_task<int ()>, std::__1::allocator<std::__1::packaged_task<int ()> >, 2>::__libcpp_compressed_pair_imp<const std::__1::packaged_task<int ()> &, const std::__1::allocator<std::__1::packaged_task<int ()> > &, 0, 0>' requested here : base(__pc, _VSTD::move(__first_args), _VSTD::move(__second_args), ^ /usr/bin/../lib/c++/v1/functional:996:11: note: in instantiation of function template specialization 'std::__1::__compressed_pair<std::__1::packaged_task<int ()>, std::__1::allocator<std::__1::packaged_task<int ()> > >::__compressed_pair<const std::__1::packaged_task<int ()> &, const std::__1::allocator<std::__1::packaged_task<int ()> > &>' requested here : __f_(piecewise_construct, _VSTD::forward_as_tuple(__f), ^ /usr/bin/../lib/c++/v1/functional:1035:17: note: in instantiation of member function 'std::__1::__function::__func<std::__1::packaged_task<int ()>, std::__1::allocator<std::__1::packaged_task<int ()> >, void ()>::__func' requested here ::new (__p) __func(__f_.first(), __f_.second()); ^ /usr/bin/../lib/c++/v1/functional:1277:26: note: in instantiation of member function 'std::__1::__function::__func<std::__1::packaged_task<int ()>, std::__1::allocator<std::__1::packaged_task<int ()> >, void ()>::__clone' requested here ::new (__f_) _FF(_VSTD::move(__f)); ^ /usr/bin/../lib/c++/v1/memory:1681:31: note: in instantiation of function template specialization 'std::__1::function<void ()>::function<std::__1::packaged_task<int ()> >' requested here ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); ^ /usr/bin/../lib/c++/v1/memory:1608:18: note: in instantiation of function template specialization 'std::__1::allocator<std::__1::function<void ()> >::construct<std::__1::function<void ()>, std::__1::packaged_task<int ()> >' requested here {__a.construct(__p, _VSTD::forward<_Args>(__args)...);} ^ /usr/bin/../lib/c++/v1/memory:1492:14: note: in instantiation of function template specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::function<void ()> > >::__construct<std::__1::function<void ()>, std::__1::packaged_task<int ()> >' requested here {__construct(__has_construct<allocator_type, pointer, _Args...>(), ^ /usr/bin/../lib/c++/v1/vector:1519:25: note: in instantiation of function template specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::function<void ()> > >::construct<std::__1::function<void ()>, std::__1::packaged_task<int ()> >' requested here __alloc_traits::construct(this->__alloc(), ^ main.cpp:19:6: note: in instantiation of function template specialization 'std::__1::vector<std::__1::function<void ()>, std::__1::allocator<std::__1::function<void ()> > >::emplace_back<std::__1::packaged_task<int ()> >' requested here vec.emplace_back( std::move(task) ); ^ /usr/bin/../lib/c++/v1/future:1956:5: note: function has been explicitly marked deleted here packaged_task(const packaged_task&) = delete; ^ 2 errors generated. 
+7
source share
2 answers

it should be converted to std::function<void()> , yes?

Not. The corresponding function constructor requires that its argument be CopyConstructible, and packaged_task not CopyConstructible, it is only MoveConstructible, because its copy constructor and copy assignment operator are deleted. This is an unfortunate requirement of function , but necessary for function to copy, due to the use of erasing styles to abstract the details of the wrapped called object.

Until the end of this process, the C ++ 0x project did not require CopyConstructible, but it was added to the final C ++ 11 DR 1287 standard, so this is my mistake, sorry ;-) In an earlier project with concept support, the CopyConstructible concept was CopyConstructible , but it CopyConstructible lost when concepts have been removed from the draft.

+9
source

I had this exact problem today. When implementing a synchronous call in terms of an asynchronous service, it is obvious that you need to try to save packaged_task in the handler function so that the caller's future is ready after the asynchronous handler completes.

Unfortunately, C ++ 11 (and 14) do not allow this. Tracking this cost me almost one day of development, and this process led me to this answer.

I knocked out a solution - a replacement for std :: function with a specialization for std :: packaged_task.

Thanks to both yngum and Jonathan for reporting the question and answer.

the code:

 // general template form template<class Callable> struct universal_call; // partial specialisation to cover most cases template<class R, class...Args> struct universal_call<R(Args...)> { template<class Callable> universal_call(Callable&& callable) : _impl { std::make_shared<model<Callable>>(std::forward<Callable>(callable)) } {} R operator()(Args&&...args) const { return _impl->call(std::forward<Args>(args)...); } private: struct concept { virtual R call(Args&&...args) = 0; virtual ~concept() = default; }; template<class Callable> struct model : concept { model(Callable&& callable) : _callable(std::move(callable)) {} R call(Args&&...args) override { return _callable(std::forward<Args>(args)...); } Callable _callable; }; std::shared_ptr<concept> _impl; }; // pathalogical specialisation for std::packaged_task - // erases the return type from the signature template<class R, class...Args> struct universal_call<std::packaged_task<R(Args...)>> : universal_call<void(Args...)> { using universal_call<void(Args...)>::universal_call; }; // (possibly) helpful function template<class F> universal_call<F> make_universal_call(F&& f) { return universal_call<F>(std::forward<F>(f)); } 
+1
source

All Articles