1

There's a function accepting an argument with type boost::asio::ip::tcp::socket. But I failed to apply std::bind to it. I've checked template arguments in std::_Bind_helper but no problem found. I've tried both gcc 8.1.0 and clang 6.0.0, and they give the same error.

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

Compilation log and errors:

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.

I'm not sure what caused this error. Could you please give me any suggestions?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
recolic
  • 554
  • 4
  • 18
  • Write `auto f = std::bind(something);` – Passer By May 20 '18 at 08:45
  • @PasserBy I already tried but it doesn't help. The return type is exactly what I wrote here. – recolic May 20 '18 at 08:51
  • 2
    [`boost::ip::tcp::socket`](https://www.boost.org/doc/libs/1_67_0/doc/html/boost_asio/reference/ip__tcp/socket.html) is not copy constructible/assignable, so `fail_f` needs to accepts its arg by reference rather than by value. Also, make use of `auto` as suggested by @PasserBy. – G.M. May 20 '18 at 09:21
  • @G.M. Thanks a lot and it works. However, I tried another solution (by right-value reference) `void fail_f(tcp::socket &&)`+`std::move(tcp::socket(ioc))` and I'm not sure why it fails. Could you please [view it](https://s.recn.pw/d.html) again? – recolic May 20 '18 at 09:41
  • 1
    Bound arguments are always passed as lvalues. – T.C. May 20 '18 at 13:27
  • 3
    @RecolicKeghart Please removed the "solved" from your title, then add your solution as an answer. Stackoverflow is _not_ a forum. – dandan78 May 21 '18 at 09:08
  • This is a Q&A. If you have an A, post an A. Don't add an A to the Q. – Lightness Races in Orbit May 21 '18 at 09:14

1 Answers1

1

void fail_f_1(tcp::socket); std::bind(&fail_f_1, tcp::socket(io_context)); This solution fails because boost::asio::ip::tcp::socket is noncopyable.

void fail_f_2(tcp::socket &&); std::bind(&fail_f_2, std::move(tcp::socket(io_context))); This solution fails because std::bind pass bound arguments as lvalues, rather than rvalue. fixed_f is a good solution.

If you have to pass rvalue-reference as bound argument, this answer will help.

recolic
  • 554
  • 4
  • 18