From: daniel.kruegler@googlemail.com   
      
   Am 28.03.2012 21:10, schrieb Ivan Godard:   
   > On 3/26/2012 12:48 AM, Daniel Krügler wrote:   
   >> On 2012-03-26 06:34, Ivan Godard wrote:   
   >>> Given:   
   >>> class A { private class B; ... };   
   >>> class A::B { public class C {...}; };   
   >>> std::ostream& operator<<(std::ostream&, const A::B::C&) {}   
   >>> There seems to be no combination of "friend" or other cleverness   
   >>> that will let the operator<< be declared.   
   >>   
      
   >> What do you mean by "declared" in this context? I'm asking, because   
   >> an immediately defining friend function definition within A::B::C   
   >> would provide this feature.   
   > Interesting - the compiler accepts immediate definition but not   
   > deferred definition - see below   
      
   Immediately defining friend functions have indeed there own rule set.   
      
   > Yes, that compiles, but this doesn't:   
   > #include    
   >   
   > class A {   
   > private:   
   > class B;   
   > };   
   >   
   > class A::B {   
   > public:   
   > class C {   
   > friend std::ostream& operator<<(std::ostream& os, const C& c);   
   > };   
   > };   
   >   
   > std::ostream& operator<<(std::ostream& os, const C& c)   
   > {   
   > // Output something   
   > return os;   
   > }   
   >   
   > Please forgive my ignorance of the language, but I had thought that   
   > immediate and deferred definition had identical semantics and   
   > differed only in convenience and the ability to handle mutual   
   > recursion.   
      
   No, no, an immediately defining friend function is very different and   
   it looks like they only feasible solution in your use-case. The   
   difference to your above example is as follows: In your variant (The   
   non-defining friend declaration), the declaration has the effect to   
   say: Hey, there is a function   
      
   std::ostream& operator<<(std::ostream& os, const C& c);   
      
   in the next surrounding namespace (which is the global namespace in   
   this example). The friend declaration is well-formed, but there is no   
   way to *define* the function outside of A::B::C, because your form   
      
   std::ostream& operator<<(std::ostream& os, const C& c)   
   {   
   // Output something   
   return os;   
   }   
      
   refers to some C in global namespace, which does not exist. An attempt   
   to correct this problem, is to define instead   
      
   std::ostream& operator<<(std::ostream& os, const A::B::C& c)   
   {   
   // Output something   
   return os;   
   }   
      
   but you have *now* the problem that you don't have access to A::B. You   
   cannot fix that, because that would also mean that you need declare   
   this function as a friend of A, which is technically not possible   
   (Your original descriptions reflects these attempts)   
      
   In my suggested form the approach works, because the friend function   
   is defined directly the class, where the access is necessary. The   
   effects will be of a free function declared in the same next   
   namespace, it will be ODR-used, when referred to in the surrounding   
   context.   
      
   > I don't care for the use of an immediate definition here - it puts   
   > executable code in a .hh file, which I consider poor practice, but   
   > at least it's a workaround for my use case.   
      
   I agree, but in your example do not exist very much options. The   
   question is, whether you really need to write all the code in the   
   header. If you just need access to the members of C, you could call a   
   different (non-friend) function that gets the members of C as arguments,   
   for example.   
      
   > But I don't think that immediate definition makes the problem go   
   > away in general: if the intended friend was not a single function   
   > but a mutually recursive pair then you are again stuck. Immediate   
   > definition is impossible because of the recursion, and deferred   
   > definition complains (as in my example) that A::B is private.   
      
   It is certainly possible to construct such cases, but I would like to   
   see an example to discuss that in detail. The question is whether this   
   scenario is an existing one in practice.   
      
   > A more general question: isn't the header of any definition supposed   
   > to see exactly the same things that the corresponding declaration   
   > could see? In my example, the compiler does not complain on the   
   > declaration using A::B; why should it complain when it sees A::B on   
   > the matching deferred definition?   
      
   These are different, because the separate definition is now in a scope   
   where the access to A::B is relevant. This is not needed within C   
   itself.   
      
   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)   
|