Namespaces
Variants

Injected-class-name

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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 :

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 D dans la portée de la classe C trouve 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