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>]
Created attachment 10946 [details] Preprocessed gccbug.cpp
This is how Agrument dependent namelookup works, well there is DR report about fundamental types which is what is being exposed here.
Which is DR 225. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html
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> &)
(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.
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.
Comeau C++ does the same thing as GCC does (at least in strict mode).
Which doesn't make this inconsistent behaviour any better. I don't know Comeau C++, is it some sort of reference implementation?
(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.
(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.
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.