2

I am trying to implement a read header handler as a member function to process incoming data. However during compilation I am told that the type requirements are not met.

I've checked the the boost docs and the function signatures seem to be fine. I couldn't spot a difference. However boost doesn't accept the handler as valid.

.cpp file:

void tcpclient::read_data() {
    char buffer_[1];
    boost::asio::async_read(_socket, boost::asio::buffer(buffer_, HEADER_LEN),
                            std::bind(&tcpclient::handle_read_header, this,
                                      boost::asio::placeholders::error,
                                      boost::asio::placeholders::bytes_transferred));
}


void tcpclient::handle_read_header(const boost::system::error_code &error, std::size_t bytes_transferred) {
    if (!error) {
        logger::log_info("Read " + std::to_string(bytes_transferred) + " bytes.");
    } else {
        logger::log_error("Failed to read header");
        _socket.close();
    }
}

.h file:

void handle_read_header(const boost::system::error_code &error, std::size_t bytes_transferred);

    void read_data();

    boost::asio::ip::tcp::socket _socket;

I would expect code to accept the handler signature just fine but instead I am prompted:

/usr/include/boost/asio/impl/read.hpp: In instantiation of ‘typename boost::asio::async_result<typename std::decay<WriteHandler>::type, void(boost::system::error_code, long unsigned int)>::return_type boost::asio::async_read(AsyncReadStream&, const MutableBufferSequence&, ReadHandler&&, typename std::enable_if<boost::asio::is_mutable_buffer_sequence<MutableBufferSequence>::value>::type*) [with AsyncReadStream = boost::asio::basic_stream_socket<boost::asio::ip::tcp>; MutableBufferSequence = boost::asio::mutable_buffers_1; ReadHandler = std::_Bind<void (tcpclient::*(tcpclient*, boost::arg<1> (*)(), boost::arg<2> (*)()))(const boost::system::error_code&, long unsigned int)>; typename boost::asio::async_result<typename std::decay<WriteHandler>::type, void(boost::system::error_code, long unsigned int)>::return_type = void; typename std::enable_if<boost::asio::is_mutable_buffer_sequence<MutableBufferSequence>::value>::type = void]’:
/home/void/Documents/Development/SocketTest/SocketTest/networking/tcpclient.cpp:55:84:   required from here
/usr/include/boost/asio/impl/read.hpp:446:3: error: static assertion failed: ReadHandler type requirements not met
   BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/asio/impl/write.hpp:430:3: error: no match for call to ‘(std::_Bind<void (tcpclient::*(tcpclient*, boost::arg<1> (*)(), boost::arg<2> (*)()))(const boost::system::error_code&, long unsigned int)>) (const boost::system::error_code&, const long unsigned int&)’
   BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kyu96
  • 1,159
  • 2
  • 17
  • 35

1 Answers1

2

Use boost::bind with boost::asio::placeholders::..

boost::bind(&tcpclient::handle_read_header, this,
                                  boost::asio::placeholders::error,
                                  boost::asio::placeholders::bytes_transferred));

or std::placeholders::_1/_2 with std::bind:

std::bind(&tcpclient::handle_read_header, this,
                                  std::placeholders::_1,
                                  std::placeholders::_2));
rafix07
  • 20,001
  • 3
  • 20
  • 33
  • Thanks for your reply. I would prefer to go with the first suggested example because it's more descriptive. However when I try to use `boost::bind` instead of `std::bind` I am told `No member 'bind' in namespace boost`. Am I missing an include? – Kyu96 Apr 18 '19 at 12:14
  • 1
    Header `boost/bind.hpp` is missing, you need to add it. – rafix07 Apr 18 '19 at 12:15
  • Is there also a chance to pass the read buffer to the handler? That way I could process the received data in the handler itself. – Kyu96 Apr 18 '19 at 12:21
  • 1
    Yes, you can do it by using lambda as handler. Then you need to pass *buffer* in capture list of lambda. If you want i can add link with example. – rafix07 Apr 18 '19 at 12:24
  • Yes an example would be awesome ! – Kyu96 Apr 18 '19 at 12:33
  • 1
    [Here - example](https://godbolt.org/z/7pfBD0) I added 2 version: one uses lambda, another uses extended `handle_read_header` member - as third parameter it takes buffer. – rafix07 Apr 18 '19 at 12:37
  • Awesome! One last thing: Is there a way to template the array size? I like to have a variable that indicates the header size without having to hardcode the size at multiple different places in the function signature. Seems that it is not possible to simply plug the variable in the function signature instead of the hardcoded values. – Kyu96 Apr 18 '19 at 15:51
  • You don't need to use `std::array` there are many ways to achive what you want, for example you may consider using `vector` or `string`, then call `resize` to prepare buffer: [example with vector here](https://godbolt.org/z/F4bHwp). – rafix07 Apr 18 '19 at 16:45
  • I know about the possibility of `std::vector` but I didn't mean resizing at runtime. The header should have a fixed size at runtime (`std::array`). I was referring to changing the implementation at some point in the future. That's why I mentioned _templating_. It's not to much of a concern tho I think. – Kyu96 Apr 18 '19 at 16:49