无法在变量中存储 bind_front_handler return 值
Cannot store bind_front_handler return value in variable
有了这些出现在我的代码库的其他部分,
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 wrapper wants 是一个临时的(因为它只是移动)。您可以通过
来“修复”它
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()));
替换了整个函数。
演示
#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_),
bind_front_handler(&server::on_accept, 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
有了这些出现在我的代码库的其他部分,
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 wrapper wants 是一个临时的(因为它只是移动)。您可以通过
来“修复”它 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()));
替换了整个函数。
演示
#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_),
bind_front_handler(&server::on_accept, 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