why can't I compile this:
#include <iostream>
#include <utility>
using namespace std;
ostream &operator<<(ostream &ostr, const pair<int, string> val)
{
return (ostr << val.first << ' ' << val.second.c_str());
}
int main()
{
ostream_iterator<pair<int, string> > oi(cout);
*oi = pair<int, string>(1, "a");
return 0;
}
Compiler reports something like:
iterator(257) : error C2679: binary '<<' : no operator found which takes a
right-hand operand of type 'const std::pair<_Ty1,_Ty2>' (or there is no
acceptable conversion)
with
[
_Ty1=int,
_Ty2=std::string
]
What's wrong with my code?
Thanks,
--
Ivan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> why can't I compile this:
>
> #include <iostream>
> #include <utility>
>
> using namespace std;
>
> ostream &operator<<(ostream &ostr, const pair<int, string> val)
> {
> return (ostr << val.first << ' ' << val.second.c_str());
> }
>
> int main()
> {
> ostream_iterator<pair<int, string> > oi(cout);
> *oi = pair<int, string>(1, "a");
>
> return 0;
> }
I forget the name of the process, but the search space for overloads
is the union of namespaces of the arguments. In this case std. [using
namespace std, does not remove things from std, only lets you refer to
them in the global namespace] therefore since there is no operator <<
(std::ostream &,std::pair<T1,T2> const &); in namespace std it does not
find your operator << overload.
Workarounds:
1) struct my_pair:std::pair<int,std::string>
{
my_pair(int a,const std::string &b)
:std::pair<int,string>(a,b){}
};
inline operator << (std::ostream &os,const my_pair &p)
{
return os << p.first << ' ' << p.second;
}
declare your pairs as my_pairs.
2) class print
{
std::pair<int,std::string> const &p;
public:
print(std::pair<int,std::string> const &a):p(a){}
std::ostream & operator () (std::ostream &os)
{
return os << p.first << ' ' << p.second;
};
};
use the manipulator like os << print(the_pair);
3) cheat [not recommended in general] and put your operator in
namespace std.
4) do not use operator << directly on std::pair's.
5) use boost::tuple which does provide operator <<'s. [Or
tr1::tuples, if available]
Thanks! This really helped. So I guess _this_ is what is called Koenig
lookup? I thought that it specifies that namespaces of argument types
should be _included_ in search space, but I didn't think that global space
is excluded. :( Thank you again!
--
Ivan
e-mail me at: korotkov2 at ztel dot ru
> why can't I compile this:
>
> #include <iostream>
> #include <utility>
#include <iterator>
You need that for ostream_iterator. Your compiler may let you get
by without it, but others will not.
> using namespace std;
namespace std { // This is forbidden but must be used to make it work.
> ostream &operator<<(ostream &ostr, const pair<int, string> val)
> {
> return (ostr << val.first << ' ' << val.second.c_str());
> }
}
> int main()
> {
> ostream_iterator<pair<int, string> > oi(cout);
> *oi = pair<int, string>(1, "a");
>
> return 0;
> }
> Compiler reports something like:
> iterator(257) : error C2679: binary '<<' : no operator found which takes a
> right-hand operand of type 'const std::pair<_Ty1,_Ty2>' (or there is no
> acceptable conversion)
> What's wrong with my code?
Because ostream_iterator is in namespace std, the search for the
operator<< used in ostream_iterator::operator= starts in that
namespace. Many operator<< are found in that namespace terminating
the search. They hide your global operator.
"It is undefined for a C++ program to add declarations or definitions
to namespace std ...". There are exceptions, but the above function
is not one of them. The only result of the undefined that I have
seen is works fine.
If you dislike that hack, you can write your own PairIntString and
write the function for that. Since your PairIntString and your
operator<< will be in either your own namespace or the global one,
ADL will find the operator.
John
> Ivan Korotkov <koroNOS...@ztelDOT.ru> wrote:
>
>> why can't I compile this:
>>
>> #include <iostream>
>> #include <utility>
>>
>> using namespace std;
>>
>> ostream &operator<<(ostream &ostr, const pair<int, string> val)
>> {
>> return (ostr << val.first << ' ' << val.second.c_str());
>> }
>>
>> int main()
>> {
>> ostream_iterator<pair<int, string> > oi(cout);
>> *oi = pair<int, string>(1, "a");
>>
>> return 0;
>> }
> I forget the name of the process, but the search space for overloads
> is the union of namespaces of the arguments.
[snip]
This is called ADL, short for Andrew's Devious Lookup. :-)
Seriously, some call it Koenig lookup, because a guy named Andrew
Koening invented it. The standard calls it Argument Dependent
Lookup, which gives a nice hint as to what it does, and most
people call it ADL, which is short Argument Dependent Lookup.
But ADL isn't the only thing happening here. It is the resolution of
depenendent names (also called two-phase lookup) which determines
that only ADL will be used to find cannidate functions for the
use(s) of operator<< inside the operator= template.
And what else can be used? Is there some info source I need to take a look
at?
--
Ivan
e-mail me at: korotkov2 at ztel dot ru
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
>> But ADL isn't the only thing happening here. It is the resolution of
>> depenendent names (also called two-phase lookup) which determines
>> that only ADL will be used to find cannidate functions for the
>> use(s) of operator<< inside the operator= template.
>
> And what else can be used? Is there some info source I need to take a look
> at?
My info source was sections 14.6 and 3.4 in the standard. However I
believe the Vandervoode and Josuttis C++ Templates book has a
more readable explanation.
The operator<< functions in namespace std don't hide the operator<< in
the global namespace. The latter isn't declared before the point of
definition of ostream_iterator so there is nothing to hide. Ordinary
name lookup (as opposed to ADL) will only find functions that are
declared before the calling function's definition (or its template's
definition).
--
Ben Hutchings
Any smoothly functioning technology is indistinguishable from a rigged demo.
> John Potter wrote:
> > Because ostream_iterator is in namespace std, the search for the
> > operator<< used in ostream_iterator::operator= starts in that
> > namespace. Many operator<< are found in that namespace terminating
> > the search. They hide your global operator.
> The operator<< functions in namespace std don't hide the operator<< in
> the global namespace. The latter isn't declared before the point of
> definition of ostream_iterator so there is nothing to hide. Ordinary
> name lookup (as opposed to ADL) will only find functions that are
> declared before the calling function's definition (or its template's
> definition).
I think you may have something to say, but did not say it well.
Consider this which passes your complaint but not the compiler.
#include <iostream>
#include <utility>
using namespace std;
ostream& operator<< (ostream& ostr, const pair<int, string> val) {
return (ostr << val.first << ' ' << val.second.c_str());
}
#include <iterator>
int main() {
ostream_iterator<pair<int, string> > oi(cout);
*oi = pair<int, string>(1, "a");
}
John
What I wrote here assumes a correct implementation of two-phase name
lookup, of course.
> I think you may have something to say, but did not say it well.
Perhaps.
> Consider this which passes your complaint but not the compiler.
>
> #include <iostream>
> #include <utility>
> using namespace std;
> ostream& operator<< (ostream& ostr, const pair<int, string> val) {
> return (ostr << val.first << ' ' << val.second.c_str());
> }
> #include <iterator>
> int main() {
> ostream_iterator<pair<int, string> > oi(cout);
> *oi = pair<int, string>(1, "a");
> }
The global operator<< may well be hidden here but that's different
from the problem with the original code.
I say "may well be" because you cannot be sure that <iostream> and
<utility> do not define std::ostream_iterator. It is a mistake to
expect *any* overloaded operator that will be invoked by the standard
library to be found by ordinary name lookup, regardless of whether it
is also overloaded in namespace std.
--
Ben Hutchings
Kids! Bringing about Armageddon can be dangerous. Do not attempt it in
your own home. - Terry Pratchett and Neil Gaiman, `Good Omens'