Re: Stream operator in namespace masks global stream operator
On May 9, 4:37 pm, mrstephengross <mrstephengr...@hotmail.com> wrote:
Hi folks. I've got a weird situation--gcc doesn't like the folllowing
code snippet, but I don't know if it's correct or not. Here's the
situation:
In the global namespace, I've got a operator<< declared that will send
a vector<T> to a std::ostream.
Note that you cannot do this reliably. In order for the
compiler to reliably find the operator, including in template
code where it occurs in a dependent context, it must be able to
find it using ADL. Which means that the operator must be in std
(or the namespace in which T is defined---built-in types are in
no namespace, however). And you cannot, legally, add things
like this to std.
In the "outer" namespace, I've got a operator<< declared that will
send a Thing<T> to a std::ostream.
In the "outer" namespace, I've got a function "foo" that tries to send
a vector<T> to a std::ostream.
When I try to compile it, gcc complains that there's no match for
operator<< in the foo function's definition.
Is this correct? Why is gcc not seeing the global namespace
operator<< ?
=== test.cpp ===
#include <iostream>
#include <vector>
template<typename T> std::ostream & operator<< (std::ostream & o,
const std::vector<T> & v);
namespace outer {
template<class T> class Thing { };
template<typename T> std::ostream & operator<< (std::ostream & o,
const Thing<T> & t);
void foo() { std::vector<double> v; std::cout << v; }
}
int main()
{
}
=== EOF ===
G++ is correct. Unqualified lookup stops when it finds the
name, here, in outer, and doesn't look further. That exposes
the operator<< in outer, and no other operator<<. ADL kicks in,
and causes lookup in the namespaces related to the arguments:
here, std, so the operator<< in std are also added to the
overload set. There's nothing to cause the compiler to look in
the global namespace, however. The built-in types are defined
in no namespace (and can't have any effect on ADL), and not in
the global namespace.
Faced with this problem, there are two answers, depending on
context:
-- In production code: don't do this. You never, never want to
overload << on something like std::vector<double> in
production code. It will introduce subtle coupling, and
will cause problems in the long run. When you need to
output a vector, either write function to do it, or use the
decorator pattern to call operator<< on one of your types.
-- For quick tests, or playing around: it's formally undefined
behavior to define this operator in namespace std, but in
practice, it won't cause any problems, so just go ahead and
do it:-).
Note that both of the above solutions depend on ADL, and so will
also work from within a template.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34