Ælex
Ælex

Reputation: 14869

boost::asio::deadline_timer binding to a polymorphic socket class pointer

My scheme is (more or less) the following:

asio_socket is the abc with a single pure virtual method:

virtual void schedule(
                      boost::asio::ip::tcp::resolver::query &,
                      boost::asio::ip::tcp::resolver &,
                      boost::asio::io_service &
                     ) = 0;

Another class asio_socket_http inherits from it, and also inherits from another asio_helper. Another class asio_socket_https also follows the same scheme.

The asio_socket_http implements the asio_async handlers, for an http connection.

Other classes (which define specific URI/URL-related operations) inherit either from asio_socket_http or asio_socket_https.

There exists a job scheduler:

void run_job(const std::shared_ptr<asio_socket> job);

Internally all it does is:

void run_job(const std::shared_ptr<asio_socket> job)
{
    boost::asio::io_service io;
    boost::asio::ip::tcp::resolver resolver(io);
    job->schedule(query_, resolver, io);
    io.run();
}

I want to add a deadline timer, which will deal with the async nature of asio:

void run_job(const std::shared_ptr<asio_socket> job)
{
    boost::asio::io_service io;
    boost::asio::ip::tcp::resolver resolver(io);
    boost::asio::deadline_timer timer(io, boost::posix_time::seconds(3)); 
    timer.async_wait(boost::bind(&asio_socket::schedule, *job));
    // I also have to bind the 3 params: query_, resolver, io
    io.run();
}

Doing so, I get template argument deduction/substitution failed: and the actual error is:

‘void (rapp::cloud::asio_socket::*)(boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::query&, boost::asio::ip::tcp::resolver&, boost::asio::io_service&) {aka void (rapp::cloud::asio_socket::*)(boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp>&, boost::asio::ip::basic_resolver<boost::asio::ip::tcp>&, boost::asio::io_service&)}’ is not derived from ‘boost::type<R>’ timer.async_wait(boost::bind(&asio_socket::schedule, *job));

How can I bind the method schedule of the (polymorphic) shared pointer job, and also bind the parameters? Trying:

timer.async_wait(boost::bind(&asio_socket::schedule, *job, _1, _2, _3)(&query_, &resolver, &io))

Complains about passing 5 arguments whilst the candidate expects 2 arguments. My guess is that timer.async_wait wants to bind a method to an object?

  1. How can I bind correctly the async timer to the schedule operation?
  2. Do I need to do nested binding, once for the async timer and once for the scheduled job?

Upvotes: 0

Views: 368

Answers (1)

Richard Hodges
Richard Hodges

Reputation: 69902

If you want to pass references into bind you need to pass them as a reference_wapper<>, which you can make with boost::ref(x) or boost::cref(x).

If you don't, the bind call will try to copy them, which of course can't work for a non-copyable asio object.

Something like this should work:

timer.async_wait(boost::bind(&asio_socket::schedule, 
                job,  // should bind to a shared_ptr just fine 
                boost::ref(query_),
                boost:;ref(resolver),
                boost::ref(io),
                boost::placeholders::_1);

schedule will need the following signature:

(boost::asio::ip::tcp::resolver::query &,
 boost::asio::ip::tcp::resolver &,
 boost::asio::io_service &,
 const boost::system::error_code& ec)

because async_wait demands that its handler is able to accept an error code argument as its 'first' unbound argument.

This is why you have to specify boost::placeholders::_1 - to marshal the 'first' argument in the binder (created by bind) to the fourth argument of your class's handler method.

Upvotes: 1

Related Questions