Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't use asio::placeholders::error in non-Boost version of Asio

I'm trying to use the non Boost version of Asio in a project. I'm writing a callback to stream_protocol::acceptor::async_accept. The signature requires asio::placeholders::error to be passed but when I do so, I get the following error:

error: no member named 'error' in namespace 'asio::placeholders'

Following the source, I can see error is there but of type undefined, which is new to me. Am I missing something? Am I supposed to do some sort of pre-processing of the libraries?

like image 458
ruipacheco Avatar asked Feb 12 '15 19:02

ruipacheco


1 Answers

In short, use std::placeholders::_1 instead of asio::placeholders:error.


Asio only supports the convenient placeholder variables when using Boost.Bind. The error placeholder documentation states:

An argument placeholder, for use with boost::bind(), ...

When using std::bind() to create handlers, one needs to use std::bind's placeholders. The async_accept() operation accepts a handler that meets the AcceptHandler type requirements:

An accept handler must meet the requirements for a handler. A value h of an accept handler class should work correctly in the expression h(ec), where ec is an lvalue of type const error_code.

When creating a functor with std::bind() to function as a AcceptHandler, if one wishes to obtain the error_code argument, then use std::placeholders::_1:

void handle_accept(const std::error_code&);

acceptor.async_accept(server_socket, std::bind(&handle_accept,
  std::placeholders::_1 /* error_code */));

Here is a complete minimal example demonstrating using std::bind(). Note that coliru does not appear to have an Asio standalone version available, but the example should suffice:

#include <iostream>
#include <functional>

#include <boost/asio.hpp>

void handle_accept(const boost::system::error_code& error_code)
{
  std::cout << "handle_accept: " << error_code.message() << std::endl;
}

void noop() {}

int main()
{
  using boost::asio::ip::tcp;
  boost::asio::io_service io_service;

  // Create all I/O objects.
  tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0));
  tcp::socket server_socket(io_service);
  tcp::socket client_socket(io_service);

  // Connect client and server sockets.
  acceptor.async_accept(server_socket, std::bind(&handle_accept,
    std::placeholders::_1 /* error_code */));
  client_socket.async_connect(acceptor.local_endpoint(), std::bind(&noop));
  io_service.run();
}

Output:

handle_accept: Success

Optionally, if one wishes for a bit more verbosity, then named placeholders could be used:

namespace asio_placeholders
{
  auto error = std::placeholders::_1;
}

// ...

acceptor.async_accept(server_socket, std::bind(&handle_accept,
  asio_placeholders::error));

The unspecified type observed in the source code is only used when generating documentation, as shown in this code:

#if defined(GENERATING_DOCUMENTATION)

/// An argument placeholder, for use with boost::bind(), that corresponds to
/// the error argument of a handler for any of the asynchronous functions.
unspecified error;

// ...

#elseif
like image 148
Tanner Sansbury Avatar answered Oct 21 '22 20:10

Tanner Sansbury