Bug 26512 - g++ doesn't recognize user-defined operator<<(ostream, const pair<int, double> &)
Summary: g++ doesn't recognize user-defined operator<<(ostream, const pair<int, double...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.0.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-03-01 14:33 UTC by Olaf Dietsche
Modified: 2006-03-08 04:49 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Preprocessed gccbug.cpp (80.27 KB, text/plain)
2006-03-01 14:35 UTC, Olaf Dietsche
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Olaf Dietsche 2006-03-01 14:33:16 UTC
g++ doesn't recognize a user-defined

operator<<(ostream, const pair<int, double> &)

although it recognizes

struct A {};
operator<<(ostream, const pair<int, A> &)

Regards, Olaf.

$ cat gccbug.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>

typedef std::map<int, double> M;
extern std::ostream &operator <<(std::ostream &f, const M::value_type &p);

void f()
{
	M m;
	std::copy(m.begin(), m.end(), std::ostream_iterator<M::value_type>(std::cout));
}

This one compiles without problems:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>

struct A {
	double d;
};

typedef std::map<int, A> M;
extern std::ostream &operator <<(std::ostream &f, const M::value_type &p);

void f()
{
	M m;
	std::copy(m.begin(), m.end(), std::ostream_iterator<M::value_type>(std::cout));
}

Putting the operator<<() in namespace std, cirucmvents the compile error too:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>

typedef std::map<int, double> M;
namespace std {
extern std::ostream &operator <<(std::ostream &f, const M::value_type &p);
};

void f()
{
	M m;
	std::copy(m.begin(), m.end(), std::ostream_iterator<M::value_type>(std::cout));
}

And here is the output of the g++ call:
$ d:/programme/mingw/bin/g++ -v -c -Wall -save-temps gccbug.cpp
Reading specs from d:/programme/mingw/bin/../lib/gcc/i686-pc-mingw32/4.0.2/specs
Target: i686-pc-mingw32
Configured with: ../gcc-4.0.2/configure --with-gcc --prefix=/mingw --enable-threads --disable-nls --enable-languages=c,c++ --disable-win32-registry --disable-shared --enable-sjlj-exceptions --without-x --enable-libstdcxx-debug
Thread model: win32
gcc version 4.0.2
 d:/programme/mingw/bin/../libexec/gcc/i686-pc-mingw32/4.0.2/cc1plus.exe -E -quiet -v -iprefix d:\programme\mingw\bin\../lib/gcc/i686-pc-mingw32/4.0.2/ gccbug.cpp -mtune=pentiumpro -Wall -fpch-preprocess -o gccbug.ii
ignoring nonexistent directory "/mingw/include"
ignoring nonexistent directory "d:/programme/mingw/i686-pc-mingw32/include"
ignoring nonexistent directory "/mingw/include"
#include "..." search starts here:
#include <...> search starts here:
 d:/programme/mingw/bin/../lib/gcc/i686-pc-mingw32/4.0.2/include
 d:/programme/mingw/include/c++/4.0.2
 d:/programme/mingw/include/c++/4.0.2/i686-pc-mingw32
 d:/programme/mingw/include/c++/4.0.2/backward
 d:/programme/mingw/include
 d:/programme/mingw/lib/gcc/i686-pc-mingw32/4.0.2/include
End of search list.
 d:/programme/mingw/bin/../libexec/gcc/i686-pc-mingw32/4.0.2/cc1plus.exe -fpreprocessed gccbug.ii -quiet -dumpbase gccbug.cpp -mtune=pentiumpro -auxbase gccbug -Wall -version -o gccbug.s
GNU C++ version 4.0.2 (i686-pc-mingw32)
	compiled by GNU C version 4.0.2.
