为什么boost :: asio :: io_service不能用std :: bind编译?

时间:2015-03-01 13:42:58

标签: c++ c++11 boost boost-asio

我正在尝试使用std::thread 4.9.1(std::bind)编译boost::asiog++-std=c++11的简单测试程序。

但是,当我使用std::bind时,在创建新线程时,它不会编译。另一方面,当我切换到boost::bind时,一切都很好。

以下是代码:

#include <iostream>
#include <memory>
#include <thread>
#include <functional>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

int main(int argc, char* argv[])
{
    boost::asio::io_service ioService;
    std::unique_ptr<std::thread> t;

    t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
    //t.reset(new std::thread(boost::bind(&boost::asio::io_service::run, &ioService)));
    return 0;
}

这是错误:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:12:80: error: no matching function for call to ‘bind(<unresolved overloaded function type>, boost::asio::io_service*)’
    t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
                                                                                            ^
test.cpp:12:80: note: candidates are:
In file included from /usr/include/c++/4.9/memory:79:0,
             from test.cpp:2:
/usr/include/c++/4.9/functional:1623:5: note: template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__or_<std::is_integral<typename std::decay<_Tp>::type>, std::is_enum<typename std::decay<_Tp>::type> >::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...)
 bind(_Func&& __f, _BoundArgs&&... __args)
 ^
/usr/include/c++/4.9/functional:1623:5: note:   template argument deduction/substitution failed:
test.cpp:12:80: note:   couldn't deduce template parameter ‘_Func’
    t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
                                                                             ^
In file included from /usr/include/c++/4.9/memory:79:0,
             from test.cpp:2:
/usr/include/c++/4.9/functional:1650:5: note: template<class _Result, class _Func, class ... _BoundArgs> typename std::_Bindres_helper<_Result, _Func, _BoundArgs>::type std::bind(_Func&&, _BoundArgs&& ...)
 bind(_Func&& __f, _BoundArgs&&... __args)
 ^
/usr/include/c++/4.9/functional:1650:5: note:   template argument deduction/substitution failed:
test.cpp:12:80: note:   couldn't deduce template parameter ‘_Result’
    t.reset(new std::thread(std::bind(&boost::asio::io_service::run, &ioService)));
                                                                            ^

我错过了什么?

4 个答案:

答案 0 :(得分:12)

错误消息表明std::bind()无法确定要使用哪个io_service::run()重载:

std::size io_service::run();
std::size io_service::run(boost::system::error_code&);

对于这种特殊情况,Boost.Bind没有问题,但它确实为binding an overloaded functions提供了一些故障排除。它建议铸造:

std::bind(
  static_cast<std::size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run),
  &ioService);

或使用临时变量:

std::size_t (boost::asio::io_service::*run)() = &boost::asio::io_service::run;
std::bind(run, &ioService);

std::bind()而非boost::bind()需要显式强制转换的原因是实现细节。如果对bind()的调用的arity没有对被绑定的函数类型设置约束,那么重载函数将需要显式转换。

例如,考虑使用可变参数模板的情况:

template<class F, class... BoundArgs>
unspecified std::bind(F&& f, BoundArgs&&... bound_args);

如果选择了最匹配的std::bind()重载,则std::bind()的调用对F没有任何限制。由于F可能是以下任何一种:

  • std::size_t (boost::asio::io_service::*)()
  • std::size_t (boost::asio::io_service::*)(boost::system::error_code&)

表达式&boost::asio::io_service::run()含糊不清。

另一方面,Boost.Bind是用重载函数实现的,其中对boost::bind()的调用的arity对被绑定函数的arity设置了约束。它的接口synopsis列出了以下值得注意的重载:

// 2 args: member-to-function (arity:0), instance
template <class R, class T, class A1>
unspecified bind(R (T::*f)(), A1 a1);

// 3 args: member-to-function (arity:1), instance, arg1
template <class R, class T, class B1, class A1, class A2>
unspecified bind(R (T::*f)(B1), A1 a1, A2 a2);

请注意boost::bind()有:

  • arity为2,指向成员函数的指针具有0
  • 的arity
  • 3的arity,指向成员的函数具有1
  • 的arity

因此,在致电时:

boost::bind(&boost::asio::io_service::run, &ioService)

潜在匹配的boost::bind()重载具有2的arity,因此指向成员的函数必须是arity为0的函数类型。因为{的集合中只有一个函数{1}}重载的arity为0,调用不明确。

答案 1 :(得分:9)

基于错误消息boost::asio::io_service::run过载或成员模板,std::bind()无法确定要使用的过载或实例化。你需要使用这样的东西,在取得地址时推断出合适的类型,例如,

static_cast<std:size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run)

关键问题是,取boost::asio::io_service::run的地址会导致成员函数有两种选择,但在获取地址时,无法确定使用哪一种。只有在使用成员函数时,才会明确表示不使用其他参数的版本。但是,地址运算符不会产生过载集。

为了推断出需要哪个重载,std::bind()需要提供一个自身的重载,它具有适当的类型作为其第一个参数。但是,我认为它无法确定应该是什么类型。我不知道它与std::boost::bind()的实际效果如何!我可以想象boost::bind()对于没有参数的成员函数有特殊的重载,可能还有boost::error_code的一个,但我真的不知道这会有什么帮助。

但是使用lambda函数可能更容易:

std::thread t([&](){ ioService.run(); });
t.join(); // without a joining or detaching terminate() is called

答案 2 :(得分:1)

理解此错误的关键是unresolved overloaded function type部分

这意味着编译器无法确定要使用哪个重载版本的boost::asio::io_service::run

the docs中查看有两个版本,您想要使用std::size_t run()。要将此信息传达给编译器,我们需要static_cast函数指针指向重载变量的显式类型,这里std:size_t (boost::asio::io_service::*)()

因此我们写static_cast<std::size_t (boost::asio::io_service::*)(void)>(&boost::asio::io_service::run)代替&boost::asio::io_service::run

完整代码如下所示

boost::asio::io_service ioService;
std::unique_ptr<std::thread> t;

t.reset(new std::thread(std::bind(
    static_cast<std::size_t(boost::asio::io_service::*)(void)>(&boost::asio::io_service::run),
    &ioService
)));

答案 3 :(得分:1)

Boost Bind支持绑定为绑定成员函数的this参数的智能指针。

这是std :: bind和boost :: bind之间相当大的(也是很棒的)差异。

Boost Asio一直推广模式¹,它严重依赖绑定到shared_pointer<T>,其中T可以是异步IO上下文中具有“神奇管理”生命周期的任何东西,例如connectionclientsessiontransfer等。

当然c ++ 11 lambdas可以直接支持(通过复制捕获共享指针)。


¹例如