why doesn't this compile?

E

ES Kim

#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;

typedef map<int, int> Map;

ostream& operator<<(ostream& os, const Map::value_type& v);

int main()
{
Map m;
copy(m.begin(), m.end(),
ostream_iterator<Map::value_type>(cout, "\n"));
}

The error message is "no match for ostream << const pair<const int, int>&",
which I think I declared.
 
V

Victor Bazarov

ES said:
#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;

typedef map<int, int> Map;

ostream& operator<<(ostream& os, const Map::value_type& v);

int main()
{
Map m;
copy(m.begin(), m.end(),
ostream_iterator<Map::value_type>(cout, "\n"));
}

The error message is "no match for ostream << const pair<const int, int>&",
which I think I declared.

The problem is in "argument-dependent name lookup". The operator << is
not found in the global namespace (where you declared it) becuase both
its operands (ostream and pair) are declared in 'std' namespace. The
work-around for this is to place your operator << in 'std' namespace.
Ugly, but works:

namespace std {
ostream& operator <<(ostream& os, const Map::value_type& v);
}

V
 
R

Rob Williscroft

ES Kim wrote in in comp.lang.c++:
#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;

typedef map<int, int> Map;

ostream& operator<<(ostream& os, const Map::value_type& v);

int main()
{
Map m;
copy(m.begin(), m.end(),
ostream_iterator<Map::value_type>(cout, "\n"));
}

The error message is "no match for ostream << const pair<const int,
int>&", which I think I declared.

Yep but ostream_iterator looks for this in:

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

Note if you make one of std::map's arguments a UDT then ADL
will find your declaration.

For those that don't know ADL = Argument Dependant Lookup.

HTH.

Rob.
 
J

John Harrison

Rob Williscroft said:
ES Kim wrote in in comp.lang.c++:
#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;

typedef map<int, int> Map;

ostream& operator<<(ostream& os, const Map::value_type& v);

int main()
{
Map m;
copy(m.begin(), m.end(),
ostream_iterator<Map::value_type>(cout, "\n"));
}

The error message is "no match for ostream << const pair<const int,
int>&", which I think I declared.

Yep but ostream_iterator looks for this in:

- 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::pair<int, int> Pair;

std::eek:stream& operator<<(std::eek:stream& os, const Pair& v);

#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>

int main()
{
std::map<int, int> m;
copy(m.begin(), m.end(),
std::eek:stream_iterator<Pair>(std::cout, "\n"));
}

but this (which is just a rearrangement) doesn't

#include <utility>
#include <iosfwd>
#include <map>
#include <iterator>
#include <iostream>
#include <algorithm>

typedef std::pair<int, int> Pair;

std::eek:stream& operator<<(std::eek:stream& os, const Pair& v);

int main()
{
std::map<int, int> m;
copy(m.begin(), m.end(),
std::eek:stream_iterator<Pair>(std::cout, "\n"));
}

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.
Note if you make one of std::map's arguments a UDT then ADL
will find your declaration.

Rob, you obviously have a thorough understanding of ADL (Koenig lookup I
still like to call it). How many other people do you find understand all the
subtleties? 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.

john
 
V

Victor Bazarov

John said:
[...]
Rob, you obviously have a thorough understanding of ADL (Koenig lookup I
still like to call it). How many other people do you find understand all the
subtleties? 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.

So, what is it _"exactly"_ you're doing? Learning properly or muddling
through? I am just learning to read English, I guess. Or maybe muddling
through it. Depends on your point of view.
 
J

John Harrison

Victor Bazarov said:
John said:
[...]
Rob, you obviously have a thorough understanding of ADL (Koenig lookup I
still like to call it). How many other people do you find understand all
the subtleties? 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.

So, what is it _"exactly"_ you're doing? Learning properly or muddling
through? I am just learning to read English, I guess. Or maybe muddling
through it. Depends on your point of view.

Some bits of C++ I've made an attempt to study and to learn thoroughly. Some
bits I've learned by trial and error. Koenig lookup is definitely in the
latter category. I'm wondering if I should actually spend some time studying
it, would that actually be useful? I'm not expecting Rob to answer that
question for me, just tell me about his experiences. That's all I'm trying
to say

john
 
R

Rob Williscroft

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::pair<int, int> Pair;

std::eek:stream& operator<<(std::eek: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::pair<int, int> Pair;

std::eek:stream& operator<<(std::eek: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.
 
A

Arijit

Victor said:
The problem is in "argument-dependent name lookup". The operator << is
not found in the global namespace (where you declared it) becuase both
its operands (ostream and pair) are declared in 'std' namespace. The
work-around for this is to place your operator << in 'std' namespace.
Ugly, but works:

namespace std {
ostream& operator <<(ostream& os, const Map::value_type& v);
}

V

Also illegal.

-Arijit
 
E

ES Kim

Rob Williscroft said:
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 :-( }.

Thank you for explanation. I think John is quite good at C++,
and when he says "complicated", it would be really complicated for me.
I've came across the term Koenig lookup several times, but haven't
study what it is, just thought "Is that named after Andrew Koenig?"
It seems this is the right time to learn it.

And would you explain again the relevant language rule (copy)(a, b, c)
calls eg::copy?
 
R

Rob Williscroft

ES Kim wrote in in comp.lang.c++:
And would you explain again the relevant language rule (copy)(a, b, c)
calls eg::copy?

3.4.2 Argument-dependent name lookup

When an unqualified name is used as the postfix-expression in a
function call (5.2.2), other namespaces not considered during
the usual unqualified lookup (3.4.1) ...

With emphasis:

unqualified name is used *as* the postfix-expression

In the case of (copy)(a, b, c) the postfix-expresion used in the
function call is "(copy)", for ADL to work it is *required* that
the postfix-expresion be an unqualified name i.e. "copy", so ADL
doesn't apply.

Hope I explained that sufficiently well.

Rob.
 

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,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top