Où et pourquoi dois-je mettre le “modèle” et “typename” de mots-clés?
Dans les modèles, où et pourquoi dois-je mettre typename
et template
sur dépendante des noms? Qu'est-ce exactement sont dépendants des noms de toute façon? J'ai le code suivant:
template <typename T, typename Tail> //Tail will be a UnionNode too.
struct UnionNode : public Tail {
//...
template<typename U> struct inUnion {
//Q: where to add typename/template here?
typedef Tail::inUnion<U> dummy;
};
template< > struct inUnion<T> {
};
};
template <typename T> //For the last node Tn.
struct UnionNode<T, void> {
//...
template<typename U> struct inUnion {
char fail[ -2 + (sizeof(U)%2) ]; //Cannot be instantiated for any U
};
template< > struct inUnion<T> {
};
};
Le problème que j'ai est dans le typedef Tail::inUnion<U> dummy
ligne. Je suis assez certain que inUnion
est une personne à charge nom et VC++ est tout à fait juste en étouffer. Je sais aussi que je devrais être en mesure d'ajouter template
quelque part pour indiquer au compilateur que inUnion est un modèle-id. Mais où exactement? Et faut-il alors supposer que inUnion est un modèle de classe, c'est à dire inUnion<U>
le nom d'un type et non pas une fonction?
Ennuyeux question: pourquoi ne pas boost::Variant?
Sensibilités politiques, de la portabilité.
J'ai fait votre question réelle ("Où mettre template/typename?") se démarquer de mieux en mettant la dernière question et le code au début et à raccourcir le code horizontalement pour s'adapter à un 1024x écran.
Suppression de "l'dépendant de noms" dans le titre, car il semble que la plupart des gens qui s'interrogent sur "typename" et "modèle" ne sait pas ce que "dépendante" de noms. Il devrait être moins compliqué de cette façon.
boost est tout à fait portable. Je dirais que la seule politique est la raison pour laquelle pourquoi boost est souvent unembraced. La seule bonne raison que je sais c'est l'augmentation du temps de compilation. Sinon, c'est tout sur la perte de milliers de dollars de réinventer la roue.
Sensibilités politiques, de la portabilité.
J'ai fait votre question réelle ("Où mettre template/typename?") se démarquer de mieux en mettant la dernière question et le code au début et à raccourcir le code horizontalement pour s'adapter à un 1024x écran.
Suppression de "l'dépendant de noms" dans le titre, car il semble que la plupart des gens qui s'interrogent sur "typename" et "modèle" ne sait pas ce que "dépendante" de noms. Il devrait être moins compliqué de cette façon.
boost est tout à fait portable. Je dirais que la seule politique est la raison pour laquelle pourquoi boost est souvent unembraced. La seule bonne raison que je sais c'est l'augmentation du temps de compilation. Sinon, c'est tout sur la perte de milliers de dollars de réinventer la roue.
OriginalL'auteur MSalters | 2009-03-04
Vous devez vous connecter pour publier un commentaire.
Afin d'analyser un programme en C++, le compilateur a besoin de savoir si certains noms sont des types ou pas. L'exemple suivant montre que:
Comment cela doit-il être interprété? Pour de nombreuses langues, le compilateur n'a pas besoin de connaître la signification d'un nom afin de les analyser et, essentiellement, de savoir ce qu'une ligne de code. En C++, le ci-dessus peut toutefois rendement très différentes interprétations en fonction de ce
t
moyens. Si c'est un type, alors il y aura une déclaration d'un pointeurf
. Toutefois, si c'est pas un type, il sera une multiplication. De sorte que le C++ Standard dit au paragraphe (3/7):Comment le compilateur de savoir ce qu'est un nom de
t::x
se réfère, sit
se réfère à un modèle type de paramètre?x
pourrait être un static int membre de données qui pourrait être multiplié ou pourrait tout aussi bien être une classe imbriquée ou définition de type qui pourrait produire une déclaration. Si un nom a cette propriété qu'il ne peut pas être regardé, jusqu'à ce que le modèle actuel et les arguments sont connus, alors il est appelé un dépendante nom (il "dépend" sur les paramètres du modèle).Vous pourriez recommander à juste attendre jusqu'à ce que l'utilisateur instancie le modèle:
Cela fonctionne, et c'est permis par la Norme comme une possible approche de mise en œuvre. Ces compilateurs essentiellement de copier le modèle du texte dans une mémoire tampon interne, et uniquement lors d'une instanciation est nécessaire, ils analyser le modèle et éventuellement de détecter les erreurs dans la définition. Mais plutôt que de déranger le modèle des utilisateurs (les pauvres collègues!) avec les erreurs commises par un modèle de l'auteur, d'autres implémentations de choisir de vérifier les modèles de début et de lui donner les erreurs dans la définition, dès que possible, avant qu'une instanciation d'un même lieu.
Donc il y a une façon de dire au compilateur que certains noms sont des types, et que certains noms ne sont pas.
La "typename" mot-clé
La réponse est: Nous décider comment le compilateur doit analyser cette. Si
t::x
est une personne à charge nom, alors nous avons besoin de le préfixer partypename
pour indiquer au compilateur d'analyser, d'une certaine façon. Que dit la Norme (14.6/2):Il y a beaucoup de noms pour lesquels
typename
n'est pas nécessaire, car le compilateur ne peut, avec la recherche d'un nom dans la définition de modèle, de comprendre comment analyser une construction elle - même, par exemple avecT *f;
, quandT
est un type de paramètre de modèle. Mais pourt::x * f;
être une déclaration, il doit être écrit commetypename t::x *f;
. Si vous omettez le mot clé et le nom est pris pour être un non-type, mais lors de l'instanciation trouve qu'il dénote un type, l'habitude de messages d'erreur émis par le compilateur. Parfois, l'erreur est donc donnée à la définition du temps:La syntaxe permet
typename
seulement avant les noms qualifiés - il est donc pris comme acquis que les noms non qualifiés sont toujours connus pour désigner des types s'ils le font.Similaire gotcha existe pour les noms désignant des modèles, comme signalé par le texte d'introduction.
Le "modèle" mot-clé
Souviens de la première citation ci-dessus et comment le Standard nécessite un traitement spécial pour les modèles ainsi? Prenons la suite de l'allure innocente exemple:
Ça peut paraître évident pour un lecteur humain. Pas tellement pour le compilateur. Imaginez la suite arbitraire de la définition de
boost::function
etf
:Qui est en fait valable expression! Il utilise l'opérateur inférieur à comparer
boost::function
contre zéro (int()
), puis utilise l'opérateur supérieur à comparer l'résultantbool
contref
. Cependant comme vous pouvez vous le savez bien,boost::function
dans la vraie vie est un modèle, de sorte que le compilateur sait (14.2/3):Maintenant nous sommes de retour pour le même problème qu'avec
typename
. Que faire si nous ne savons pas encore si le nom est un modèle lors de l'analyse du code? Nous aurons besoin d'insérertemplate
immédiatement avant le nom du modèle, tel que spécifié par14.2/4
. Cela ressemble à:Les noms de modèle ne peut pas seulement se produire après un
::
mais aussi après une->
ou.
dans une classe de l'accès des membres. Vous devez insérer le mot-clé il y a trop:Dépendances
Pour les gens qui ont une épaisseur de Standardese livres sur leur étagère et qui veulent savoir exactement ce dont je parlais, je vais parler un peu comment cela est spécifié dans la Norme.
Dans le modèle des déclarations de certaines constructions ont des significations différentes en fonction de ce modèle arguments que vous utilisez pour instancier le modèle: les Expressions peuvent avoir différents types ou des valeurs, des variables peuvent avoir des types différents ou des appels de fonction pourrait appeler des fonctions différentes. De telles constructions sont généralement dépendent sur les paramètres du modèle.
La Norme définit précisément les règles de savoir si une construction est dépendante ou non. Il les sépare logiquement dans les différents groupes: l'Un des captures types, un autre des captures d'expressions. Les Expressions peuvent dépendre de leur valeur et/ou de leur type. Nous avons donc, avec des exemples typiques ajouté:
T
)N
)(T)0
)La plupart des règles sont intuitives et sont construits de manière récursive: Par exemple, un type construit comme
T[N]
est un type dépendant siN
est une valeur dépendante de l'expression ou de laT
est un type de charge. Les détails de ce qui peut être lu dans la section(14.6.2/1
) pour les types de charge,(14.6.2.2)
pour les en fonction du type d'expressions et(14.6.2.3)
pour une valeur dépendante de la expressions.Dépendant de noms
La Norme est un peu confus au sujet de ce que exactement est un dépendante nom. Sur une simple lecture (vous savez, le principe de moindre surprise), tout ce qu'il définit comme un dépendante nom est le cas spécial pour les noms de fonction ci-dessous. Mais depuis clairement
T::x
doit également être recherchée dans l'instanciation contexte, il a aussi besoin d'être une personne à charge nom (heureusement, au milieu de C++14, le comité a commencé à examiner la façon de résoudre cette confusion définition).Pour éviter ce problème, j'ai recours à une simple interprétation du texte Standard. De toutes les constructions qui dénotent des types dépendants ou des expressions, un sous-ensemble d'entre eux représentent des noms. Ces noms sont donc "dépendante" de noms. Un nom peut prendre différentes formes - que dit la Norme:
Un identificateur est juste une simple séquence de caractères /chiffres, tandis que les deux suivantes sont les
operator +
etoperator type
forme. La dernière forme esttemplate-name <argument list>
. Tous ces noms, et par l'utilisation conventionnelle de la Norme, un nom peut également inclure des qualificatifs que dire ce que l'espace de noms ou de classe, un nom doit être recherché dans.Une valeur dépendante de l'expression
1 + N
n'est pas un nom, maisN
est. Le sous-ensemble de tous dépendants les constructions qui sont des noms est appelé dépendante nom. Les noms de fonction, cependant, peut avoir une signification différente dans les différentes instanciations d'un modèle, mais, malheureusement, ne sont pas visés par cette règle générale.Fonction dépend de noms
Pas principalement une préoccupation de cet article, mais il vaut la peine de mentionner les noms de Fonction sont une exception qui sont traitées séparément. Un identificateur nom de la fonction est dépendante de la pas par lui-même, mais par le type dépendant argument une expression utilisée dans un appel. Dans l'exemple
f((T)0)
,f
est une personne à charge nom. Dans la Norme, c'est spécifiée à(14.6.2/1)
.Des notes supplémentaires et des exemples
Assez de cas, nous avons besoin à la fois de
typename
ettemplate
. Votre code devrait ressembler à celui-ciLe mot-clé
template
n'est pas toujours figurer dans la dernière partie d'un nom. Elle peut apparaître sur le milieu devant un nom de classe qui est utilisé comme un champ d'application, comme dans l'exemple suivantDans certains cas, les mots clés sont interdites, comme détaillé ci-dessous
Sur le nom de l'un dépendant de la classe de base, vous n'êtes pas autorisé à écrire
typename
. Il est supposé que le nom donné est un type de classe nom. Cela est vrai pour les deux noms dans la base-liste des classes et le constructeur de l'initialiseur de la liste:À l'aide de déclarations, il n'est pas possible d'utiliser
template
après la dernière::
, et le comité C++ dit de ne pas travailler sur une solution.Pouvez-vous m'aider quand dois-je utiliser cette syntaxe? this->modèle de f<int>(); j'ai cette erreur "modèle" (comme un disambiguator) n'est autorisée que dans les modèles, mais sans le modèle de mot-clé, il fonctionne très bien.
La présentation de cette réponse est tout simplement merveilleuse. Il est bien pensé et apporte pause à toute personne qui les lit à la question de ce qu'ils vraiment pense qu'ils savent au sujet de la façon dont le langage "œuvres". Je souhaite que je pourrais haut de voter plus d'une fois.
vous ne manquez rien. Mais encore nécessaire pour écrire la désambiguïsation même si la ligne ne serait pas plus ambiguë.
le but est de garder la langue et les compilateurs plus simple. Il y a des propositions pour permettre à davantage de situations automatiquement comprendre les choses, de sorte que vous avez besoin de la clé de moins en moins souvent. Notez que dans votre exemple, le jeton est ambigu et seulement après que vous avez vu ">" après le double, vous pouvez lever l'ambiguïté comme un modèle de crochet. Pour plus de détails, je suis la mauvaise personne à demander, parce que je n'ai aucune expérience dans la mise en œuvre d'une compilateurs C++' analyseur.
OriginalL'auteur Johannes Schaub - litb
C++11
Problème
Alors que les règles en C++03 sujet de quand vous avez besoin
typename
ettemplate
sont largement raisonnable, il y a un inconvénient gênant de sa formulationComme on peut le voir, nous avons besoin de la désambiguïsation mot-clé, même si le compilateur peut parfaitement comprendre que
A::result_type
ne peut êtreint
(et est donc un type), etthis->g
ne peut être que le membre modèleg
déclaré plus tard (même siA
est explicitement spécialisés quelque part, cela ne modifie pas le code au sein de ce modèle, de sorte que son sens ne peut pas être affectée par un plus tard, la spécialisation deA
!).Actuel de l'instanciation
Pour améliorer la situation, en C++11 la langue des pistes quand un type se réfère à l'enfermant modèle. À savoir que, le type doit avoir été formé en utilisant une certaine forme de nom, qui est son propre nom (ci-dessus,
A
,A<T>
,::A<T>
). Un type référencé par un nom qui est connu pour être la actuel de l'instanciation de. Il peut y avoir plusieurs types qui sont tous au courant de l'instanciation si le type de qui le nom est formé, est un membre/classe imbriquée (puis,A::NestedClass
etA
sont à la fois actuel instanciations).Basé sur cette notion, la langue dit que
CurrentInstantiation::Foo
,Foo
etCurrentInstantiationTyped->Foo
(commeA *a = this; a->Foo
) sont tous membres de l'actuel instanciation si ils sont membres d'une classe qui est l'actuel instanciation ou de l'une de ses non-dépendante des classes de base (il vous suffit de faire la recherche par nom immédiatement).Les mots-clés
typename
ettemplate
sont maintenant pas plus requis si le qualificatif est un membre de l'actuel de l'instanciation. Un point crucial de rappeler ici est queA<T>
est encore un de dépendant du type de nom (après toutT
est également dépendante du type). MaisA<T>::result_type
est connu pour être de type, le compilateur "comme par magie" regarde ce genre de types dépendants.C'est impressionnant, mais que pouvons-nous faire mieux? La langue va même plus loin et nécessite qu'une mise en œuvre regarde à nouveau jusqu'
D::result_type
lors de l'instanciation deD::f
(même si il a trouvé son sens déjà à la définition du temps). Lorsque maintenant le résultat de recherche diffère ou les résultats dans l'ambiguïté, le programme est mal formé et un diagnostic doit être donné. Imaginez ce qui arriverait si nous avons définiC
comme ceUn compilateur est nécessaire à la capture de l'erreur lors de l'instanciation de
D<int>::f
. Ainsi, vous obtenez le meilleur des deux mondes: "le Retard" recherche de vous protéger si vous pourriez avoir de la difficulté à charge des classes de base, et aussi "Immédiate" de recherche qui vous permet de vous libérer detypename
ettemplate
.Inconnu spécialisations
Dans le code de
D
, le nomtypename D::questionable_type
n'est pas un membre de l'actuel de l'instanciation. Au lieu de la langue de la marque comme un membre d'un inconnu spécialisation. En particulier, ce qui est toujours le cas lorsque vous faitesDependentTypeName::Foo
ouDependentTypedName->Foo
et soit le type de charge est pas le courant de l'instanciation (dans ce cas, le compilateur peut faire et de dire "nous allons examiner plus tard ce queFoo
est) ou il est le courant de l'instanciation et le nom n'a pas été trouvé ou ses non-dépendante des classes de base et il y a aussi dépendante des classes de base.Imaginer ce qui se passe si nous avons eu une fonction membre
h
au sein de l'défini ci-dessusA
modèle de classeEn C++03, la langue a permis de rattraper cette erreur, car il ne pourrait jamais être un moyen valable pour instancier
A<T>::h
(quel argument que vous donnez àT
). En C++11, la langue a maintenant un chèque supplémentaire de donner une raison de plus pour les compilateurs pour mettre en œuvre cette règle. DepuisA
a la charge des classes de base, etA
déclare aucun membrequestionable_type
, le nomA<T>::questionable_type
est ni un membre de l'actuel instanciation ni un membre d'un inconnu spécialisation. Dans ce cas, il devrait y avoir aucun moyen que ce code pourrait valablement compiler à l'instanciation de temps, de sorte que la langue interdit à un nom de où le qualificatif est un courant de l'instanciation de n'être ni un membre d'un inconnu spécialisation, ni membre de l'actuel de l'instanciation (toutefois, cette violation est toujours pas nécessaire d'être diagnostiqué).Exemples et les anecdotes
Vous pouvez essayer cette connaissance cette réponse et de voir si les définitions ci-dessus ont un sens pour vous sur un exemple réel (ils se répètent un peu moins détaillée dans la réponse).
Le C++11, les règles, les valide en C++03 code mal formé (qui n'était pas prévue par le comité C++, mais ne sera probablement pas fixe)
Ce valide en C++03 code lier
this->f
àA::f
à l'instanciation de temps et tout va bien. C++11 est cependant immédiatement le lie àB::f
et nécessite un double-vérifier lors de l'instanciation, de vérifier si le recherche encore des matches. Cependant lors de l'instanciation deC<A>::g
, le La Domination De La Règle s'applique et la recherche d'trouverezA::f
à la place.OriginalL'auteur Johannes Schaub - litb
Quel est le but de
typename
ettemplate
?typename
ettemplate
sont utilisables dans d'autres situations que lors de la déclaration d'un modèle.Il y a certains contextes dans C++ où le compilateur doit être explicitement dit comment traiter un nom, et tous ces contextes ont une chose en commun; ils dépendent d'au moins un template-parameter.
Nous nous référons à ces noms, où il peut y avoir une ambiguïté dans l'interprétation, comme; "dépendant de noms".
Ce poste va offrir une explication de la relation entre dépendante des noms de, et les deux mots-clés.
UN EXTRAIT EN DIT PLUS QUE 1000 MOTS
Essayer d'expliquer ce qui se passe dans la suite de de la fonction de modèle de, soit à vous-même, un ami, ou peut-être de votre chat, ce qui se passe dans l'énoncé marqué (Un)?
Il pourrait ne pas être aussi facile qu'on le pense, plus précisément le résultat de l'évaluation (Un) fortement dépend sur la définition du type passé en tant que modèle à paramètre
T
.Différents
T
s peuvent changer radicalement la sémantique impliqués.Les deux scénarios différents:
Si nous instancier la fonction de modèle de type X, comme dans (C), nous aurons une déclaration d'un pointeur vers int nommé x, mais;
si nous instancier le modèle de type Y, comme dans (D), (Un) devrait plutôt consister en une expression qui calcule le produit de 123 multiplié avec certains déjà déclaré variable x.
LA JUSTIFICATION
La Norme C++ se soucie de la sécurité et le bien-être, au moins dans ce cas.
Pour empêcher une mise en œuvre à partir de potentiellement souffrant de mauvaises surprises, la Norme mandats que nous avons en quelque sorte l'ambiguïté d'un dépendante de nom de par explicitement indiquant l'intention de n'importe où nous aimerions traiter le nom comme un type de nom de, ou un modèle-id.
Si rien n'est indiqué, le dépendante de nom de sera considéré comme une variable ou une fonction.
COMMENT GÉRER DÉPENDANT DE NOMS?
Si c'était un film d'Hollywood, dépendante des noms de serait la maladie qui se propage par le contact du corps, instantanément affecte son hôte pour le rendre confus. La Confusion qui pourrait, éventuellement, conduire à un mal-formé perso-, heu.. programme.
Un dépendante de nom de est tout nom qui, directement ou indirectement, dépend d'un template-parameter.
Nous avons quatre dépendante noms dans l'extrait ci-dessus:
SomeTrait<T>
, qui comprennentT
, et;SomeTrait<T>
, et;SomeTrait<T>
, et;SomeTrait<T>
.Ni de déclaration (E), (F) ou (G) est valide si le compilateur pourrait interpréter le dépendante des noms de comme des variables/fonctions (comme indiqué plus haut est ce qui se passe si nous n'avons pas explicitement dire le contraire).
LA SOLUTION
De faire
g_tmpl
ont une définition valable, nous devons indiquer explicitement au compilateur que nous nous attendons à un type (E), un modèle-id et un type (F), et un modèle-id (G).Chaque fois qu'un nom désigne un type, tous noms concernées doivent être type-noms ou espaces de noms, avec cela à l'esprit, il est assez facile de voir que l'on applique
typename
au début de notre nom qualifié.template
cependant, est différente à cet égard, car il n'y a aucun moyen d'en venir à une conclusion comme; "oh, c'est un modèle, puis cette autre chose doit être aussi un modèle". Cela signifie que l'on appliquetemplate
directement en face de toute l' nom que nous aimerions traiter comme tel.PUIS-JE SIMPLEMENT COLLER LE MOTS-CLÉS EN FACE DE SON NOM?
Les règles de la Norme stipule que vous pouvez appliquer des mots-clés comme longtemps que vous faites affaire avec un qualifié-nom (K), mais si le nom n'est pas qualifié l'application est mal formé (L).
Note: Application de
typename
outemplate
dans un contexte où il n'est pas nécessaire n'est pas considéré comme une bonne pratique; juste parce que vous pouvez faire quelque chose, ne signifie pas que vous devriez.En outre il y a des contextes où
typename
ettemplate
sont explicitement interdits:Lors de la spécification des bases dont la classe hérite
Chaque nom écrit dans une classe dérivée de de base-spécificateur-liste est déjà traité comme un type de nom de, spécifiant explicitement
typename
est à la fois mal formé, et redondants.Lorsque le modèle-id est celui mentionné dans une classe dérivée de à l'aide de la directive
OriginalL'auteur Filip Roséen - refp
Cependant, je ne suis pas sûr que vous êtes à la mise en œuvre de inUnion est correct. Si je comprends bien, cette classe n'est pas censé être instancié, donc le "fail" de l'onglet ne sera jamais avtually échoue. Il serait peut-être mieux indique si le type est dans l'union ou pas avec une simple valeur booléenne.
PS: jetez un oeil à Boost::Variant
PS2: jetez un oeil à typelists, notamment dans Andrei Alexandrescu du livre: Modern C++ Design
Et le travail avec result=true/false, c'est que j'avais besoin de boost::enable_if< >, ce qui est incompatible avec notre actuelle de la chaîne d'OSX. Le gabarit est toujours une bonne idée, cependant.
Luc signifie que la définition de type de Queue::inUnion<U> mannequin; ligne. qui va instancier la Queue. mais pas inUnion<U>. il est instanciée lorsqu'il a besoin de toute définition. que se passe par exemple si vous prenez le sizeof, ou accéder à un membre (à l'aide d' ::foo). @MSalters de toute façon, vous avez un autre problème:
-sizeof(U) n'est jamais négatif 🙂 parce que size_t est un type entier non signé. vous obtiendrez certains nombre très élevé. vous voulez probablement faire sizeof(U) >= 1 ? -1 : 1 ou similaires 🙂
je voudrais juste laisser pas défini et seulement déclarer: template<typename U> struct inUnion; de sorte qu'il ne peut certainement pas être instanciée. je pense que le sizeof, le compilateur est également autorisée à vous donner une erreur, même si vous pas instancier, parce que si sait sizeof(U) est toujours >=1 et ...
OriginalL'auteur Luc Touraille
Cette réponse est destinée à être assez court et doux une réponse (une partie de) l'intitulé de la question. Si vous voulez une réponse avec plus de détails qui explique pourquoi vous devez les mettre là, s'il vous plaît aller ici.
La règle générale pour mettre le
typename
mot-clé est la plupart du temps lorsque vous utilisez un paramètre de modèle et que vous souhaitez accéder à un imbriquéetypedef
ou l'aide-alias, par exemple:Noter que ceci s'applique également aux fonctions de meta ou les choses qui prennent modèle générique de paramètres. Cependant, si le paramètre de modèle fourni est de type explicite, alors vous n'avez pas à spécifier
typename
, par exemple:Les règles générales pour l'ajout de la
template
qualificatif sont pour la plupart les mêmes, sauf qu'ils impliquent généralement basées sur des modèles de fonctions membres (statiques ou non) de la structure/classe qui est lui-même basé sur un modèle, par exemple:Compte tenu de cette structure et de la fonction:
Tenter d'accéder à des
t.get<int>()
à partir de l'intérieur de la fonction génère une erreur:Donc, dans ce contexte, vous aurez besoin de l'
template
mot-clé à l'avance et de l'appeler de la sorte:t.template get<int>()
De cette façon, le compilateur va analyser correctement, plutôt que de
t.get < int
.OriginalL'auteur Rapptz
Je me suis mise JLBorges excellent réponse à une question similaire, mot pour mot cplusplus.com comme il est de la plus succincte explication que j'ai lu sur le sujet.
Résumé
Utilisez le mot-clé typename uniquement dans modèle déclarations et les définitions à condition d'avoir un nom qui fait référence à un type et dépend d'un paramètre du modèle.
OriginalL'auteur Nikos