schuess
schuess

Reputation: 1059

boost::asio::async_read_until with custom match condition operator overload confusion

I am attempting to using a custom match function as part of a boost::asio composed operation. VS2017 cannot deduce the parameters with the custom match condition when passing in a std::move(*this) as the handler for an async operation.

The composed operation is a class that has a void operator()(boost::beast::error_code ec, std::size_t bytes_transferred) overload. eg:

class match_char
{
public:
  explicit match_char(char c) : c_(c) {}

  template <typename Iterator>
  std::pair<Iterator, bool> operator()(
      Iterator begin, Iterator end) const
  {
    Iterator i = begin;
    while (i != end)
      if (c_ == *i++)
        return std::make_pair(i, true);
    return std::make_pair(i, false);
  }

private:
  char c_;
};

namespace asio {
  template <> struct is_match_condition<match_char>
    : public boost::true_type {};
} // namespace asio

template<class AsyncStream, class DynamicBuffer, class Handler>
class composed_op
{
 public:
 int state = 0;
 // --- boilerplate code
 void operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
 {
     switch(state)
     {
          case x:
               return boost::asio::async_read_until(stream, buffer, match_char('a'), std::move(*this));
     }
 }

}

When using a straight void handler(boost::system::error_code ec, std::size_t bytes); instead of std::move(*this) is compiles fine. The follow is the output from MSVC 2017. Any help in being able to tell the compiler which overload to use would be greatly appreciated.

1>C:\Users\xxxx\builds\dev\src\comm/read_msg.hpp(310): error C2665: 'boost::asio::read_until': none of the 5 overloads could convert all the argument types
1>C:\Users\xxxx\builds\boost_1_64_0\boost/asio/impl/read_until.hpp(265): note: could be 'size_t boost::asio::read_until<AsyncStream,std::allocator<char>,comm::detail::match_char>(SyncReadStream &,boost::asio::basic_streambuf<std::allocator<char>> &,MatchCondition,boost::system::error_code &,void *)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            SyncReadStream=boost::beast::test::string_iostream,
1>            MatchCondition=comm::detail::match_char
1>        ]
1>C:\Users\xxxx\builds\boost_1_64_0\boost/asio/impl/read_until.hpp(317): note: or       'size_t boost::asio::read_until<AsyncStream,std::allocator<char>,comm::detail::match_char>(SyncReadStream &,boost::asio::basic_streambuf<std::allocator<char>> &,MatchCondition,void *)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            SyncReadStream=boost::beast::test::string_iostream,
1>            MatchCondition=comm::detail::match_char
1>        ]
1>C:\Users\xxxx\builds\boost_1_64_0\boost/asio/impl/read_until.hpp(206): note: or       'size_t boost::asio::read_until<AsyncStream,std::allocator<char>>(SyncReadStream &,boost::asio::basic_streambuf<std::allocator<char>> &,const boost::regex &,boost::system::error_code &)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            SyncReadStream=boost::beast::test::string_iostream
1>        ]
1>C:\Users\xxxx\builds\boost_1_64_0\boost/asio/impl/read_until.hpp(139): note: or       'size_t boost::asio::read_until<AsyncStream,std::allocator<char>>(SyncReadStream &,boost::asio::basic_streambuf<std::allocator<char>> &,const std::string &,boost::system::error_code &)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            SyncReadStream=boost::beast::test::string_iostream
1>        ]
1>C:\Users\xxxx\builds\boost_1_64_0\boost/asio/impl/read_until.hpp(48): note: or       'size_t boost::asio::read_until<AsyncStream,std::allocator<char>>(SyncReadStream &,boost::asio::basic_streambuf<std::allocator<char>> &,char,boost::system::error_code &)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            SyncReadStream=boost::beast::test::string_iostream
1>        ]
1>C:\Users\xxxx\builds\dev\src\comm/read_msg.hpp(310): note: while trying to match the argument list '(boost::beast::test::string_iostream, boost::asio::streambuf, comm::detail::match_char, comm::read_msg_op<AsyncStream,DynamicBuffer,____C_A_T_C_H____T_E_S_T____74::<lambda_881e0622dc11cafb22751f624439b95e>>)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            DynamicBuffer=comm::wire_msg
1>        ]
1>C:\Users\xxxx\builds\dev\src\comm/read_msg.hpp(286): note: while compiling class template member function 'void comm::read_msg_op<AsyncStream,DynamicBuffer,____C_A_T_C_H____T_E_S_T____74::<lambda_881e0622dc11cafb22751f624439b95e>>::operator ()(boost::beast::error_code,::size_t)'
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            DynamicBuffer=comm::wire_msg
1>        ]
1>C:\Users\xxxx\builds\dev\src\comm/read_msg.hpp(483): note: see reference to function template instantiation 'void comm::read_msg_op<AsyncStream,DynamicBuffer,____C_A_T_C_H____T_E_S_T____74::<lambda_881e0622dc11cafb22751f624439b95e>>::operator ()(boost::beast::error_code,::size_t)' being compiled
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            DynamicBuffer=comm::wire_msg
1>        ]
1>C:\Users\xxxx\builds\dev\src\comm/read_msg.hpp(483): note: see reference to class template instantiation 'comm::read_msg_op<AsyncStream,DynamicBuffer,____C_A_T_C_H____T_E_S_T____74::<lambda_881e0622dc11cafb22751f624439b95e>>' being compiled
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            DynamicBuffer=comm::wire_msg
1>        ]
1>C:\Users\xxxx\builds\dev\src\comm\test\read_msg_test.cpp(55): note: see reference to function template instantiation 'void comm::read_msg<boost::beast::test::string_iostream,comm::wire_msg,____C_A_T_C_H____T_E_S_T____74::<lambda_881e0622dc11cafb22751f624439b95e>&>(AsyncStream &,DynamicBuffer &,CompletionToken)' being compiled
1>        with
1>        [
1>            AsyncStream=boost::beast::test::string_iostream,
1>            DynamicBuffer=comm::wire_msg,
1>            CompletionToken=____C_A_T_C_H____T_E_S_T____74::<lambda_881e0622dc11cafb22751f624439b95e> &
1>        ]

Upvotes: 1

Views: 1290

Answers (1)

Tom Trebicky
Tom Trebicky

Reputation: 648

I am not sure what you are trying to achieve with std::move(*this) but even if it was a well-written handler, which it is not, it is not a good idea to delete a handler from underneath asio's hand.

Without knowing the end goal, I would remedy the situation with something like this

return boost::asio::async_read_until(
    stream, buffer, match_char('a'),
    [this](const boost::system::error_code& ec, size_t bytes_transferred) {
      // handler code comes here
      // is the following what you are trying to achieve?
      this->operator()(ec, bytes_transferred);
    });

If your concern is the lifetime of composed_op<> then you need to use a different approach and I would recommend composed_op to inherit from std::enable_shared_from_this<> and rewriting the handler like this:

return boost::asio::async_read_until(
    stream, buffer, match_char('a'),
    [self = shared_from_this()]
    (const boost::system::error_code& ec, size_t bytes_transferred) {
      // handler code comes here
      // is the following what you are trying to achieve?
      self->operator()(ec, bytes_transferred);
    });

Footnote: For additional info on how to use shared_ptr to ensure lifetime in asio operations, check out Reserving memory for asynchronous send buffers (boost asio sockets)

Upvotes: 3

Related Questions