1

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> ] 

1 Answer 1

3

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)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.