Why is this possible (in VS2009):

struct outer{
    struct inner1{
       void f(){
          inner2 in2; 
          in2.g(); /* no previous forward declaraction*/
       }
    };
   struct inner2{
     void g(){}
   }
};

... but not this (???)

struct outer{
   /* This line required to remove error:
       struct inner2;
   */
    struct inner1{
       inner1(struct inner2){} /* ERROR unless you precede struct inner1 with forward declaration struct inner2;*/
    };
   struct inner2{
   }
};
[

Because, in the first example, the use of inner2 is only within the definition of the function f() of inner1, while in the second example, the use of the inner2 class is in the declaration of the inner1 class. It is important to understand the difference here. Think of it as a two-pass process. In order for the compiler to build up a complete understanding of what a particular class is, it has to know its entire declaration (i.e. to be able to register what data members it has, what member functions it has, what nested classes / typedefs it has, etc.). But, when you define some functions inside the class declaration, in order for the compiler to know and understand fully the type of the "this" pointer for a member function for example, it has to parse the entire declaration first, and then parse the function definitions, even if they appear in the class declaration. In other words, the compiler looks at all the data members and member function prototypes first, and then comes back to look at the definitions of the member functions. So, in your first example, by the time the compiler looks at the implementation of the f() function, it has already a complete knowledge of the declaration of the inner2 class. With the second example, as the compiler tries to understand the prototype for the constructor of inner1, it finds a class that it has not yet seen, i.e. the inner2 class.

So if we go to the implication of what you said, this shouldn't compile:

struct outer{
     struct inner1{
        void f(inner2 in2){
             /* inner2 in2; CHANGED, now put as argument */
            in2.g(); /* no previous forward declaraction*/
         }
     };
     struct inner2{
         void g(){}
     }   
 };

And indeed it is just as your post so well explained!

Many thanks for your crystal-clear, straight-to-the-point and immensely helpful posts!
Greatly appreciated.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.