2

I'm trying to use Boost.Asio's async_read_until() free function, but I'm having trouble specifying a member function as the callback using std::bind(). I have no trouble using this idiom for other Boost.Asio functions, so I'm confused as to why it's not working for async_read_until().

Here's my example:

#include <functional>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

class Test
{
public:
    boost::asio::streambuf buf;
    boost::asio::ip::tcp::socket sock;

    Test(boost::asio::io_service& io) :
        sock(io)
    {
    }

    void readComplete(const boost::system::error_code& error,
                      std::size_t bytesTransferred)
    {
    }

    void invoke()
    {
        boost::asio::async_read_until(sock,
                                      buf,
                                      '\n',
                                      std::bind(&Test::readComplete,
                                                this,
                                                boost::asio::placeholders::error,
                                                boost::asio::placeholders::bytes_transferred));
    }
};

int main(int argc, char** argv)
{
    boost::asio::io_service io;
    Test t(io);

    t.invoke();

    return 0;
}

In this case, the compilation fails with the following error (along with other template-compiler-error-barf):

In file included from /home/me/eclipse-workspace/practice/main.cpp:4:
In file included from /usr/include/boost/asio.hpp:91:
In file included from /usr/include/boost/asio/read_until.hpp:921:
/usr/include/boost/asio/impl/read_until.hpp:707:3: error: static_assert failed "ReadHandler type requirements not met"
  BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/asio/detail/handler_type_requirements.hpp:153:3: note: expanded from macro 'BOOST_ASIO_READ_HANDLER_CHECK'
  BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
  ^
/usr/include/boost/asio/detail/handler_type_requirements.hpp:105:6: note: expanded from macro 'BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT'
     static_assert(expr, msg);
     ^             ~~~~
/home/me/eclipse-workspace/practice/main.cpp:24:22: note: in instantiation of function template specialization 'boost::asio::async_read_until<boost::asio::basic_stream_socket<boost::asio::ip::tcp,
      boost::asio::stream_socket_service<boost::asio::ip::tcp> >, std::allocator<char>, std::_Bind<std::_Mem_fn<void (Test::*)(const boost::system::error_code &, unsigned long)>
      (Test *, boost::arg<1> (*)(), boost::arg<2> (*)())> >' requested here
        boost::asio::async_read_until(sock,
                     ^

So it's telling me that my function signature is wrong, which it doesn't appear to be.

I don't understand why it's not working, and what I more so don't understand is that if I just swap out std::bind() for boost::bind(), it builds and works completely fine. Could someone please help me understand this?

FYI I'm using Boost 1.58.0 (from the Ubuntu 16.04 Universe repos) and clang++ 3.8 with C++11.

villapx
  • 1,743
  • 1
  • 15
  • 31
  • i think you need to use boost::bind – Tyker Aug 27 '18 at 14:35
  • use `boost::bind` instead of `std::bind`, or use `std::placeholders::_1` and `std::placeholderds::_2 `or use [Asio](https://think-async.com/) instead of it's Boost version – Victor Gubin Aug 27 '18 at 14:36

1 Answers1

6

Unfortunately, you're mixing and matching binds:

std::bind(&Test::readComplete,
    this,
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred));

The boost::asio::placeholders only work with boost::bind, not with std::bind.

From the docs, you want either:

std::bind(&Test::readComplete,
    this,
    std::placeholders::_1,
    std::placeholders::_2));

or

boost::bind(&Test::readComplete,
    this,
    boost::asio::placeholders::error,
    boost::asio::placeholders::bytes_transferred)); 

I don't understand why boost doesn't just say that its placeholders are std placeholders:

namespace std {
    template <int I>
    struct is_placeholder<boost::arg<I>>
        : integral_constant<int, I>
    { };
}

I assume there's a good reason?

Barry
  • 286,269
  • 29
  • 621
  • 977