Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does CRTP not cause infinite nesting?

I am confused about how CRTP is compiled. If we have something like this:

template<class T>
class Base
{

};
class Derived : public Base<Derived>
{

};

Why doesn't something akin to this happen during compilation?

(X[Y] denotes X inherits from Y)

Upon declaration of a Derived instance Derived d;

d is being expanded into an infinite recurrence of templates and inheritances

d[Base<Derived[Base<Derived[Base<Derived[Base<Derived[...]>]>]>]>]

Why does this not happen? All tutorials on CRTP only explain what you can do with it, not what happens under the hood (at least vaguely).

like image 238
lo tolmencre Avatar asked Oct 03 '16 03:10

lo tolmencre


2 Answers

The fundamental concept to understand is that an instance of a template is just a class. It is fundamentally no different than any other class.

When you have a typical template definition:

template<typename T> class Base;

Then the template instance:

Base<int>

Is just a class of that name. It has nothing to do with int, and has absolutely no relationship, whatsoever, with an int. It doesn't inherit from it, in some way, or in any way.

Next step:

class Derived;

template<typename T> class Base {};

Base<Derived> foo;

Again, Base<Derived> is just a class. It has no intrinsic relationship with Derived. It doesn't derive from it, does not inherit from it, nothing.

So, now we take the final step:

template<class T>
class Base
{

};

class Derived : public Base<Derived>
{

};

This declares a class called Derived, which inherits from a class called Base<Derived>. And Base<Derived> is just a class. It's a very simple class. Can't get any simpler than that. It doesn't have any methods. It doesn't have any members. Nor private, protected, or public. It's a tiny class, but it has the same rights and privileges as any other class. You can declare a pointer to it. Or a reference to it. It's just a class.

Again, the key concept is that an instance of a template is just a class. It doesn't "inherit" in any way from the class that's the parameter to the template. In this case, the template instance is completely empty, but it can do anything that any other class can do. It can have public, private, and protected members. It can derive from some other class, which could be another template instance (since a template instance is just a class). Or, some other class can derive from the template instance, because a template instance is just a class.

There is no infinite nesting here. You just have one class inheriting from another class. The second class happens to be a template instance, but did I happen to mention that a template instance is just a class?

like image 135
Sam Varshavchik Avatar answered Oct 09 '22 07:10

Sam Varshavchik


Simple explanation: because the following is completely valid:

template<class T>
class Base
{
};

class Derived /* at this point, Derived is declared (not defined) */;

int main()
{
    Base<Derived> base;  // the definition of Derived (or lack thereof) is irrelevant.
}
like image 3
user541686 Avatar answered Oct 09 '22 07:10

user541686