2016-10-03 2 views
6

Je suis confus sur la façon dont CRTP est compilé. Si nous avons quelque chose comme ceci:Pourquoi le protocole CRTP ne provoque pas l'imbrication infinie?

template<class T> 
class Base 
{ 

}; 
class Derived : public Base<Derived> 
{ 

}; 

Pourquoi pas quelque chose comme cela se produise lors de la compilation?

(X[Y] désigne X hérite de Y)

Après la déclaration d'un Derived exemple Derived d;

d s'étoffe dans une récurrence infinie de modèles et héritages

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

Pourquoi cela n'arrive-t-il pas? Tous les tutoriels sur CRTP expliquent seulement ce que vous pouvez faire avec, pas ce qui se passe sous le capot (au moins vaguement).

+0

Dans le contexte de 'Base',' T' n'est pas un type complètement complet. Pour cette raison, vous ne pouvez pas accéder à des choses comme 'typedef's définies dans' T' à partir de 'Base' (voir [1] (http://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp- et-using-typedefs-from-derived-classes) et [2] (http://stackoverflow.com/questions/652155/invalid-use-of-incomplete-type)). Comme 'T' n'est pas un type complètement complet, le compilateur n'a pas besoin de se répéter indéfiniment dans cette situation. Au moins c'est ma compréhension. – Cornstalks

+0

@ Eichhörnchen Parce que je dérive de Base, qui est gérée par Derived, qui hérite de Base, qui est gérée par Derived, qui hérite de Base ... –

+0

@Cornstalks yea sonne à peu près juste –

Répondre

7

Le concept fondamental est de comprendre qu'une instance d'un modèle est juste une classe. Ce n'est fondamentalement pas différent de n'importe quelle autre classe.

Lorsque vous avez une définition typique de modèle:

template<typename T> class Base; 

Ensuite, l'instance de modèle:

Base<int> 

est juste une classe de ce nom. Il n'a rien à voir avec int, et n'a absolument aucune relation, quelle qu'elle soit, avec un int. Il n'en hérite pas, d'une manière ou d'une autre.

Prochaine étape:

class Derived; 

template<typename T> class Base {}; 

Base<Derived> foo; 

Encore une fois, Base<Derived> est juste une classe. Il n'a aucune relation intrinsèque avec Derived. Il n'en dérive pas, n'en hérite pas, rien.

Donc, maintenant nous prenons la dernière étape:

template<class T> 
class Base 
{ 

}; 

class Derived : public Base<Derived> 
{ 

}; 

Ceci déclare une classe appelée Derived, qui hérite d'une classe appelée Base<Derived>. Et Base<Derived> est juste une classe. C'est une classe très simple. Je ne peux pas être plus simple que ça. Il n'a pas de méthodes. Il n'a aucun membre. Ni privé, protégé ou public. C'est une toute petite classe, mais elle a les mêmes droits et privilèges que n'importe quelle autre classe. Vous pouvez déclarer un pointeur dessus. Ou une référence à cela. C'est juste une classe.

Encore une fois, le concept clé est qu'une instance d'un modèle est juste une classe. Il "n'hérite" en aucune façon de la classe qui est le paramètre du template. Dans ce cas, l'instance du modèle est complètement vide, mais elle peut faire tout ce que n'importe quelle autre classe peut faire. Il peut avoir des membres publics, privés et protégés. Il peut dériver d'une autre classe, qui pourrait être une autre instance de modèle (puisqu'une instance de modèle est juste une classe). Ou, une autre classe peut dériver de l'instance de modèle, car une instance de modèle est juste une classe.

Il n'y a pas d'imbrication infinie ici. Vous venez d'hériter d'une classe d'une autre classe. La deuxième classe se trouve être une instance de modèle, mais ai-je mentionné qu'une instance de modèle est juste une classe?

3

explication simple: parce que ce qui suit est tout à fait valable:

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. 
}