为什么std :: bind和boost :: bind不能在这个Boost.Asio教程中互换使用

时间:2012-01-28 19:59:11

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

我在Boost.Asio文档中尝试了不同的教程,并尝试用C ++ 11替换boost组件。但是,我在Timer.5 - Synchronising handlers in multithreaded programs中使用std :: bind时出错了。这是建议的代码:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

class printer { /* Not relevent here */ };

int main()
{
  boost::asio::io_service io;
  printer p(io);
  boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
  io.run();
  t.join();

  return 0;
}

我尝试将boost::thread替换为std::thread,将boost::bind替换为std::bind。这是我的代码:

#include <functional>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

class printer { /* Not relevent here */ };

int main() {
    boost::asio::io_service io;
    printer p(io);
    std::thread t(std::bind(&boost::asio::io_service::run, &io));
    io.run();
    t.join();
}

使用GCC 4.7进行编译时,出现了编译时错误:

g++ -std=c++0x main.cpp -lboost_system -lboost_date_time -lpthread
main.cpp: In function ‘int main()’:
main.cpp:52:60: erreur: no matching function for call to ‘bind(<unresolved overloaded function type>, boost::asio::io_service*)’
main.cpp:52:60: note: candidates are:
/usr/include/c++/4.6/functional:1444:5: note: template<class _Functor, class ... _ArgTypes> typename std::_Bind_helper::type std::bind(_Functor&&, _ArgTypes&& ...)
/usr/include/c++/4.6/functional:1471:5: note: template<class _Result, class _Functor, class ... _ArgTypes> typename std::_Bindres_helper::type std::bind(_Functor&&, _ArgTypes&& ...)

此错误来自何处,考虑到我没有使用任何boost::asio::placeholders(如此stackoverflow问题Should std::bind be compatible with boost::asio?中的解释)?

4 个答案:

答案 0 :(得分:35)

boost::asio::io_service::run()成员函数被重载:一个版本不带参数,而另一个版本带一个参数。也就是说,取boost::asio::io_service::run的地址需要一个上下文,在该上下文中编译器可以直接推导出函数的签名。但是,std::bind()不需要执行演绎魔法,而boost::bind()似乎试图找到匹配的重载,即它的第一个参数类型似乎很容易被约束(假设增强示例确实编译)

解决这个问题,您可以明确指定std::bind()的第一个参数的类型(它也适用于boost::bind()),例如像这样:

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

我没有检查标准是否有任何要求,但如果它确实没有做任何要求,我会考虑一个实现,去英雄主义推断参数类型是更好的质量,虽然它的工作量更少:它要求用户编写可以在另一个编译器上编译的代码。

答案 1 :(得分:12)

快速说明一下,在C ++ 11之后,你可以使用lambdas来避免所有的faff并大大简化整个事情。老人:

boost::thread t(boost::bind(&boost::asio::io_service::run, &io));

或std :: version:

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

变得只是:

std::thread t([&io_service](){io_service.run();});

答案 2 :(得分:1)

这是一个巨大的PITA,所以谢谢Dietmar的暗示。对于那些使用boost :: bind的人,你的解决方案看起来像这样:

// create the io_service    

boost::asio::io_service io_service;

 // assign some work to asio before starting
 {
    io_service.post(&some_work);   // just for example
    ....
 }

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

// work should be executed in a new thread

t.join()

return;

答案 3 :(得分:0)

  

由于您已经在使用C ++ 11:lambdas可能是std :: bind的替代品,例如std :: thread t(&amp; io {io.run();}); 。这完全避免了重载决策。

要获得正确的输出,解决方案(在asio standalone或boost :: asio中)是:

asio::io_service io;
auto ptrToIoService = &io;
printer p(io);

//asio::thread t(std::bind(&asio::io_service::run, &io));
//asio::thread t([&io]() {io.run();});
asio::thread t([ptrToIoService] () { ptrToIoService->run();});

参见&#34;有效的现代C ++&#34;在&#34;项目31下避免默认捕获模式。&#34;