Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this template code compile?

Tags:

c++

templates

I'm working on a large project, which contains a section of code that compiles - but I don't understand how. I distilled it down 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 class First is templated on Traits and references Traits::Three, which itself is a typedef based on Two, which is a typedef based on First<Traits>... hence 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 about the typedef inside of Second.

Why does this code compile, and why is it that the ordering of the typedef and the member variable matters?

like image 827
Barry Avatar asked Apr 10 '13 20:04

Barry


People also ask

What is a template compiler?

Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled.

How are templates compile in C++?

Template compilation requires the C++ compiler to do more than traditional UNIX compilers have done. The C++ compiler must generate object code for template instances on an as-needed basis. It might share template instances among separate compilations using a template repository.

What are templates and how does the compiler interpret them?

In other words, a template is a mechanism that allows a programmer to use types as parameters for a class or a function. The compiler then generates a specific class or function when we later provide specific types as arguments.

How many times is template code compiled?

In general, yes, template classes are usually compiled every time they're encountered by the compiler.


2 Answers

There are a couple of things worth saying.

  • The code will break if Second is modified to contain

    T badObject;
    

    with a long "instantiated from..." chain and ending with an "incomplete type" error, due to the circularity you expect, but not if you instead add

    typename T::type object;
    

    This is telling you that the compiler is cleverly observing it doesn't need to completely encapsulate T, only to know what T::type is. To illustrate this, note you can legally have

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

    since T contains no currently-being-defined objects, 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 either - but not, say,

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

    since only then is the compiler is actually required to nest a First<Traits> object within a First<Traits> object.

  • The issue with swapping (A) and (B) is that the clever trick the compiler pulled above is working by introducing a new copy of the definition of each specialized template, parsing it one line at a time. The error occurs if it hasn't got as far as the type definition in First when it is required to know it by Second.

like image 143
not all wrong Avatar answered Oct 27 '22 23:10

not all wrong


You don't need a complete type for a typedef.

like image 24
David Rodríguez - dribeas Avatar answered Oct 27 '22 23:10

David Rodríguez - dribeas