简体   繁体   English

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

[英]Why can't std::bind and boost::bind be used interchangeably in this Boost.Asio tutorials

I was trying the differents tutorials in Boost.Asio documentation and tried to replace boost components with C++11 ones. 我在Boost.Asio文档中尝试了不同的教程,并试图用C ++ 11替换boost组件。 However, I got an error using std::bind in Timer.5 - Synchronising handlers in multithreaded programs . 但是,我在Timer.5中使用std :: bind时出错了 - 在多线程程序中同步处理程序 Here is the code proposed: 这是建议的代码:

#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;
}

I tried to replace boost::thread by std::thread and boost::bind by std::bind . 我试图取代boost::thread通过std::threadboost::bind通过std::bind Here is my code: 这是我的代码:

#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();
}

When compiling with GCC 4.7, I got this compile-time error: 在使用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&& ...)

Where is this error comming from, taking into account that I did not use any boost::asio::placeholders (as explain in this stackoverflow question Should std::bind be compatible with boost::asio? )? 这个错误来自何处,考虑到我没有使用任何boost::asio::placeholders (在此stackoverflow问题中解释应该std :: bind是否与boost :: asio兼容? )?

The boost::asio::io_service::run() member function is overloaded: one version takes no argument while another version takes one argument. boost::asio::io_service::run()成员函数被重载:一个版本不带参数,而另一个版本带一个参数。 That is, taking the address of the of boost::asio::io_service::run requires a context in which the compiler can directly deduce the signature of the function. 也就是说,获取boost::asio::io_service::run需要一个上下文,在该上下文中编译器可以直接推导出函数的签名。 However, std::bind() isn't required to do deduction magic while it seems that boost::bind() attempts to locate a matching overload ie it seems for its first argument type to be readily constrained (assuming the boost example indeed compiles). 但是, std::bind()不需要做演绎魔法,而似乎boost::bind()试图找到匹配的重载,即它的第一个参数类型似乎很容易被约束(假设确实是增强示例)编译)。

The work-around this problem you can explicitly specify the type of the first argument to std::bind() (it should also work with boost::bind() ) eg like this: 解决这个问题你可以明确指定std::bind()的第一个参数的类型(它也应该与boost::bind() ),例如:

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

I haven't checked whether the standard makes any requirements but if it indeed doesn't do any requirements I would consider an implementation which does not go to heroics to deduce the argument type to be of better quality although it does less work: it requires that the user writes code which can compile unchanged on another compiler. 我没有检查标准是否有任何要求,但如果它确实没有做任何要求,我会考虑一个实现,虽然它的工作量较少,但是并没有用英雄来推断出论证类型的质量更好:它需要用户编写的代码可以在另一个编译器上编译。

Just a quick note, in C++11 onwards you can just use lambdas to avoid all the faff and simplify the whole thing greatly. 简单来说,在C ++ 11之后,你可以使用lambdas来避免所有的faff并大大简化整个事情。 The old: 老人:

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

or the std::version: 或者std :: version:

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

become just: 变得公正:

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

This was a huge PITA to figure out, so thank you Dietmar for the hint. 这是一个巨大的PITA,所以谢谢Dietmar的暗示。 for those using the boost::bind, you solution looks like this: 对于那些使用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;

Since you're already using C++11: lambdas may be an alternative to std::bind for you, eg, std::thread t(&io { io.run(); });. 由于您已经在使用C ++ 11:lambdas可能是std :: bind的替代品,例如,std :: thread t(&io {io.run();});. This avoid the overload resolution entirely. 这完全避免了重载决策。

To get the right output, the solution(in asio standalone or boost::asio) is: 要获得正确的输出,解决方案(在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();});

See "Effective Modern C++" under "Item 31 Avoid default capture modes." 请参阅“项目31避免默认捕获模式”下的“有效的现代C ++”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM