c++namespacesargument-dependent-lookup

why does 'using namespace' not take priority when in a namespace


This is a follow-up to no match for operator<<(std::ostream, ns::Type) when in the global namespace, combined with the namespace numerical_chars trick from https://stackoverflow.com/a/21389821/1888983. I want two things:

  1. To cout << thirdPartyType defined in a namespace I don't own
  2. To use the numerical_chars::operator<<(ostream, char) in that namespace

In inline std::ostream& ns::operator<<(std::ostream& os, const ns::Foo& foo) below I'm trying to print an (int8_t)-1. Why does using namespace numerical_chars; not work? It does work if I don't wrap Foo in namespace ns.

#include <ostream>
#include <iostream>

namespace numerical_chars {
inline std::ostream& operator<<(std::ostream& os, signed char c)
{
  return os << static_cast<int>(c);
}
}  // namespace numerical_chars

namespace ns {
struct Foo { int8_t x = -1; };
inline std::ostream& operator<<(std::ostream& os, const Foo& foo)
{
    using namespace numerical_chars; // does nothing
    //using numerical_chars::operator<<; // one solution
    return os << foo.x; // pls print "-1", not (char)-1
}
} // namespace ns

int main()
{
    ns::Foo foo;
    std::cout << foo;
    return 0;
}

https://godbolt.org/z/od94MY3hc

Importing the numerical_chars::operator<< operator specifically does work, but why not the whole namespace?

Removing operator<<(std::ostream& os, const Foo& foo) from namespace ns also works, but unfortunately I need that because I don't own ns::Foo and have to add the operator there for ADL (see the first link above).

(Yes, I can also just cast Foo::x to an int)


Solution

  • As explained on cppreference, using namespace doesn't bring the names into the current scope. It brings them to the most nested common enclosing namespace of the current namespace and the one you're importing.

    In this case that common namespace is ::, so it behaves as if you declared your operators in the global namespace. They are understandably shadowed by ns::operator<< when inside of namespace ns.