C++ boost::asio boost::asio::basic_socket_acceptor::async_accept() 的接受处理程序中的可变参数模板运算符
C++ boost::asio Variadic template operator in accept handler for boost::asio::basic_socket_acceptor::async_accept()
我正在尝试创建一个接受连接的异步 TCP 服务器。我将要使用如下所示的接受处理函数对象:
template <typename Function>
struct callback
{
Function func_;
callback()
{
}
callback(Function&& f)
: func_(std::forward<Function>(f))
{
}
template <typename ...Args>
void operator() (Args&& ...args)
{
func_(std::forward<Args>(args)...);
}
};
我的服务器class:
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <session.hpp>
#include <handler.hpp>
class server
{
private:
typedef callback<boost::function<void(const boost::system::error_code&, session_ptr&)>> accept_handler;
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
accept_handler handler_;
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session_ptr new_session = session_ptr(new session(io_service_));
auto callback = boost::bind(&server::handle_accept,
this,
boost::asio::placeholders::error,
new_session);
handler_ = accept_handler(std::move(callback));
acceptor_.async_accept(new_session->socket(),
handler_);
}
void handle_accept(const boost::system::error_code& error, session_ptr new_session)
{
if (!error)
{
new_session->start();
new_session.reset(new session(io_service_));
acceptor_.async_accept(new_session->socket(),
handler_);
}
}
};
但是当我尝试编译时出现以下错误:
错误:对“(boost::function&)>) (const boost::system::error_code&)”的调用不匹配
func_(std::forward(args)...);
所以我必须只使用满足 AcceptHandler 要求的处理程序
struct accept_handler
{
...
void operator()(
const boost::system::error_code& ec)
{
...
}
...
};
或者有使用重载可变参数模板 opreator() 的解决方案?
UPDATED After realizing the real mistake:
好消息是:只需更改一行即可轻松修复错误:
typedef callback<boost::function<void(const boost::system::error_code&, session_ptr&)>> accept_handler;
进入
typedef callback<boost::function<void(const boost::system::error_code&)>> accept_handler;
之前的定义完全错误,原因如下:
- 不符合处理程序要求
- 它也不匹配
bind
表达式:bind(&server::handle_accept, this, asio::placeholders::error, new_session)
。请注意,它只有 1 个占位符 (asio::placeholders::error
),因此它不可能使用 2 个参数
#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
namespace ba = boost::asio;
using ba::ip::tcp;
struct session : std::enable_shared_from_this<session> {
session(ba::io_service& svc) : _socket(svc) {}
void start() {} // do something asynchronously
tcp::socket& socket() { return _socket; }
tcp::socket _socket;
};
using session_ptr = std::shared_ptr<session>;
template <typename Function>
struct callback
{
Function func_;
callback(Function&& f = {}) : func_(std::forward<Function>(f)) {
}
template <typename ...Args>
void operator() (Args&& ...args) {
func_(std::forward<Args>(args)...);
}
};
class server
{
private:
typedef callback<boost::function<void(const boost::system::error_code&)>> accept_handler;
ba::io_service& io_service_;
tcp::acceptor acceptor_;
accept_handler handler_;
public:
server(ba::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session_ptr new_session = session_ptr(new session(io_service_));
handler_ = accept_handler(bind(&server::handle_accept, this, ba::placeholders::error, new_session));
acceptor_.async_accept(new_session->socket(), handler_);
}
void handle_accept(const boost::system::error_code& error, session_ptr new_session)
{
if (!error)
{
new_session->start();
new_session.reset(new session(io_service_));
acceptor_.async_accept(new_session->socket(),
handler_);
}
}
};
int main() {
}
简化:删除冗余包装
我在这里唯一要注意的是,none callback<>
、accept_handler
有任何用处:
class server
{
private:
ba::io_service& io_service_;
tcp::acceptor acceptor_;
public:
server(ba::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
void do_accept() {
session_ptr new_session = session_ptr(new session(io_service_));
acceptor_.async_accept(new_session->socket(), bind(&server::handle_accept, this, ba::placeholders::error, new_session));
}
void handle_accept(const boost::system::error_code& error, session_ptr new_session)
{
if (!error) {
new_session->start();
do_accept();
}
}
};
更简单:捕获 Lambda
您可以同时不使用绑定、占位符和 handle_accept
成员:
class server
{
private:
ba::io_service& io_service_;
tcp::acceptor acceptor_;
public:
server(ba::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
void do_accept() {
session_ptr new_session = std::make_shared<session>(io_service_);
acceptor_.async_accept(new_session->socket(), [this,new_session](const boost::system::error_code& error) {
if (!error) {
new_session->start();
do_accept();
}
});
}
};
旧答案
在第一次阅读时,我假设您 运行 陷入了我经常 运行 使用 Boost Asio 和多态 lambda 的经典陷阱。对不起。
确实,在可变情况下,概念检查无法验证处理程序要求。我的方法是禁用需求检查:
#define BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS 1
主要丢失的是不匹配时更友好的错误消息:
Asio 1.6.0 / Boost 1.47
- Added friendlier compiler errors for when a completion handler does not meet the necessary type requirements. When C++0x is available (currently supported for g++ 4.5 or later, and MSVC 10), static_assert is also used to generate an informative error message. This checking may be disabled by defining BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS.
见http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/history.html
我正在尝试创建一个接受连接的异步 TCP 服务器。我将要使用如下所示的接受处理函数对象:
template <typename Function>
struct callback
{
Function func_;
callback()
{
}
callback(Function&& f)
: func_(std::forward<Function>(f))
{
}
template <typename ...Args>
void operator() (Args&& ...args)
{
func_(std::forward<Args>(args)...);
}
};
我的服务器class:
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <session.hpp>
#include <handler.hpp>
class server
{
private:
typedef callback<boost::function<void(const boost::system::error_code&, session_ptr&)>> accept_handler;
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
accept_handler handler_;
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session_ptr new_session = session_ptr(new session(io_service_));
auto callback = boost::bind(&server::handle_accept,
this,
boost::asio::placeholders::error,
new_session);
handler_ = accept_handler(std::move(callback));
acceptor_.async_accept(new_session->socket(),
handler_);
}
void handle_accept(const boost::system::error_code& error, session_ptr new_session)
{
if (!error)
{
new_session->start();
new_session.reset(new session(io_service_));
acceptor_.async_accept(new_session->socket(),
handler_);
}
}
};
但是当我尝试编译时出现以下错误:
错误:对“(boost::function&)>) (const boost::system::error_code&)”的调用不匹配 func_(std::forward(args)...);
所以我必须只使用满足 AcceptHandler 要求的处理程序
struct accept_handler
{
...
void operator()(
const boost::system::error_code& ec)
{
...
}
...
};
或者有使用重载可变参数模板 opreator() 的解决方案?
UPDATED After realizing the real mistake:
好消息是:只需更改一行即可轻松修复错误:
typedef callback<boost::function<void(const boost::system::error_code&, session_ptr&)>> accept_handler;
进入
typedef callback<boost::function<void(const boost::system::error_code&)>> accept_handler;
之前的定义完全错误,原因如下:
- 不符合处理程序要求
- 它也不匹配
bind
表达式:bind(&server::handle_accept, this, asio::placeholders::error, new_session)
。请注意,它只有 1 个占位符 (asio::placeholders::error
),因此它不可能使用 2 个参数
#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
namespace ba = boost::asio;
using ba::ip::tcp;
struct session : std::enable_shared_from_this<session> {
session(ba::io_service& svc) : _socket(svc) {}
void start() {} // do something asynchronously
tcp::socket& socket() { return _socket; }
tcp::socket _socket;
};
using session_ptr = std::shared_ptr<session>;
template <typename Function>
struct callback
{
Function func_;
callback(Function&& f = {}) : func_(std::forward<Function>(f)) {
}
template <typename ...Args>
void operator() (Args&& ...args) {
func_(std::forward<Args>(args)...);
}
};
class server
{
private:
typedef callback<boost::function<void(const boost::system::error_code&)>> accept_handler;
ba::io_service& io_service_;
tcp::acceptor acceptor_;
accept_handler handler_;
public:
server(ba::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
session_ptr new_session = session_ptr(new session(io_service_));
handler_ = accept_handler(bind(&server::handle_accept, this, ba::placeholders::error, new_session));
acceptor_.async_accept(new_session->socket(), handler_);
}
void handle_accept(const boost::system::error_code& error, session_ptr new_session)
{
if (!error)
{
new_session->start();
new_session.reset(new session(io_service_));
acceptor_.async_accept(new_session->socket(),
handler_);
}
}
};
int main() {
}
简化:删除冗余包装
我在这里唯一要注意的是,none callback<>
、accept_handler
有任何用处:
class server
{
private:
ba::io_service& io_service_;
tcp::acceptor acceptor_;
public:
server(ba::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
void do_accept() {
session_ptr new_session = session_ptr(new session(io_service_));
acceptor_.async_accept(new_session->socket(), bind(&server::handle_accept, this, ba::placeholders::error, new_session));
}
void handle_accept(const boost::system::error_code& error, session_ptr new_session)
{
if (!error) {
new_session->start();
do_accept();
}
}
};
更简单:捕获 Lambda
您可以同时不使用绑定、占位符和 handle_accept
成员:
class server
{
private:
ba::io_service& io_service_;
tcp::acceptor acceptor_;
public:
server(ba::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
void do_accept() {
session_ptr new_session = std::make_shared<session>(io_service_);
acceptor_.async_accept(new_session->socket(), [this,new_session](const boost::system::error_code& error) {
if (!error) {
new_session->start();
do_accept();
}
});
}
};
旧答案
在第一次阅读时,我假设您 运行 陷入了我经常 运行 使用 Boost Asio 和多态 lambda 的经典陷阱。对不起。
确实,在可变情况下,概念检查无法验证处理程序要求。我的方法是禁用需求检查:
#define BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS 1
主要丢失的是不匹配时更友好的错误消息:
Asio 1.6.0 / Boost 1.47
- Added friendlier compiler errors for when a completion handler does not meet the necessary type requirements. When C++0x is available (currently supported for g++ 4.5 or later, and MSVC 10), static_assert is also used to generate an informative error message. This checking may be disabled by defining BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS.
见http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/history.html