home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 32,133 of 33,346   
   =?ISO-8859-1?Q?Daniel_Kr=FCgler?= to All   
   Re: ostream_iterator for map   
   14 Apr 12 11:24:34   
   
   From: daniel.kruegler@googlemail.com   
      
   Am 14.04.2012 00:28, schrieb James K. Lowden:   
   [..]   
   >> ADL name-lookup wont find your operator<< overload, because it only   
   >> looks in namespace std, but your operator<< overload for std::pair   
   >> is not part of this namespace.   
   >   
   > I think you will tell me my operator<<  works with   
   >   
   >    cout<<  *m.begin()<<  endl;   
   >   
   > because that statement appears in main(), which must be in the   
   > global namespace.  The compiler therefore searches the global   
   > namespace and finds my operator.  When instantiating std::copy,   
   > however, ::operator<< is not found because -- and only because --   
   > the template I'm instantiating is defined in std.   
      
   This describes it roughly. More precisely what we have in both   
   situations is unqualified name lookup. In your first example the   
   operator<< overload in the global namespace can be found in main(),   
   because it is found by the "usual unqualified lookup": Starting from   
   the actual evocation point in main it finds the *previously* declared   
   global operator<< overload. The second example is more complex,   
   because the need for finding a matching name for operator<< is within   
   a member function of an instantiation of std::ostream_iterator. The   
   fact that this template is instantiated within std::copy is not   
   relevant in this case (std::copy does not perform lookup of <<, but it   
   does lookup for a dereference operator call and other functions). You   
   can note the same problem when you write within main the following   
   lines:   
      
       std::ostream_iterator it(std::cout, "\n");   
       *it = *m.begin();   
      
   At the point where this member function is defined, your global   
   operator<< overload cannot be found and the compiler now enters the   
   second stage of ADL where names in associated namespaces are   
   considered.  In your example the only relevant namespace is namespace   
   std, but the operator<< overload is not contained in that one.   
      
   >> According to the library requirements, user-code shall not add any   
   >> components (except template specializations with at least one   
   >> user-defined type) to namespace std.   
   >   
   > How far does that prohibition extend?  ISTM if I add to the std   
   > namespace in any module that includes main(), I can't possibly   
   > pollute anyone's namespace or confuse the compiler.   
      
   It is an absolute requirement. It makes sense, because namespace std   
   is not your territory and it would easily lead to problems if more   
   than one programmer has the same idea as you. Don't do that, unless   
   you use this idiom only in your own code, never do that for sharing   
   your code. The real problem is that some introductory C++ books   
   unfortunately use similar examples and this makes use code believe   
   they could do the same.  I can only warn about such an idiom. The much   
   better route is to use a wrapper type. Most people are not happy when   
   they hear this suggestion, because they often think first of   
   performance and overhead. This negative position is IMO usually   
   inappropriate. First, it may help that using my suggested idiom is a   
   well-known technique known as "IO manipulators". The library provides   
   several IO manipulators they have many advantages. One special   
   advantage is that they allow you to control the exact form of the   
   output format. Second, this wrapper type should not introduce   
   observable loss of performance when used appropriately.   
      
   > One last option.  I think I can use still use std::copy if I don't   
   > use std::ostream_iterator.   
      
   Sure, sure, you can use std::copy as well in *this* specific example,   
   because I designed my pair_io to be implicitly convertible from the   
   source type. Just write   
      
       std::copy( m.begin(), m.end(),   
   	std::ostream_iterator >(std::cout, "\n") );   
      
   in this example, if you want. The reason why I *generally* recommend   
   std::transform is, because it allows you to handle more complex   
   situations: e.g. you don't want to have the manipulator type   
   implicitly convertible or you want to provide additional formatting   
   parameters to that wrapper. So for just any default formatting   
   std::copy is perfectly fine.   
      
   HTH & Greetings from Bremen,   
      
   Daniel Krügler   
      
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca