Quand le mot-clé “typename” est-il nécessaire?

Duplication possible:
Officiellement, à quoi sert typename?
Où et pourquoi dois-je mettre le template et les mots-clés de typename?

considérez le code ci-dessous:

template class C { struct P {}; vector

vec; void f(); }; template void C::f() { typename vector

::iterator p = vec.begin(); }

Pourquoi le mot-clé “typename” est-il nécessaire dans cet exemple? Y a-t-il d’autres cas où “typename” doit être spécifié?

Réponse courte: Chaque fois que vous faites référence à un nom nested qui est un nom dépendant , c’est-à-dire nested dans une instance de modèle avec un paramètre inconnu.

Réponse longue: Il existe trois niveaux d’entités dans C ++: valeurs, types et modèles. Tous ceux-ci peuvent avoir des noms et le nom seul ne vous dit pas à quel niveau d’entité il s’agit. L’information sur la nature de l’entité d’un nom doit plutôt être déduite du contexte.

Chaque fois que cette conclusion est impossible, vous devez le spécifier:

 template  struct Magic; // defined somewhere else template  struct A { static const int value = Magic::gnarl; // assumed "value" typedef typename Magic::brugh my_type; // decreed "type" // ^^^^^^^^ void foo() { Magic::template kwpq(1, 'a', .5); // decreed "template" // ^^^^^^^^ } }; 

Ici, les noms Magic::gnarl , Magic::brugh et Magic::kwpq ont dû être expliqués, car il est impossible de dire: puisque Magic est un modèle, la nature même du type Magic dépend de T – il peut y avoir des spécialisations totalement différentes du modèle principal, par exemple.

Ce qui fait de Magic::gnarl un nom dépendant est le fait que nous sums dans une définition de modèle, où T est inconnu. Si nous avions utilisé Magic , ce serait différent, puisque le compilateur connaît (vous promettez!) La définition complète de Magic .

(Si vous voulez tester cela vous-même, voici un exemple de définition de Magic que vous pouvez utiliser. Pardonnez l’utilisation de constexpr dans la spécialisation pour des raisons de brièveté; si vous avez un ancien compilateur, n’hésitez pas à remplacer -style forme pré-C ++ 11.)

 template  struct Magic { static const T gnarl; typedef T & brugh; template  static void kwpq(int, char, double) { T x; } }; template <> struct Magic { // note that `gnarl` is absent static constexpr long double brugh = 0.25; // `brugh` is now a value template  static int kwpq(int a, int b) { return a + b; } }; 

Usage:

 int main() { A a; a.foo(); return Magic::kwpq(2, 3); // no disambiguation here! } 

Le mot-clé typename est nécessaire car l’ iterator est un type dépendant sur P Le compilateur ne peut pas deviner si l’ iterator fait référence à une valeur ou à un type, donc il prend sa valeur à moins que vous ne typename . Il est nécessaire chaque fois qu’un type dépend d’un argument de modèle, dans un contexte où les types ou les valeurs seraient valides. Par exemple, en tant que classes de base, typename n’est pas nécessaire car une classe de base doit être un type.

Sur le même sujet, il existe un mot-clé template permettant au compilateur de savoir qu’un nom dépendant est une fonction modèle au lieu d’une valeur.

Le mot-clé typename est nécessaire chaque fois qu’un nom de type dépend d’un paramètre de modèle, (le compilateur peut donc “connaître” la sémantique d’un identifiant ( type ou valeur ) sans avoir une table de symboles complète au premier passage).


Dans le même sens, et un peu moins courant, le motclé lone typename peut également être utile lorsque vous utilisez des parameters de modèle génériques: http://ideone.com/amImX

 #include  #include  #include  template