Injected-class-name
Le nom de classe injecté est le nom non qualifié d'une classe dans la portée de ladite classe.
Dans un class template , le nom de classe injecté peut être utilisé soit comme un nom de template qui fait référence au template actuel, soit comme un nom de classe qui fait référence à l'instanciation actuelle.
Table des matières |
Explication
Dans une portée de classe , le nom de classe de la classe courante ou le nom de template du template de classe courant est traité comme s'il s'agissait d'un nom de membre public ; cela est appelé injected-class-name . Le point de déclaration du nom se situe immédiatement après l'accolade ouvrante de la définition de la classe (template).
int X; struct X { void f() { X* p; // OK, X est un nom de classe injecté ::X* q; // Erreur : la recherche de nom trouve un nom de variable, qui masque le nom de la structure } }; template<class T> struct Y { void g() { Y* p; // OK, Y est un nom de classe injecté Y<T>* q; // OK, Y est un nom de classe injecté, mais Y<T> ne l'est pas } };
Comme les autres membres, les noms injectés de classe sont hérités. En présence d'un héritage privé ou protégé, le nom injecté de classe d'une classe de base indirecte peut devenir inaccessible dans une classe dérivée.
struct A {}; struct B : private A {}; struct C : public B { A* p; // Erreur : le nom de classe injecté A est inaccessible ::A* q; // OK, n'utilise pas le nom de classe injecté };
Dans le modèle de classe
Le nom de classe injecté d'un modèle de classe peut être utilisé comme nom de modèle ou comme nom de type.
Dans les cas suivants, le nom de classe injecté est traité comme un nom de template du modèle de classe lui-même :
-
Il est suivi par
<. - Il est utilisé comme argument de template template .
- Il s'agit du dernier identifiant dans le spécificateur de type élaboré d'une déclaration de classe amie template.
Sinon, il est traité comme un nom de type, et est équivalent au nom du template suivi des paramètres du template de la classe template placés entre
<>
.
template<template<class, class> class> struct A; template<class T1, class T2> struct X { X<T1, T2>* p; // OK, X est traité comme un nom de template using a = A<X>; // OK, X est traité comme un nom de template template<class U1, class U2> friend class X; // OK, X est traité comme un nom de template X* q; // OK, X est traité comme un nom de type, équivalent à X<T1, T2> };
Dans le cadre d'une
spécialisation de modèle
ou d'une
spécialisation partielle
de classe, lorsque le nom de classe injecté est utilisé comme nom de type, il est équivalent au nom du modèle suivi des arguments du modèle de la spécialisation de modèle de classe ou de la spécialisation partielle placés entre
<>
.
template<> struct X<void, void> { X* p; // OK, X est traité comme un nom de type, équivalent à X<void, void> template<class, class> friend class X; // OK, X est traité comme un nom de template (identique au template primaire) X<void, void>* q; // OK, X est traité comme un nom de template }; template<class T> struct X<char, T> { X* p, q; // OK, X est traité comme un nom de type, équivalent à X<char, T> using r = X<int, int>; // OK, peut être utilisé pour nommer une autre spécialisation };
Le nom de classe injecté d'un modèle de classe ou d'une spécialisation de modèle de classe peut être utilisé soit comme nom de modèle soit comme nom de type partout où il est dans la portée.
template<> class X<int, char> { class B { X a; // signifie X<int, char> template<class, class> friend class X; // signifie ::X }; }; template<class T> struct Base { Base* p; // OK : Base signifie Base<T> }; template<class T> struct Derived : public Base<T*> { typename Derived::Base* p; // OK : Derived::Base signifie Derived<T>::Base, // qui est Base<T*> }; template<class T, template<class> class U = T::template Base> struct Third {}; Third<Derived<int>> t; // OK : l'argument par défaut utilise le nom de classe injecté comme template
Une recherche qui trouve un nom de classe injecté peut entraîner une ambiguïté dans certains cas (par exemple, s'il est trouvé dans plus d'une classe de base). Si tous les noms de classe injectés trouvés se réfèrent à des spécialisations du même modèle de classe, et si le nom est utilisé comme nom de modèle, la référence se rapporte au modèle de classe lui-même et non à une spécialisation de celui-ci, et n'est pas ambiguë.
template<class T> struct Base {}; template<class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // erreur : ambigu typename Derived::Base<double> d; // OK };
nom de classe injecté et constructeurs
Les constructeurs n'ont pas de noms, mais le nom de classe injecté de la classe englobante est considéré comme nommant un constructeur dans les déclarations et définitions de constructeurs.
Dans un nom qualifié
C::D
, si
- la recherche de nom n'ignore pas les noms de fonctions, et
-
la recherche de
Ddans la portée de la classeCtrouve son nom de classe injecté
le nom qualifié est toujours considéré comme nommant
C
's constructor. Un tel nom ne peut être utilisé que dans la déclaration d'un constructeur (par exemple dans une déclaration de constructeur ami, une spécialisation de modèle de constructeur, une instanciation de modèle de constructeur, ou une définition de constructeur)
ou être utilisé pour hériter des constructeurs
(since C++11)
.
struct A { A(); A(int); template<class T> A(T) {} }; using A_alias = A; A::A() {} A_alias::A(int) {} template A::A(double); struct B : A { using A_alias::A; }; A::A a; // Erreur : A::A est considéré comme nommant un constructeur, pas un type struct A::A a2; // OK, identique à 'A a2;' B::A b; // OK, identique à 'A b;'
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Applicable à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 1004 | C++98 |
un nom de classe injecté ne pouvait pas
être un argument de template template |
autorisé, il se réfère au modèle de classe
lui-même dans ce cas |
| CWG 2637 | C++98 | le template-id entier pouvait être un nom de classe injecté | seul le nom du template peut |