Reputation:
The code below gives an error in the a::b::print
function: Invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'Foo')
.
The error goes away if I comment out the operator<<
overload in namespace b
. But I don't understand why that makes a difference because it has a different signature to the operator<<
overload in namspace a
. What's going on?!
#include <iostream>
class Foo {};
namespace a {
std::ostream &operator<<(std::ostream &os, Foo &foo);
void print(Foo& foo) {
std::cout << foo;
}
namespace b {
std::ostream &operator<<(std::ostream &os, double d); // uncomment to resolve error
void print(Foo& foo) {
std::cout << foo; // error here
}
}
}
Upvotes: 1
Views: 46
Reputation: 6131
As namespace b
is nested inside namespace a
, names declared in b
will hide names declared in a
. When name lookup occurs in a::b::print
, it searches b
, and if it doesn't find what it's looking for continues searching in a
. So it does find operator<< in b
and stops looking, and does not even consider the proper one in a
. When you comment it out, it doesn't find it in b
, and continues searching into a
and finds it. You could fix this by adding this in namespace b:
using a::operator<<;
However, the real problem with your code is that you're not utilizing ADL (argument dependent lookup) properly. Operators that work on user defined types should be in the same namespace as the types they operate on. What ADL does is add extra namespaces to search, so that any arguments (or template parameters) involved with the call will have their namespace considered--automatically. (This is why you can use the operators provided in the std
namespace for builtin types when your code is outside std
.)
So move operator<<
out of namespace a
and into the same (global) namespace where Foo
is. Or, probably better, move Foo
into namespace a
.
Upvotes: 1