我想打开这个电话:
timer.async_wait(handler);
进入这个电话:
func(handler);
所以我尝试使用std::bind
:
#include <functional>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/system/error_code.hpp>
using std::bind;
using std::function;
using boost::asio::io_service;
using boost::asio::steady_timer;
using boost::system::error_code;
int main(int, char**) {
using namespace std::placeholders;
io_service io_s;
steady_timer timer (io_s);
// error
function<void(function<void(const error_code&)>)> bound =
bind(&steady_timer::async_wait, timer, _1);
return 0;
}
但它不会编译!编译时如下:
g++-4.9 -std=c++11 -Wall -I/usr/local/include -L/usr/local/lib -lboost_system -o bin main.cpp
错误信息是:
main.cpp:22:46: error: no matching function for call to 'bind(<unresolved overloaded function type>, boost::asio::steady_timer&, const std::_Placeholder<1>&)'
bind(&steady_timer::async_wait, timer, _1);
我尝试了各种各样的东西(比如转换,模板参数,函数对象),但我无法编译它。
我使用Boost ASIO 1.58和the documentation说明如下:
template<
typename WaitHandler>
void-or-deduced async_wait(
WaitHandler handler);
而here你可以看到WaitHandler是什么。我不明白void-or-deduced
的意思,但我认为这可能是什么给了我一个艰难的时刻?我已经盯着这个问题很长时间了,因为我认为我已经获得了隧道视野。
在这种情况下如何正确使用std::bind
?
答案 0 :(得分:3)
从启动函数(async_*
)返回的对象类型在提供给启动函数的处理程序类型上是依赖。文档以void-or-deduced
类型表示此变体。
尝试在此使用function
和bind
会遇到多个问题:
timer.async_wait()
的函数签名std::function<...>
可能会产生意想不到的后果,因为将调用默认的asio_handler_*
挂钩而不是自定义挂钩。有关处理程序挂钩的更多详细信息,请参阅this答案。相反,考虑使用自定义仿函数来完成绑定,同时允许处理程序类型正确传递给Asio:
/// @brief Custom functor used to initiate async_wait operations.
template <typename Timer>
class async_wait_functor
{
public:
async_wait_functor(Timer& timer): timer_(timer) {}
template <typename WaitHandler>
auto operator()(WaitHandler handler)
{
return timer_.async_wait(handler);
}
private:
Timer& timer_;
};
/// @brief Auxiliary factory function for binding a timer.
template <typename Timer>
async_wait_functor<Timer> bind_async_wait(Timer& timer)
{
return async_wait_functor<Timer>(timer);
}
...
auto func = bind_async_wait(timer);
func(handler);
以下是使用自定义仿函数的完整示例demonstrating:
#include <iostream>
#include <functional>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
/// @brief Custom functor used to initiate async_wait operations.
template <typename Timer>
class async_wait_functor
{
public:
async_wait_functor(Timer& timer): timer_(timer) {}
template <typename WaitHandler>
auto operator()(WaitHandler handler)
{
return timer_.async_wait(handler);
}
private:
Timer& timer_;
};
/// @brief Auxiliary factory function for binding a timer.
template <typename Timer>
async_wait_functor<Timer> bind_async_wait(Timer& timer)
{
return async_wait_functor<Timer>(timer);
}
int main()
{
boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);
auto handler = [](const boost::system::error_code&) {
std::cout << "in handler" << std::endl;
};
auto func = bind_async_wait(timer);
func(handler);
timer.cancel();
io_service.run();
}
跑步时输出:
in handler
documentation详细说明了如何确定返回类型:
默认情况下,启动函数返回
void
。当处理程序是函数指针,C ++ 11 lambda或由boost::bind
或std::bind
生成的函数对象时,情况总是如此。对于其他类型,可以通过
async_result
模板的特化来定制返回类型,该模板既用于确定返回类型,也用于从处理程序中提取返回值。 / p>
例如,Boost.Asio专门针对boost::asio::async_result
boost::asio::use_future
。当boost::asio::use_future
作为iniating函数的处理程序提供时,返回类型为std::future
。
答案 1 :(得分:1)
你不是。改为使用lambda:
auto func = [&timer](const function<void(const error_code&)>& cb) {
timer.async_wait(cb);
};
func(handler);
bind
首先不是最方便的用法,但在处理重载成员函数时,这一点尤其痛苦。也就是说,如果您只是说&steady_timer::async_wait
,那么您就会模糊不清,并且编译器无法确定您指的是哪个重载。
您可以通过explicitly casting to the correct type解决此问题,但对于像steady_timer
这样的复杂类型来说,这将非常痛苦。 lambda优雅地解决问题,并为编译器提供了额外的优化机会,因为它不像bind
创建的类型那样不透明。