How does boost::beast::bind_front_handler works?
Asked Answered
R

1

10

I am trying boost::beast examples, I came across to this piece of code.

    void on_write(beast::error_code ec, std::size_t byte_transferred) {
        if (ec) return fail(ec, "write");

        http::async_read(m_tcp_stream, m_buffer, m_response, beast::bind_front_handler(
            &Session::on_read, shared_from_this()));
    }

    void on_read(beast::error_code ec, std::size_t bytes_transferred) {
        if (ec) return fail(ec, "read");
        //std::cout << m_response << std::endl;
        write_on_file(m_response);
        m_tcp_stream.socket().shutdown(tcp::socket::shutdown_both, ec);
        if (ec && ec != beast::errc::not_connected) return fail(ec, "showdown");
    }

Particularly http::async_read(m_tcp_stream, m_buffer, m_response, beast::bind_front_handler(&Session::on_read, shared_from_this())); this line. I am not able to understand its code. How does it work. As far as I get from the code, that It returns bind_front_wrapper which constructs a Handler and tuple of args within itself. But I did not understand how does it manage to get the arguments of the passed Handler in bind_front_handler even though we are not passing, we are just passing shared_ptr. In this case async_read is calling on_read method. But we are not passing any parameters, but still it get called, I wonder how?

Refection answered 26/3, 2021 at 19:17 Comment(0)
O
4

You use asynchronous operations, so your job is to define callbacks which are called by Beast core code when operations are completed. When an operation started by async_read is ready, handler passed to async_read is called with two arguments: error code + number of transferred bytes. You decided to wrap on_read into callback by bind_front_handler. bind_front_handler generates a functor object whose implementation in pseudocode may look like:

class Handler {
    void (Session::*onRead)(...); // pointer to on_read function member of Session
    Session* session;  // pointer to session, get by shared_from_this

    Handler(/* pointer to on_read, pointer to session */) {}

    template<class ... Args>
    void operator() (Args... args) {
        ((*session).*onRead)(args...);
    }        
}

when read operation is ready, function operator() of above handler is called with two arguments pack: error code and number of read bytes.

Since c++20 there is std::bind_front, you may visit reference to get more details how it could be implemented in Beast library.

Organism answered 26/3, 2021 at 20:41 Comment(2)
boost can be a pretty thankless pit :) Thanks for writing awesome answers like theseNim
Thanks for the wonderful answer. But, as a novice, I got confused at the last sentence. What is the relationship between beast::bind_front_handler and std::bind_front?Albite

© 2022 - 2024 — McMap. All rights reserved.