Search code examples
c++boostboost-asioboost-threadboost-bind

Boost bind inside Boost packaged_task. Why boost asio thinks its not CompletionHandler?


So all my work happens inside of a class named thread_pool. This code will work no matter what run_item takes into itself:

template <class task_return_t>
    void thread_pool::pool_item( boost::shared_ptr< boost::packaged_task<task_return_t> > pt)
    {
        internal_tasks.post(boost::bind(&thread_pool::run_item<task_return_t>, this, pt));
//...

This will not compile:

template <class task_return_t>
    void thread_pool::pool_item( boost::shared_ptr< boost::packaged_task<task_return_t> > pt)
    {
         boost::packaged_task<void> task ( boost::bind(&thread_pool::run_item<task_return_t>, this, pt)));
        internal_tasks.post( task);

Why? And how to make it compile?

I use boost 1.47.0. Errors my VS2010 talls me:

Error   6   error C2665: 'boost::asio::detail::zero_arg_handler_test' : none of the 2 overloads could convert all the argument types    C:\Program Files (x86)\Boost-1.47.0\include\boost\asio\impl\io_service.hpp  88  1   cf-server

Error   9   error C2664: 'void boost::asio::detail::task_io_service::post<CompletionHandler>(Handler)' : cannot convert parameter 1 from 'const boost::packaged_task<R>' to 'boost::packaged_task<R>'   C:\Program Files (x86)\Boost-1.47.0\include\boost\asio\impl\io_service.hpp  90  1   cf-server

Error   8   error C2664: 'T &boost::asio::detail::lvref<CompletionHandler>(T)' : cannot convert parameter 1 from 'const boost::packaged_task<R>' to 'boost::packaged_task<R>'   C:\Program Files (x86)\Boost-1.47.0\include\boost\asio\impl\io_service.hpp  88  1   cf-server

Error   7   error C2664: 'boost::asio::detail::clvref' : cannot convert parameter 1 from 'const boost::packaged_task<R>' to 'boost::packaged_task<R>'   C:\Program Files (x86)\Boost-1.47.0\include\boost\asio\impl\io_service.hpp  88  1   cf-server

Solution

  • It looks like the function thread_pool::run_item<task_return_t> accepts a non-const packaged task reference (or pointer) but boost::bind made a const copy, and is unable to pass the argument.

    Without seeing the run_item signature, I can't tell exactly, but that's where I would look.

    Edit: Looking a bit deeper (once I could get to a copy of boost 1_47), the problem is that boost::packaged_tasks are not copyable, however, boost::asio::io_service requires that CompletionHandler be CopyConstructable. Since boost::packaged_tasks are only MoveConstructable/MoveAssignable, you cannot pass them directly to the io_service.

    See Boost.Asio requirements for CompletionHandlers