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
: typename Something
. Le problème est qu’il peut y avoir un T
pour lequel Something
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
.
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; };