【问题标题】:Why can't std::bind and boost::bind be used interchangeably in this Boost.Asio tutorials为什么 std::bind 和 boost::bind 在这个 Boost.Asio 教程中不能互换使用
【发布时间】:2012-02-21 07:36:55
【问题描述】:

我正在尝试 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? 中所述),此错误来自哪里?

【问题讨论】:

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

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


【解决方案1】:

boost::asio::io_service::run() 成员函数被重载:一个版本不带参数,而另一个版本带一个参数。也就是说,取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);

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

【讨论】:

    【解决方案2】:

    请注意,在 C++11 及以后的版本中,您可以使用 lambdas 来避免所有麻烦并大大简化整个事情。老人:

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

    【讨论】:

    • 好多了!
    • 通常您希望将该线程放入向量中。但是写成 lambda 向量是不可移动的,所以你需要使用 threadPool.emplace_back(std::move(t))
    【解决方案3】:

    这是一个巨大的 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;
    

    【讨论】:

      【解决方案4】:

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

      要获得正确的输出,解决方案(在 asio 独立或 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();});
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-20
        • 1970-01-01
        相关资源
        最近更新 更多