Как работает boost :: beast :: bind_front_handler?

Пробую boost::beast примеры, наткнулся на этот кусок кода.

    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");
    }

В частности http::async_read(m_tcp_stream, m_buffer, m_response, beast::bind_front_handler(&Session::on_read, shared_from_this())); эта строка. Я не могу понять его код. Как это работает. Насколько я понимаю из кода, он возвращает bind_front_wrapper, который создает внутри себя Handler и tuple of args. Но я не понял, как ему удается получить аргументы переданного Handler в bind_front_handler, даже если мы не передаем, мы просто передаем shared_ptr. В этом случае async_read вызывает метод on_read. Но мы не передаем никаких параметров, но все равно вызывается, интересно, как?


person foragerDev    schedule 26.03.2021    source источник


Ответы (1)


Вы используете асинхронные операции, поэтому ваша задача - определить обратные вызовы, которые вызываются основным кодом Beast по завершении операций. Когда операция, запущенная async_read, готова, обработчик, переданный async_read, вызывается с двумя аргументами: код ошибки + количество переданных байтов. Вы решили заключить on_read в обратный вызов от bind_front_handler. bind_front_handler генерирует объект-функтор, реализация которого в псевдокоде может выглядеть так:

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...);
    }        
}

когда операция чтения готова, вызывается функция operator() указанного выше обработчика с двумя пакетами аргументов: кодом ошибки и количеством прочитанных байтов.

Поскольку в c ++ 20 есть std::bind_front, вы можете посетить ссылку на получить более подробную информацию о том, как это может быть реализовано в библиотеке Beast.

person rafix07    schedule 26.03.2021