微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法在变量中存储 bind_front_handler 返回值

如何解决无法在变量中存储 bind_front_handler 返回值

这些出现在我代码库的其他部分中,

namespace net = boost::asio;
using boost::asio::ip::tcp;

boost::asio::io_context& io_context_;
tcp::acceptor acceptor_;
void server::on_accept(boost::beast::error_code ec,boost::asio::ip::tcp::socket socket);

我注意到这段代码可以编译:

auto strand = net::make_strand(io_context_);
std::shared_ptr<server> this_pointer = shared_from_this();

acceptor_.async_accept(
    strand,boost::beast::bind_front_handler(&server::on_accept,this_pointer)
);

而这不是:

auto strand = net::make_strand(io_context_);
std::shared_ptr<server> this_pointer = shared_from_this();

auto call_next = boost::beast::bind_front_handler(&server::on_accept,this_pointer);

acceptor_.async_accept(
    strand,call_next
);

它因错误而失败

/usr/include/boost/beast/core/detail/bind_handler.hpp:251:45: error: cannot convert ‘boost::beast::detail::bind_front_wrapper<void (server::*)(boost::system::error_code,boost::asio::basic_stream_socket<boost::asio::ip::tcp>),std::shared_ptr<server> >’ to ‘void (server::*)(boost::system::error_code,boost::asio::basic_stream_socket<boost::asio::ip::tcp>)’ in initialization
  251 |,args_(std::forward<Args_>(args)...)

我很好奇为什么将 bind_front_handler 返回的值直接传递给 async_accept 会起作用,但将该值存储在变量中然后传递该变量不起作用。

我现在对 Boost 和 Beast 也知之甚少,但在我看来,我似乎忘记了 C++ 本身的一些非常基本的东西。为什么这两段代码不等价?

解决方法

确实,您不应该这样做。 bind-front 包装器希望是一个临时的(因为它只是移动)。你可以通过这样做来“修复”它

    acceptor_.async_accept(strand,std::move(call_next));

(之后您必须记住 call_next 可能不会再次使用,因为它已被移出)。

我个人会走另一条路 - 因为这个助手显然是故意的 - 并写出惯用的

    acceptor_.async_accept(
        make_strand(io_context_),bind_front_handler(&server::on_accept,shared_from_this()));

替换整个函数。

演示

Live On Coliru

#include <boost/beast.hpp>
#include <boost/asio.hpp>
#include <iostream>
namespace net = boost::asio;
namespace beast = boost::beast;
using boost::system::error_code;
using net::ip::tcp;

struct server : std::enable_shared_from_this<server> {
    server() {
        acceptor_.listen();
    }

    void start(){
        using beast::bind_front_handler;
        acceptor_.async_accept(
            make_strand(io_context_),shared_from_this()));
    }

    void wait() {
        work_.reset();

        if (thread_.joinable())
            thread_.join();
    }

  private:
    void on_accept(error_code ec,tcp::socket&& socket) {
        std::cout << "Accepted connection from " << socket.remote_endpoint() << "\n";
        //// loop to accept more:
        // start();
    }

    net::io_context io_context_;
    tcp::acceptor   acceptor_{io_context_,{{},9999}};

    net::executor_work_guard<net::io_context::executor_type> work_{
        io_context_.get_executor()};
    std::thread thread_{[this] { io_context_.run(); }};
};

int main()
{
    auto s = std::make_shared<server>();
    s->start();
    s->wait();
}

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp
./a.out& sleep .5; nc 127.0.0.1 9999 <<<'hello world'; wait

打印例如

Accepted connection from 127.0.0.1:36402

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。