boost async_read_until problem with custom match function won't complile in GCC
The following code compiles and works with visual studio 2010 but won't complile under GCC:
Declarations:
boost::asio::strand m_strand;
typedef boost::asio::buffers_iterator< boost::asio::streambuf::const_buffers_type > iterator;
std::pair<iterator, bool> match_version(iterator begin, iterator end);
Implimentation:
std::pair<TcpMimeConnection::iterator, bool> TcpMimeConnection::match_version(iterator begin, iterator end)
{
boost::match_results<iterator> matchResult;
const bool found = boost::regex_search( begin, end, matchResult, boost::regex("MIME-Version:\\s*1.0\\s*\r\n", boost::regex::icase));
if(found)
{
versionFound = true;
return std::make_pair(matchResult[0].second, true);
}
else if (std::distance(begin,end) >= MAX_STREAM_READ_SIZE)
{
return std::make_pair(end, true);
}
return std::make_pair(begin, false);
}
/**
* Start an async read to of a mime message.
* @return the operation ID for this operation.
*/
sapphire::OperationId TcpMimeConnection::read()
{
const sapphire::OperationId id = getNextOperationId();
versionFound = false;
aio::async_read_until(
socket(),
buffer(),
boost::bind(&TcpMimeConnection::match_version, shared_from_this(), _1, _2),
m_strand.wrap(
boost::bind(
&TcpMimeConnection::handleMimeVersion,
shared_from_this(),
id,
aio::placeholders::error,
aio::placeholders::bytes_transferred)));
return id;
}
I get the following error:
[11:20:59]: TcpMimeConnection.cpp:372: instantiated from here [11:20:59]: read_until.hpp:60: error: call of overloaded ‘helper(const boost::_bi::bind_t, bool>, boost::_mfi::mf2, bool>, sapphire::transport::ip::TcpMimeConnection, boost::asio::buffers_iterator, boost::asio::buffers_iterator >, boost::_bi::list3 >, boost::arg<1>, boost::arg<2> > >&)’ is ambiguous [11:20:59]: read_until.hpp:57: note: candidates are: static boost::asio::detail::has_result_type::big boost::asio::detail::has_result_type::helper(U, ...) [with U = boost::_bi::bind_t, bool>, boost::_mfi::mf2, bool>, sapphire::transport::ip::TcpMimeConnection, boost::asio::buffers_iterator, boost::asio::buffers_iterator >, boost::_bi::list3 >, boost::arg<1>, boost::arg<2> > >, T = boost::_bi::bind_t, bool>, boost::_mfi::mf2, bool>, sapphire::transport::ip::TcpMimeConnection, boost::asio::buffers_iterator, boost::asio::buffers_iterator >, boost::_bi::list3 >, boost::arg<1>, boost::arg<2> > >] [11:20:59]: read_until.hpp:58: note: static char boost::asio::detail::has_result_type::helper(U, typename U::result_type*) [with U = boost::_bi::bind_t, bool>, boost::_mfi::mf2, bool>, sapphire::transport::ip::TcpMimeConnection, boost::asio::buffers_iterator, boost::asio::buffers_iterator >, boost::_bi::list3 >, boost::arg<1>, boost::arg<2> > >, T = boost::_bi::bind_t, bool>, boost::_mfi::mf2, bool>, sapphire::transport::ip::TcpMimeConnection, boost::asio::buffers_iterator, boost::asio::buffers_iterator >, boost::_bi::list3 >, boost::arg<1>, boost::arg<2> > >] [11:20:59]: TcpMimeConnection.cpp: In member function ‘virtual sapphire::OperationId sapphire::transport::ip::TcpMimeConnection::read()’: [11:20:59]: sapphire/transport/ip/TcpMimeConnection.cpp:372: error: no matching function for call to ‘async_read_until(boost::asio::basic_stream_socket >&, boost::asio::basic_streambuf >&, boost::_bi::bind_t, bool>, boost::_mfi::mf2, bool>, sapphire::transport::ip::TcpMimeConnection, boost::asio::buffers_iterator, boost::asio::buffers_iterator >, boost::_bi::list3 >, boost::arg<1>, boost::arg<2> > >, boost::asio::detail::wrapped_handler, boost::_bi::list4 >, boost::_bi::value, boost::arg<1> ()(), boost::arg<2> ()()> > >)’
When I simply passed the boost::regex("MIME-Version:\s*1.0\s*\r\n", boost::regex::icase) into the async_read_until (third overload) there was no problems, but I wanted to customize the match condition of the async_read_until (fourth overload) and I ran into problems when I made the match condition an member function. I need match_version to be a member function since there is no way to signal the handler wh开发者_开发百科y its returning (size or match found). So I know the problem is with the boost::bind(&TcpMimeConnection::match_version, shared_from_this(), _1, _2), line of code but I don't know how to fix it.
It appears that in order to use a binder as a match, you will need to specialize boost::asio::is_match_condition
for this type, even though the documentation states that anything that defines a result_type
can be used.
After adding all the necessary stuff to make your code compile (next time, please post a compilable example), I was able to reproduce your error, and I was able to fix it by adding the following:
namespace boost {
namespace asio {
template <> struct is_match_condition<
decltype(
boost::bind(&TcpMimeConnection::match_version,
shared_ptr<TcpMimeConnection>(), _1, _2)
)>
: public boost::true_type {};
}
}
This is obviously unwieldy, I would use a named function object here instead of a binder.
Here is the solution I used based off of Cubbi's answer that compiles under both visual studio 2010 and gcc 4.4.2:
class MatchVersion {
public:
explicit MatchVersion(bool& versionFound) : m_versionFound(versionFound) {}
typedef boost::asio::buffers_iterator<
boost::asio::streambuf::const_buffers_type>
iterator;
template <typename Iterator>
std::pair<Iterator, bool> operator()(Iterator begin, Iterator end) const {
boost::match_results<iterator> matchResult;
const bool found = boost::regex_search(
begin, end, matchResult,
boost::regex("MIME-Version:\\s*1.0\\s*\r\n", boost::regex::icase));
if (found) {
m_versionFound = true;
return std::make_pair(matchResult[0].second, true);
} else if (std::distance(begin, end) >=
sapphire::transport::ip::TcpMimeConnection::
MAX_STREAM_READ_SIZE) {
return std::make_pair(end, true);
}
return std::make_pair(begin, false);
}
MatchVersion(const MatchVersion& other)
: m_versionFound(other.m_versionFound) {}
private:
bool& m_versionFound;
MatchVersion& operator=(const MatchVersion& other);
};
namespace boost::asio {
template <>
struct is_match_condition<MatchVersion> : public boost::true_type {};
} // namespace boost::asio
namespace sapphire::transport::ip {
sapphire::OperationId TcpMimeConnection::read() {
const sapphire::OperationId id = getNextOperationId();
m_versionFound = false;
aio::async_read_until(
socket(), buffer(), MatchVersion(m_versionFound),
m_strand.wrap(boost::bind(
&TcpMimeConnection::handleMimeVersion, shared_from_this(), id,
aio::placeholders::error, aio::placeholders::bytes_transferred)));
return id;
}
} // namespace sapphire::transport::ip
I can't see anything obvious, but asio interfaces are abysmal.
When I have problems like this, I start breaking up inline code. Given your last statement, I'd guess shared_from_this may be confusing it. If you start explicitly saying what you think all these inline things mean, you may discover your bad assumption.
boost::shared_ptr<TcpMimeConnection> temp = shared_from_this();
boost::bind(&TcpMimeConnection::match_version, temp, _1, _2);
or
boost::bind(&TcpMimeConnection::match_version, this, _1, _2);
精彩评论