GGC heuristics: --param ggc-min-expand=99 --param ggc-min-heapsize=129918
d:/programme/mingw/include/c++/4.0.2/bits/stream_iterator.h: In member function 'std::ostream_iterator<_Tp, _CharT, _Traits>& std::ostream_iterator<_Tp, _CharT, _Traits>::operator=(const _Tp&) [with _Tp = std::pair<const int, double>, _CharT = char, _Traits = std::char_traits<char>]':
d:/programme/mingw/include/c++/4.0.2/bits/stl_algobase.h:270:   instantiated from 'static _OI std::__copy<<anonymous>, <template-parameter-1-2> >::copy(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = std::ostream_iterator<std::pair<const int, double>, char, std::char_traits<char> >, bool <anonymous> = false, <template-parameter-1-2> = std::bidirectional_iterator_tag]'
d:/programme/mingw/include/c++/4.0.2/bits/stl_algobase.h:317:   instantiated from '_OI std::__copy_aux(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = std::ostream_iterator<std::pair<const int, double>, char, std::char_traits<char> >]'
d:/programme/mingw/include/c++/4.0.2/bits/stl_algobase.h:326:   instantiated from 'static _OI std::__copy_normal<<anonymous>, <anonymous> >::copy_n(_II, _II, _OI) [with _II = std::_Rb_tree_iterator<std::pair<const int, double> >, _OI = std::ostream_iterator<std::pair<const int, double>, char, std::char_traits<char> >, bool <anonymous> = false, bool <anonymous> = false]'
d:/programme/mingw/include/c++/4.0.2/bits/stl_algobase.h:387:   instantiated from '_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = std::_Rb_tree_iterator<std::pair<const int, double> >, _OutputIterator = std::ostream_iterator<std::pair<const int, double>, char, std::char_traits<char> >]'
gccbug.cpp:12:   instantiated from here
d:/programme/mingw/include/c++/4.0.2/bits/stream_iterator.h:196: error: no match for 'operator<<' in '*((std::ostream_iterator<std::pair<const int, double>, char, std::char_traits<char> >*)this)->std::ostream_iterator<std::pair<const int, double>, char, std::char_traits<char> >::_M_stream << __value'
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:67: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:78: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:90: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:125: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:159: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:102: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:176: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:187: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:191: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:202: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:183: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:218: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:242: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:217: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:265: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:288: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:311: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:447: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:509: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char) [with _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:458: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char) [with _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:463: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char) [with _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:571: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*) [with _CharT = char, _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/bits/ostream.tcc:616: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const char*) [with _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:497: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*) [with _Traits = std::char_traits<char>]
d:/programme/mingw/include/c++/4.0.2/ostream:502: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*) [with _Traits = std::char_traits<char>]
Comment 1 Olaf Dietsche 2006-03-01 14:35:22 UTC
Created attachment 10946 [details]
Preprocessed gccbug.cpp
Comment 2 Andrew Pinski 2006-03-01 14:37:00 UTC
This is how Agrument dependent namelookup works, well there is DR report about fundamental types which is what is being exposed here.
Comment 3 Andrew Pinski 2006-03-01 14:40:54 UTC
Which is DR 225.
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html
Comment 4 Olaf Dietsche 2006-03-03 22:57:18 UTC
I looked at your link and at issue 197. I don't see how this applies to my bug
report, especially in connection with _user defined_ types. What I don't
understand is, why does g++ handle builtin types different than user defined
types. e.g:

operator<<(ostream, const pair<int, double> &)
vs.
operator<<(ostream, const pair<int, struct A> &)
Comment 5 Andrew Pinski 2006-03-03 23:10:44 UTC
(In reply to comment #4)
> I looked at your link and at issue 197. I don't see how this applies to my bug
> report, especially in connection with _user defined_ types. What I don't
> understand is, why does g++ handle builtin types different than user defined
> types. e.g:

This does not match what you have in the source:
extern std::ostream &operator <<(std::ostream &f, const M::value_type &p);
M::value_type here is either an user defined type, A or a fundamental type.

Comment 6 Olaf Dietsche 2006-03-05 14:21:59 UTC
Sorry, if my example wasn't clear enough :-(. I'll try to clarify.

M::value_type is std::map<int, double>::value_type, which is std::map<int, double>::pair<int, double> in my first example.

g++ doesn't recognize the user defined
operator <<(std::ostream &f, const M::value_type &), which is
operator<<(ostream &, const pair<int, double> &)

If I change double to struct A, g++ _does_ recognize the user defined
operator <<(std::ostream &f, const M::value_type &), which is
- in my second example - operator<<(ostream, const pair<int, struct A> &)

And this is my problem: the difference in ignoring the user defined
operator<<() in the first case and recognizing the user defined operator<<()
in the second case.

I hope, this makes my problem a bit more understandable.
Comment 7 Andrew Pinski 2006-03-05 15:43:14 UTC
Comeau C++ does the same thing as GCC does (at least in strict mode).
Comment 8 Olaf Dietsche 2006-03-05 16:22:58 UTC
Which doesn't make this inconsistent behaviour any better. I don't know Comeau C++, is it some sort of reference implementation?
Comment 9 Andrew Pinski 2006-03-05 16:26:36 UTC
(In reply to comment #8)
> Which doesn't make this inconsistent behaviour any better. I don't know Comeau
> C++, is it some sort of reference implementation?

It is just another implementation to compare against.
Comment 10 Wolfgang Bangerth 2006-03-08 04:43:17 UTC
(In reply to comment #4)
> I looked at your link and at issue 197. I don't see how this applies to my bug
> report, especially in connection with _user defined_ types. What I don't
> understand is, why does g++ handle builtin types different than user defined
> types. e.g:
> 
> operator<<(ostream, const pair<int, double> &)
> vs.
> operator<<(ostream, const pair<int, struct A> &)

Because user defined types are associated with a namespace (in which the
compiler can then lookup functions, if one of its arguments is from that
namespace), whereas builtin types have no associated namespace.

W.

Comment 11 Wolfgang Bangerth 2006-03-08 04:49:37 UTC
This is indeed invalid under the present rules:
---------------
typedef std::map<int, double> M;
namespace std {
extern std::ostream &operator <<(std::ostream &f, const M::value_type &p);
};

void f()
{
        M m;
        std::copy(m.begin(), m.end(),
                  std::ostream_iterator<M::value_type>(std::cout));
}
---------------
When inside std::copy, the compiler needs to lookup an operator<< for
its arguments. It does so in the present namespace (i.e. std::) as well
as the namespaces of all arguments. The arguments are std::ofstream and
std::pair (and possibly the template arguments of two classes, though
I'm not sure about that). All these arguments are from namespace std::
or are builtin types that have no associated namespace. Lookup therefore
has to fail.

The solution is to put your own definition of operator<< into namespace
std:: -- not pretty, but a solution that we have discussed several times
here in this database...

W.