Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BOOST_CHECK_EQUAL with pair<int, int> and custom operator <<

When attempting to do a BOOST_CHECK_EQUAL(pair, pair), gcc doesnt find the stream operator for pair, inspite of declaring it. The funny thing is that std::out finds the operator.

ostream& operator<<(ostream& s, const pair<int,int>& p) {
    s << '<' << p.first << ',' << p.second << '>';
    return s;
}


BOOST_AUTO_TEST_CASE(works)
{
    pair<int,int> expected(5, 5);
    pair<int,int> actual  (5, 5);
    std::cout << expected << std::endl;
    std::cout << actual   << std::endl;
    BOOST_CHECK(actual == expected);
}

BOOST_AUTO_TEST_CASE(no_work)
{
    pair<int,int> expected(5, 5);
    pair<int,int> actual  (5, 5);
    BOOST_CHECK_EQUAL(actual, expected);
}

This doesnt compile with the error:

...  instantiated from here
../boost-atp/release/include/boost/test/test_tools.hpp:326:9: error: no match for ‘operator<<’ in ‘ostr << t’
like image 400
nishantjr Avatar asked Jun 11 '12 07:06

nishantjr


2 Answers

Putting operator<< in std like Remus's answer is undefined behavior in the C++ 14 draft (N4296 section:17.6.4.2.1). Boost provides a hook (used by this answer) and you can write:

namespace boost
{
    namespace test_tools
    {
        template<typename T,typename U>
        struct print_log_value<std::pair<T, U> >
        {
            void operator()(std::ostream& os, std::pair<T, U> const& pr)
            {
                os << "<" << std::get<0>(pr) << "," << std::get<1>(pr) << ">";
            }
        };
    }
}

print_log_value is a template so if you are not declaring a templated value like pair<T,U>, you will need to write something like:

template<>
struct print_log_value<MyType>{ /* implementation here*/ };

Edit

If you are using boost 1.59 or later you need to use namespace boost::test_tools::tt_detail instead. That is, the code needs to start:

namespace boost
{
    namespace test_tools
    {
        namespace tt_detail
        {
like image 84
Eponymous Avatar answered Oct 29 '22 11:10

Eponymous


Try putting the operator itself in the std namespace:

namespace std
{
  ostream& operator<<(ostream& s, const pair<int,int>& p) {
    s << '<' << p.first << ',' << p.second << '>';
    return s;
  }
}

Update: perhaps this is why the ADL fails (at least on llvm):

Just like before, unqualified lookup didn't find any declarations with the name operator<<. Unlike before, the argument types both contain class types: one of them is an instance of the class template type std::basic_ostream, and the other is the type ns::Data that we declared above. Therefore, ADL will look in the namespaces std and ns for an operator<<. Since one of the argument types was still dependent during the template definition, ADL isn't done until the template is instantiated during Use, which means that the operator<< we want it to find has already been declared. Unfortunately, it was declared in the global namespace, not in either of the namespaces that ADL will look in!

like image 30
Remus Rusanu Avatar answered Oct 29 '22 12:10

Remus Rusanu