在意识到真正的错误之后
:
好消息是:只需更改一行即可修复错误:
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)
. 注意,它只有一个占位符(
asio::placeholders::error
)所以它不可能在两个参数下工作
Live On Coliru
#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() {
}
简化:删除冗余包装
callback<>
,
accept_handler
有任何用途:
Live On Coliru
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
所有成员同时:
Live On Coliru
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
如果存在不匹配,则丢失的主要信息是更友好的错误消息:
-
当完成处理程序不满足必要的类型要求时,添加了更友好的编译器错误。当C++0x可用时(当前支持g++4.5或更高版本,以及MSVC 10),静态_断言也用于生成信息性错误消息。可以通过定义BOOST\u ASIO\u DISABLE\u HANDLER\u TYPE\u要求来禁用此检查。
看见
http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/history.html