Topic: How to resolve ADL(?) issue using std::copy and std::ostream_iterator


Author: devcjohnson@gmail.com (Chris Johnson)
Date: Sun, 2 Jul 2006 23:56:04 GMT
Raw View
My knowledgeable friends over at comp.lang.c++ directed me to post this
message here.  I am pasting the message here as originally asked.
Apologies if this comes off as spamming/cross-posting to either group
(not the intent):

Greetings all.  I am really stuck on this one as I can't seem to grok if
I am abusing the C++ language or if I am simply using components of the
C++ Standard Library incorrectly.  Here is the code:

#include <string>
#include <map>
#include <iostream>
#include <utility>
#include <iterator>

typedef std::pair<std::string, std::string> STR;

#ifdef NON_COMPLIANT
// Works but my understanding this is forbidden by
//   Standard ISO/IEC 14882.2003 17.4.3.1-1
//   since I introduce code into namespace std
namespace std {
     {
     std::ostream& operator<<(std::ostream& os, STR const& ip) {
     os << ip.first << " " << ip.second << std::endl;
     return os;
     }
}
#else
// Generates error
//  std::copy can't find a suitable candidate for operator<<
std::ostream& operator<<(std::ostream& os, STR const& ip) {
     os << ip.first << " " << ip.second << std::endl;
     return os;
}
#endif

int main(int argc, char** argv, char** env) {
     std::map<std::string, std::string> test;
     test["foo"] = "bar";
     test["baz"] = "qux";

     std::ostream_iterator<STR> o(std::cout);
     std::copy(
         test.begin(),
         test.end(),
         o);

     return 0;
}

If compiled with the macro definition NON_COMPLIANT line 12 violates the
Standard section 17.4.3.1-1 commented on in the code but that seems to
be the only way to allow for std::copy to deduce the correct context of
operator<<, is this correct?  (I apologize if I am not using the correct
terminology - please educate me accordingly on this as well)

If my understanding above is correct then can I conclude that I simply
do not understand how to use the Standard C++ library correctly in this
case?  The code appears to be a logical use of the components at play
but my compiler disagrees with my thinking.

Thank you for reading and any insight you can assist me with in advance.
Chris

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: devcjohnson@gmail.com (Chris Johnson)
Date: Mon, 3 Jul 2006 09:01:03 GMT
Raw View
Chris Johnson wrote:
--8<--[SNIP]--8<--

Please disregard - this was posted to this newsgroup prematurely on my
part.  comp.lang.c++ has explained sufficiently what is actually happening.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: cbarron3@ix.netcom.com (Carl Barron)
Date: Mon, 3 Jul 2006 15:22:48 GMT
Raw View
Chris Johnson <devcjohnson@gmail.com> wrote:

> My knowledgeable friends over at comp.lang.c++ directed me to post this
> message here.  I am pasting the message here as originally asked.
> Apologies if this comes off as spamming/cross-posting to either group
> (not the intent):
>
> Greetings all.  I am really stuck on this one as I can't seem to grok if
> I am abusing the C++ language or if I am simply using components of the
> C++ Standard Library incorrectly.  Here is the code:
>
> [sample code attempting to use std::ostream_iterator<std:pair<T1.T2> >.

Looking at the definition of std::output_iterator<T,Ch,Tr>
[the last to args default to char and std::char_traits<char>]

you will find it evaluates the expression *it = x as os << x, in effect
so we must as you show as NON_COMPILANT, devise an operator << () for
std::ostream_iterator to compile. When the compiler looks for operator
<< it looks in namespace std since ostream is there, it looks whereever
the type T is as well so std::ostream_iterator<std::pair<T1,T2> > will
ultimately look for the operator in only namespace std.  But if T is not
in namespace std, sucn as its in the global namespace, it will look for
the operator in the global namespace as well. Thats the theory poorly
explained.  The following OutProxy solves the problem:

// general case
   template <class T>
   struct OutProxy
   {
       const T &t;
       OutProxy(const T &a):t(a){}
       std::ostream & put (std::ostream &os) const
       {  return os << t;}
   };

 //  specialize for Pair<T1,T2>
   template <class T1,T1> struct OutProxy<std::pair<T1,T2> >
   {
      const std::pair<T1,T2> &p;
      OutProxy(const std::pair<T1,T2> &a):p(a)
      std::ostream & put(std::ostrwam &os) const
      {
         return os << p.first << ' ' << p.second;
      }
   };
//   template <class T>
   std::ostream & operator << (std::ostream &os, OutProxy<T> const &p)
   { return p.put(os);}

 std::copy<test.begin(),test.end(),
      std::ostream_iterator<OutProxy<MapType::value_type> >(std::cout));

 note this place the type used by ostream_itertor into the global
namespce and this it finds operator << ().  There is an implicit
conversion used to convert std::pair<T1,T2> to OutProxy<std::pair<T1,T2>
>.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]