Stream operator in namespace masks global stream operator

M

mrstephengross

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::eek:stream.
In the "outer" namespace, I've got a operator<< declared that will
send a Thing<T> to a std::eek:stream.
In the "outer" namespace, I've got a function "foo" that tries to send
a vector<T> to a std::eek:stream.

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<< ?

Thanks,
--Steve ([email protected])

=== test.cpp ===

#include <iostream>
#include <vector>

template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
const std::vector<T> & v);

namespace outer {

template<class T> class Thing { };

template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
const Thing<T> & t);

void foo() { std::vector<double> v; std::cout << v; }

}

int main()
{
return 0;
}

=== EOF ===
 
F

Fei Liu

mrstephengross said:
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::eek:stream.
In the "outer" namespace, I've got a operator<< declared that will
send a Thing<T> to a std::eek:stream.
In the "outer" namespace, I've got a function "foo" that tries to send
a vector<T> to a std::eek:stream.

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<< ?

Thanks,
--Steve ([email protected])

=== test.cpp ===

#include <iostream>
#include <vector>

template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
const std::vector<T> & v);

namespace outer {

template<class T> class Thing { };

template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
const Thing<T> & t);

void foo() { std::vector<double> v; std::cout << v; }

}

int main()
{
return 0;
}

=== EOF ===

The compiler is telling you it cannot find a prototype for '<<' in foo.
The '<<' function hides the '<<' function in global namespace. Try the
below implementation instead:

#include <iostream>
#include <vector>

template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
const std::vector<T> & v);

namespace outer {

template<class T> class Thing { };

template<typename T> std::eek:stream & operator<< (std::eek:stream & o,
const T & t);

void foo() { std::vector<double> v; std::cout << v; }

}

int main()
{
return 0;
}
 
M

modemer

I think compiling is ok but linking has an error with symbol not
found.

Just in case if you used gcc, it'd be g++.

cheers
 
J

James Kanze

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::eek:stream.

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::eek:stream.
In the "outer" namespace, I've got a function "foo" that tries to send
a vector<T> to a std::eek:stream.
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::eek:stream & operator<< (std::eek:stream & o,
const std::vector<T> & v);
namespace outer {
template<class T> class Thing { };
template<typename T> std::eek:stream & operator<< (std::eek:stream & 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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top