Why is this template code compiled?

I am working on a large project that contains a section of code that compiles, but I do not understand how to do this. I overdid up to this simple example:

template <typename T> struct First { typedef int type; // (A) typename T::Three order; // (B) }; template <typename T> struct Second { typedef typename T::type type; }; template <typename T> struct Third { int val; T two; }; struct Traits { typedef First<Traits> One; typedef Second<One> Two; typedef Third<Two> Three; }; int main(int argc, char** argv) { Traits::One x; }; 

The First class is a template on Traits and links are Traits::Three , which itself is a typedef based on Two , which is a typedef based on First<Traits> ... therefore, it is circular. But this code compiles fine on both gcc4.6 and VC10. However, if I flip the ordering of the two lines marked (A) and (B) , the code does not compile, complaining of a typedef inside Second .

Why is this code compiling and why does the ordering of the typedef variable and the member matter?

+8
c ++ templates
source share
3 answers

There are a few things worth saying.

  • Code will be broken if Second modified to contain

     T badObject; 

    with a long chain of "instance from ..." and ending with an "incomplete type" error due to the roundness you expect, but if you add instead

     typename T::type object; 

    This tells you that the compiler cleverly notices that you do not need to fully encapsulate T , only to know what T::type . To illustrate this, note that you may legally have

     First { ... typedef T type; ... } Second { typename T::type object; } 

    because T does not contain objects that are currently defined, or

     First { ... typedef typename T::One type; ... } Second { typedef typename T::type object; } 

    since the typedef in Second does not require an instance of any objects - but not , say,

     First { ... typedef typename T::One type; ... } Second { typename T::type object; } 

    since only then does the compiler really need to embed the First<Traits> object in the First<Traits> object.

  • The problem with swapping (A) and (B) is that the ingenious trick that pushes above works by introducing a new copy of the definition of each specialized template, analyzing it for one line at a time . An error occurs if it does not reach the type definition in First , when you need to know it with Second .

+3
source share

You do not need the full type for typedef .

+1
source share

You accepted an answer that was much better than the one I provided - so I delete mine. However, I thought you might be interested in further reducing your example. I highlighted two lines, like A and B, for correlation with the source code. If you flip them, then, as in your example, compilation will fail.

  template<typename T> struct First { typedef typename T::type type; }; struct Second { typedef int type; // (A) First<Second> order; // (B) }; int main(int argc, char** argv) { Second x; }; 
+1
source share

All Articles