Quand devrais-je utiliser le mot-clé «typename» lors de l’utilisation de modèles

Je travaille depuis peu sur un petit projet et je n’arrivais pas à trouver quelque chose ..

On m’a donné un fichier .h contenant une classe, en utilisant un modèle typename. À l’intérieur de cette classe, il y avait une classe privée.

template  class Something { public: Something(); ~Something(); Node* Function1(int index); int Index(const T& id); private: class Node() { public: T id; //Imagine the rest for the Node }; }; 

Le problème est survenu lorsque j’ai voulu définir les fonctions de la classe “Quelque chose”

Voici comment je le faisais (dans un fichier .inl)

 template Node* Something::Function1(int index) //Is the return type well written? { // returns the node at the specified index } template int Something::Index(const T& id) //Is the parameter type well specified? { // returns the index of the node with the specified id } 

La partie bogue était donc dans la partie définitions … Dois-je dire au compilateur que le type de retour (dans ce cas, Node *) utilise le modèle typename (comme celui-ci: typename Node* )? Et qu’en est-il du paramètre? typename const Node& ?

Donc, fondamentalement, quand dois-je spécifier si la fonction / le paramètre utilise un modèle?

Merci pour votre temps.

 template typename Something::Node * Something::Function1(int index) //Is the return type well written? { // returns the node at the specified index } 

Pour Function1 , vous devez indiquer au compilateur ce qu’est le nœud. Dans ce cas, il s’agit d’un type nested dans Something . Comme il dépend de T (c’est un nom dépendant), vous devez indiquer au compilateur qu’il s’agit d’un type. Vous devez donc l’écrire sous la forme typename Something::Node : typename Something::Node . Le problème est qu’il peut y avoir un T pour lequel Something::Node n’est pas réellement un type (c’est-à-dire si vous spécialisez partiellement Something ).

Pour Index , ce que vous avez est très bien – const T& est simplement une référence à un const T , et le compilateur sait ce que T est.

La règle simple: vous devez utiliser le mot-clé typename chaque fois que vous nommez un type à l’aide de la syntaxe Class::Type , si la partie Class dépend d’un paramètre de modèle. (La partie Class peut être un paramètre de modèle, ou un typedef dans votre modèle de classe, etc.)

Edit: Il existe également une certaine confusion au sujet des règles de scope de classe nestedes. Ceci est principalement indépendant du problème typename , voici donc un exemple non-template.

 class Outer { public: class Inner { }; Inner* func(Inner* obj); }; Outer::Inner* func(Inner* obj) { } 

Le nom complet de Inner est Outer::Inner . Mais vous pouvez également utiliser le nom Inner n’importe où dans le cadre de la classe Outer , y compris toute la déclaration de func . Lors de la définition de func , le type de retour N’EST PAS dans la scope de Outer . Le nom complet est donc nécessaire. Mais après le ( , les parameters de la fonction sont dans la scope de Outer , le nom abrégé est donc correct.

En combinant ceci avec le modèle de l’exemple d’origine, puisque l’équivalent de Outer est Something , vous avez besoin du mot-clé typename pour dire Something::Node .

typename et class sont équivalents dans la liste de parameters de type de modèle:

 template  class C; 

est le même que

 template  class C; 

Le typename est requirejs lorsque vous vous typename à des noms dépendants :

 template  struct A { typedef typename T::some_type container; };