0
votes

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 why 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.

3
9/10 weird compiler errors will be evident if you start simplifying everything to explain it better. I don't know what handleMimeVersion is, nor m_strand. Post full examples.Tom Kerr
I added the declarations and clarified the problem. I hope this helps. The problem is not with the handler but with the customized match_condition being a member function. Thanks.Roger

3 Answers

2
votes

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.

1
votes

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
0
votes

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);