将 std::bind 应用于带有参数 <boost::asio::ip::tcp::socket> 的函数时出错?

Posted

技术标签:

【中文标题】将 std::bind 应用于带有参数 <boost::asio::ip::tcp::socket> 的函数时出错?【英文标题】:Error while appling std::bind to function with argument <boost::asio::ip::tcp::socket>? 【发布时间】:2018-05-20 08:35:09 【问题描述】:

有一个函数接受 boost::asio::ip::tcp::socket 类型的参数。但我未能将 std::bind 应用于它。我检查了 std::_Bind_helper 中的模板参数,但没有发现问题。我已经尝试过 gcc 8.1.0 和 clang 6.0.0,它们给出了相同的错误。

#include <functional>
#include <boost/asio.hpp>
using namespace std;
namespace asio = boost::asio;
using tcp = asio::ip::tcp;

int c;

void good_f(int) c=1;
void good() 
    using typeA = int;

    auto helper = std::bind(&good_f, typeA(1));
    helper();
    // OK


void fixed_f(tcp::socket &) c=1;
void fixed() 
    using type1 = tcp::socket;
    asio::io_context ioc;
    tcp::socket sock(ioc);

    auto helper = std::bind(&fixed_f, std::ref(sock));
    helper();
    // OK


void fail_f(tcp::socket &&) c=1;
void fail() 
    using type1 = tcp::socket;
    asio::io_context ioc;
    tcp::socket sock(ioc);

    // fail_f(std::move(sock));
    // OK

    auto helper = std::bind(&fail_f, std::move(sock));
    helper();
    // a.cc:34:5: error: no matching function for call to object of type 'std::_Bind<void (*(boost::asio::basic_stream_socket<boost::asio::ip::tcp>))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
    //    helper();
    //    ^~~~~~

编译日志和错误:

recolic@RECOLICPC ~/tmp> clang++ --version
clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
recolic@RECOLICPC ~/tmp> clang++ -c a.cc
a.cc:39:5: error: no matching function for call to object of type 'std::_Bind<void (*(boost::asio::basic_stream_socket<boost::asio::ip::tcp>))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
    helper();
    ^~~~~~
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:480:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void
      (*&(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
        operator()(_Args&&... __args)
        ^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:491:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void (*const &(const
      boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
        operator()(_Args&&... __args) const
        ^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:509:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void (*volatile &(volatile
      boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
        operator()(_Args&&... __args) volatile
        ^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../include/c++/8.1.0/functional:521:2: note: candidate template ignored: substitution failure [with _Args = <>]: no type named 'type' in 'std::result_of<void (*const volatile &(const volatile
      boost::asio::basic_stream_socket<boost::asio::ip::tcp> &))(boost::asio::basic_stream_socket<boost::asio::ip::tcp> &&)>'
        operator()(_Args&&... __args) const volatile
        ^
1 error generated.

我不确定是什么导致了这个错误。你能给我一些建议吗?

【问题讨论】:

auto f = std::bind(something); @PasserBy 我已经尝试过了,但没有帮助。返回类型正是我在这里写的。 boost::ip::tcp::socket 不是可复制构造/可赋值的,因此 fail_f 需要通过引用而不是值来接受其 arg。另外,请按照@PasserBy 的建议使用auto 绑定参数总是作为左值传递。 @RecolicKeghart 请从您的标题中删除“已解决”,然后添加您的解决方案作为答案。 ***不是论坛。 【参考方案1】:

void fail_f_1(tcp::socket); std::bind(&fail_f_1, tcp::socket(io_context)); 此解决方案失败,因为 boost::asio::ip::tcp::socket 不可复制。

void fail_f_2(tcp::socket &&); std::bind(&fail_f_2, std::move(tcp::socket(io_context))); 此解决方案失败,因为std::bind 将绑定参数作为左值而不是右值传递。 fixed_f 是一个很好的解决方案。

如果您必须将右值引用作为绑定参数传递,this answer 会有所帮助。

【讨论】:

以上是关于将 std::bind 应用于带有参数 <boost::asio::ip::tcp::socket> 的函数时出错?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::bind 不能作为参数包的参数?

第11课 std::bind和std::function_std::bind绑定器

为啥我会收到带有 std::bind() 的“本地临时返回地址”警告?

本周小贴士#108:避免std::bind

模板类重载 std::bind 成员函数

C++11 std::bind和std::function解析