C++ 为什么可以';t std::bind和boost::bind在这个boost.Asio教程中可以互换使用

C++ 为什么可以';t std::bind和boost::bind在这个boost.Asio教程中可以互换使用,c++,boost,c++11,boost-asio,boost-bind,C++,Boost,C++11,Boost Asio,Boost Bind,我尝试了Boost.Asio文档中的不同教程,并尝试用C++11替换Boost组件。但是,我在使用std::bind-in时出错。建议的守则如下: #include <iostream> #include <boost/asio.hpp> #include <boost/thread/thread.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix

我尝试了Boost.Asio文档中的不同教程,并尝试用C++11替换Boost组件。但是,我在使用std::bind-in时出错。建议的守则如下:

#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;
}
使用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&& ...)
g++-std=c++0x main.cpp-lboost\u系统-lboost\u日期\u时间-lpthread
main.cpp:在函数“int main()”中:
main.cpp:52:60:erreur:bind(,boost::asio::io_service*)调用没有匹配的函数
main.cpp:52:60:注:候选人为:
/usr/include/c++/4.6/functional:1444:5:注意:模板类型名称std::_Bind_helper::type std::Bind(_Functor&,_ArgTypes&&…)
/usr/include/c++/4.6/functional:1471:5:注意:模板类型名称std::_Bindres\u helper::type std::bind(_Functor&,_ArgTypes&&…)

考虑到我没有使用任何
boost::asio::占位符
(如stackoverflow问题中所解释的)

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

解决此问题的方法您可以显式指定
std::bind()
的第一个参数的类型(它也应该与
boost::bind()
一起使用),例如:

std::bind(static_cast<size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io);
// 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;
std::bind(static\u cast(&boost::asio::io\u service::run),&io);

我没有检查标准是否有任何要求,但是如果它确实没有任何要求,我会考虑一个执行<强>不/强>的实现,去英雄,推断参数类型是更好的质量,尽管它的工作量较小:它要求用户编写可以在另一个程序上编译不变的代码。编译器。

这是一个需要解决的巨大问题,因此感谢迪特玛的提示。对于使用boost::bind的用户,您的解决方案如下所示:

std::bind(static_cast<size_t (boost::asio::io_service::*)()>(&boost::asio::io_service::run), &io);
// 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;
//创建io\U服务
boost::asio::io_服务io_服务;
//开始前,为asio分配一些工作
{
io_service.post(&some_work);//仅举个例子
....
}
boost::线程t(boost::bind(static_cast(&boost::asio::io_service::run),&io_service));
//工作应该在新线程中执行
t、 加入
返回;

请注意,在C++11以后的版本中,您可以使用lambdas来避免所有的错误,并大大简化整个过程。老一辈:

boost::threadt(boost::bind(&boost::asio::io_service::run,&io));
或std::版本:

std::threadt(boost::bind(static_cast(&boost::asio::io_service::run),&io_service));
变得公正:

std::线程t([&io_服务](){io_服务.run();});

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

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


请参阅“第31项避免默认捕获模式”下的“有效的现代C++”。

可能的重复:请参阅)。由于您已经在使用C++11:lambdas可以替代
std::bind
,例如,
std::thread t([&io](){io.run();})。这完全避免了过载解决方案。只是更好!通常,您希望将该线程放入向量中。但是作为lambda编写的向量是不可移动的,因此需要使用threadPool.emplace_back(std::move(t))