1

If you define an operator << for a C++11 enum class, then you can use it successfully with Boost's unit test library.

However if you put the enum class inside a namespace, the Boost code no longer compiles.

Why does putting the enum class inside a namespace stop it from working? It works fine with std::cout both ways so surely this means the operator << is correct?

Here is some sample code demonstrating the issue:

// g++ -std=c++11 -o test test.cpp -lboost_unit_test_framework
#include <iostream>
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE EnumExample
#include <boost/test/unit_test.hpp>

// Remove this namespace (and every "A::") and the code will compile
namespace A {

enum class Example {
    One,
    Two,
};

} // namespace A

std::ostream& operator<< (std::ostream& s, A::Example e)
{
    switch (e) {
        case A::Example::One: s << "Example::One"; break;
        case A::Example::Two: s << "Example::Two"; break;
    }
    return s;
}

BOOST_AUTO_TEST_CASE(enum_example)
{
    A::Example a = A::Example::One;
    A::Example b = A::Example::Two;

    // The following line works with or without the namespace
    std::cout << a << std::endl;

    // The following line does not work with the namespace - why?
    BOOST_REQUIRE_EQUAL(a, b);
}
Malvineous
  • 25,144
  • 16
  • 116
  • 151

1 Answers1

1

You need to define the operator inside the namespace if you want to make use of ADL.

#include <iostream>
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE EnumExample
#include <boost/test/unit_test.hpp>

namespace A {

enum class Example {
    One,
    Two,
};


std::ostream& operator<< (std::ostream& s, Example e)
{
    switch (e) {
        case A::Example::One: s << "Example::One"; break;
        case A::Example::Two: s << "Example::Two"; break;
    }
    return s;
}

} // namespace A

BOOST_AUTO_TEST_CASE(enum_example)
{
    A::Example a = A::Example::One;
    A::Example b = A::Example::Two;

    // The following line works with or without the namespace
    std::cout << a << std::endl;

    // The following line does not work with the namespace - why?
    BOOST_REQUIRE_EQUAL(a, b);
}
user657267
  • 20,568
  • 5
  • 58
  • 77
  • Aha, that explains it, thanks! Since I was declaring the function in a `.hpp` file, I had to put `std::ostream& operator<< (std::ostream& s, Example e);` in the `.hpp` inside the namespace, then in the `.cpp` implementation, put it as `std::ostream& A::operator<< (std::ostream& s, A::Example e)` so it could be implemented outside the namespace. Putting the `.cpp` implementation inside another `namespace A { }` clause doesn't work. – Malvineous Nov 24 '15 at 04:48
  • @Malvineous It's good practice to use fully qualified names when defining stuff anyway, if you mess up the declarations it'll give you an early error during compilation rather than linking. – user657267 Nov 24 '15 at 04:53