Search code examples
c++boostboost-test

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’

Solution

  • 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
            {