0

The following code works fine:

#define BOOST_TEST_MODULE TestFoo
#include <boost/test/unit_test.hpp>
#include <boost/dynamic_bitset.hpp>
#include <string>

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T> &v)
{
    os << "[ ";
    for ( const T& elem : v )
        os << elem << ' ';
    return os << ']';
}

typedef boost::dynamic_bitset<> BS;
static const std::vector<BS> foo = { BS(std::string("101")) };

BOOST_AUTO_TEST_CASE( test_foo )
{
    BOOST_CHECK_EQUAL( foo[0], foo[0] );
}

However, when I replace the test case with

BOOST_AUTO_TEST_CASE( test_foo )
{
    BOOST_CHECK_EQUAL( foo, foo );
}

then operator<< is no longer found by the compiler:

/usr/include/boost/test/test_tools.hpp:326:14: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘const std::vector<boost::dynamic_bitset<> >’)

I would expect the compiler to instantiate the operator<< template defined above. Why is this not happening / how to fix?

Henning Koehler
  • 2,456
  • 1
  • 16
  • 20
  • 1
    Unrelated: It's best to not use `#include `. It's a g++ internal header that's supposed to support pre-compiled headers. Since it's non-standard, it can disappear or change dramatically any time you update the tool chain and it flat out doesn't exist on anything but g++. – user4581301 Nov 29 '18 at 00:50
  • @user4581301 Fair point, I simplified the example & removed that distraction. – Henning Koehler Nov 29 '18 at 01:06

1 Answers1

1

edit: see comment, this is UB - there doesn't appear to be a "good" solution to the problem.

wrap your op<< in a namespace std {...}

#include <boost/dynamic_bitset.hpp>
#include <boost/test/unit_test.hpp>

namespace std { // THIS LINE

template <typename T, typename... Rest>
std::ostream& operator<<(std::ostream& os, const std::vector<T, Rest...> &v)
{
    os << "[ ";
    for ( const T& elem : v )
        os << elem << ' ';
    os << ']';
    return os;
}
} // THIS LINE

typedef boost::dynamic_bitset<> BS;
static const std::vector<BS> foo = { BS(std::string("101")) };


BOOST_AUTO_TEST_CASE( test_foo )
{
    BOOST_CHECK_EQUAL( foo, foo );
}

https://godbolt.org/z/xoW-IJ

Otherwise it's not looking in the right namespace for your implementation. Pretty sure this is ADL: https://en.cppreference.com/w/cpp/language/adl

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • This exhibits undefined behavior, per [\[namespace.std\]/1](http://eel.is/c++draft/namespace.std#1) – Igor Tandetnik Nov 29 '18 at 01:07
  • @IgorTandetnik yep, you're right.. but is there any way to introduce this in an ADL-aware fashion? – xaxxon Nov 29 '18 at 01:11
  • That does work, though I'm still not clear why it didn't find it before. The operator was defined in the global namespace, which I thought was always searched? – Henning Koehler Nov 29 '18 at 01:13
  • 1
    "Name lookup rules make it impractical to declare operators in global or user-defined namespace that operate on types from the std namespace, e.g. a custom operator>> or operator+ for std::vector or for std::pair (unless the element types of the vector/pair are user-defined types, which would add their namespace to ADL). Such operators would not be looked up from template instantiations, such as the standard library algorithms. See dependent names for further details." – xaxxon Nov 29 '18 at 01:17