boost::asio::deadline_timer 绑定到多态套接字类指针

Posted

技术标签:

【中文标题】boost::asio::deadline_timer 绑定到多态套接字类指针【英文标题】:boost::asio::deadline_timer binding to a polymorphic socket class pointer 【发布时间】:2016-05-01 22:57:23 【问题描述】:

我的方案(或多或少)如下:

asio_socket 是带有单个纯虚方法的 abc:

virtual void schedule(
                      boost::asio::ip::tcp::resolver::query &,
                      boost::asio::ip::tcp::resolver &,
                      boost::asio::io_service &
                     ) = 0;

另一个类asio_socket_http 继承自它,也继承自另一个asio_helper。另一个类asio_socket_https 也遵循相同的方案。

asio_socket_http 实现了 asio_async 处理程序,用于 http 连接。

其他类(定义特定的 URI/URL 相关操作)继承自 asio_socket_httpasio_socket_https

存在一个作业调度器:

void run_job(const std::shared_ptr<asio_socket> job);

它在内部所做的只是:

void run_job(const std::shared_ptr<asio_socket> job)

    boost::asio::io_service io;
    boost::asio::ip::tcp::resolver resolver(io);
    job->schedule(query_, resolver, io);
    io.run();

我想添加一个截止时间计时器,它将处理 asio 的异步性质:

void run_job(const std::shared_ptr<asio_socket> job)

    boost::asio::io_service io;
    boost::asio::ip::tcp::resolver resolver(io);
    boost::asio::deadline_timer timer(io, boost::posix_time::seconds(3)); 
    timer.async_wait(boost::bind(&asio_socket::schedule, *job));
    // I also have to bind the 3 params: query_, resolver, io
    io.run();

这样做,我得到template argument deduction/substitution failed: 实际的错误是:

‘void (rapp::cloud::asio_socket::*)(boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::query&, boost::asio::ip::tcp::resolver&, boost::asio::io_service&) aka void (rapp::cloud::asio_socket::*)(boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp>&, boost::asio::ip::basic_resolver<boost::asio::ip::tcp>&, boost::asio::io_service&)’ is not derived from ‘boost::type<R>’ timer.async_wait(boost::bind(&asio_socket::schedule, *job));

如何绑定(多态)共享指针job的方法schedule,同时绑定参数? 尝试:

timer.async_wait(boost::bind(&asio_socket::schedule, *job, _1, _2, _3)(&query_, &resolver, &io))

抱怨传递 5 个参数,而候选人期望 2 个参数。 我的猜测是timer.async_wait 想将方法绑定到对象?

    如何将异步计时器正确绑定到调度操作? 我是否需要进行嵌套绑定,一次用于异步计时器,一次用于计划作业?

【问题讨论】:

【参考方案1】:

如果您想将引用传递给bind,您需要将它们作为reference_wapper&lt;&gt; 传递,您可以使用boost::ref(x)boost::cref(x)

如果您不这样做,bind 调用将尝试复制它们,这当然不适用于不可复制的 asio 对象。

这样的事情应该可以工作:

timer.async_wait(boost::bind(&asio_socket::schedule, 
                job,  // should bind to a shared_ptr just fine 
                boost::ref(query_),
                boost:;ref(resolver),
                boost::ref(io),
                boost::placeholders::_1);

时间表需要以下签名:

(boost::asio::ip::tcp::resolver::query &,
 boost::asio::ip::tcp::resolver &,
 boost::asio::io_service &,
 const boost::system::error_code& ec)

因为 async_wait 要求其处理程序能够接受错误代码参数作为其“第一个”未绑定参数。

这就是为什么您必须指定 boost::placeholders::_1 - 将绑定程序中的“第一个”参数(由 bind 创建)编组到类的处理程序方法的第四个参数。

【讨论】:

非常感谢您的帮助。我试过boost::ref,但我得到了error: invalid use of non-static member function。所以现在我正在尝试使用boost::mem_fnboost::ref。不过我还是一头雾水,难道我还需要绑定schedule方法的参数吗? @Ælex 更新了答案。希望这是有道理的。如果没有,请查看 asio 文档中的示例。 确实有效!非常感谢!我仍然有点困惑,但这是有道理的。我很惊讶它适用于std::shared_ptr。最后一个问题,占位符是用于job 对象指针,而不是用于对参数的引用? @Ælex 占位符用于 async_wait 在调用您的处理程序时将提供的参数。它期望调用带有签名 f(const error_code& ec) 的处理程序。占位符允许它向您发送一个参数,然后您将该占位符绑定到处理程序方法的第四个参数中。成员函数的 std::bind 将绑定到指针、shared_ptr 和(从内存中)引用包装器。为了满足大多数用例,bind 有多个重载(std::bind 也是如此,顺便说一下,它也可以用于构造 asio 处理程序)。

以上是关于boost::asio::deadline_timer 绑定到多态套接字类指针的主要内容,如果未能解决你的问题,请参考以下文章