John Harrison wrote in in
comp.lang.c++:
- namespace std, by ADL as ostream and pair are declared there.
- namespace std, as ostream_iterator is defined there [1]
- namespace :: (global) as it containes std [1].
However in both non-ADL cases [1] the namespace is only searched
for declaration's that existed *prior* to the defenition of
ostream_iterator.
Your declaration/defenition was added *after* that point so
it isn't found.
That's amazing. I changed the OP's example slightly. On Comeau C++
this compiles
#include <utility>
#include <iosfwd>
typedef std:
air<int, int> Pair;
std:
stream& operator<<(std:
stream& os, const Pair& v);
but this (which is just a rearrangement) doesn't
#include <utility>
#include <iosfwd>
#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>
typedef std:
air<int, int> Pair;
std:
stream& operator<<(std:
stream& os, const Pair& v);
Which means I think that predict what code will compile in cases like
these you have to known precisely what definitions are included by
which header files.
And any header can include any other header and an implementation
doesen't have to document it, so its UB.
Rob, you obviously have a thorough understanding of ADL (Koenig lookup
I still like to call it).
I suspect that many people simply avoid ADL 'cause thay think its
more complicated than it really is. Certainly when I first read
the term Koenig lookup thats what I thought.
Start calling it ADL (Argument Dependant Lookup) and spell it out
so other's get the benifit of this simple demystification too.
How many other people do you find understand
all the subtleties?
No idea (and I'm not sure I understand all the subtleties), but yes
there are plenty of people who don't get it, but remember there are
millions of C++ programmers out there that don't get half the things
we regulars of c.l.c++ consider basics. They still manage to write
effective programmes though.
All that aside the feature we're discussing here is actually to
do with how dependant name lookup interacts with ADL.
There are two ways that a programmer can provide a dependant name
after is is used, by specializing an existing declaration or by
ADL.
The rule about ADL can be abused, as your first example did, but
it isn't a language feature I'd try to exploit.
Do you think it is too complicated? Is it worth
learning properly, or can you just muddle through? Reading this thread
has made me all to aware that is exactly what I am doing.
Too compilacted for what ?, it certainly isn't too complicated to learn.
Or do you mean too compilcated a feature ? I'm kindof 50-50 on that.
I'd much rather it needed to be explicity enabled (except for operators
maybe).
Anyway you should learn it, but as to how you do that I don't know,
probably by using it, IOW use namespcaes, but you probably do that
anyway.
ADL mostly just works(tm), when it doesn't it is usualy because a
generic function (template) has been put in a namespace with types
declarations that it isn't supposed to work on:
#include <vector>
namespace eg
{
typedef std::vector< int > ivect_t;
void copy( ivect_t&, ivect_t&, ivect_t& );
void f()
{
ivect_t a, b, c;
copy( a, b, c ); /* may try to call std::copy */
(copy)(a, b, c); /* Ok eg::copy */
eg::copy( a, b, c ); /* ok */
}
}
Write such functions in a nested namespace and hoist them with a
using declaration/statment and the problem goes away. If it hurts
don't do it
. { if you can :-( }.
Rob.