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

El nombre de clase inyectado es el nombre no calificado de una clase dentro del ámbito de dicha clase.

En una class template , el nombre de clase inyectado puede usarse como un nombre de plantilla que se refiere a la plantilla actual, o como un nombre de clase que se refiere a la instanciación actual.

Contenidos

Explicación

En un ámbito de clase , el nombre de clase de la clase actual o el nombre de plantilla de la plantilla de clase actual se trata como si fuera un nombre de miembro público; esto se denomina injected-class-name . El punto de declaración del nombre es inmediatamente después de la llave de apertura de la definición de la clase (plantilla).

int X;
struct X
{
    void f()
    {
        X* p;   // OK, X es un nombre de clase inyectado
        ::X* q; // Error: la búsqueda de nombre encuentra un nombre de variable, que oculta el nombre de la estructura
    }
};
template<class T>
struct Y
{
    void g()
    {
        Y* p;    // OK, Y es un nombre de clase inyectado
        Y<T>* q; // OK, Y es un nombre de clase inyectado, pero Y<T> no lo es
    }
};

Al igual que otros miembros, los nombres inyectados de clase se heredan. En presencia de herencia privada o protegida, el nombre inyectado de clase de una clase base indirecta podría terminar siendo inaccesible en una clase derivada.

struct A {};
struct B : private A {};
struct C : public B
{
    A* p;   // Error: el nombre de clase inyectado A es inaccesible
    ::A* q; // OK, no utiliza el nombre de clase inyectado
};

En plantilla de clase

El nombre de clase inyectado de una plantilla de clase puede utilizarse como nombre de plantilla o como nombre de tipo.

En los siguientes casos, el nombre de clase inyectado se trata como un nombre de plantilla de la propia plantilla de clase:

De lo contrario, se trata como un nombre de tipo, y es equivalente al nombre de plantilla seguido de los parámetros de plantilla de la clase de plantilla encerrados en <> .

template<template<class, class> class>
struct A;
template<class T1, class T2>
struct X
{
    X<T1, T2>* p;   // OK, X se trata como un nombre de plantilla
    using a = A<X>; // OK, X se trata como un nombre de plantilla
    template<class U1, class U2>
    friend class X; // OK, X se trata como un nombre de plantilla
    X* q;           // OK, X se trata como un nombre de tipo, equivalente a X<T1, T2>
};

Dentro del ámbito de una clase template specialization o partial specialization , cuando el nombre-de-clase-inyectado se utiliza como nombre-de-tipo, es equivalente al nombre-de-plantilla seguido por los argumentos-de-plantilla de la especialización de plantilla de clase o especialización parcial encerrados en <> .

template<>
struct X<void, void>
{
    X* p; // OK, X se trata como un nombre de tipo, equivalente a X<void, void>
    template<class, class>
    friend class X; // OK, X se trata como un nombre de plantilla (igual que en la plantilla primaria)
    X<void, void>* q; // OK, X se trata como un nombre de plantilla
};
template<class T>
struct X<char, T>
{
    X* p, q; // OK, X se trata como un nombre de tipo, equivalente a X<char, T>
    using r = X<int, int>; // OK, puede usarse para nombrar otra especialización
};

El nombre de clase inyectado de una plantilla de clase o especialización de plantilla de clase puede usarse como nombre de plantilla o como nombre de tipo dondequiera que esté en alcance.

template<>
class X<int, char>
{
    class B
    {
        X a;            // significa X<int, char>
        template<class, class>
        friend class X; // significa ::X
    };
};
template<class T>
struct Base
{
    Base* p; // OK: Base significa Base<T>
};
template<class T>
struct Derived : public Base<T*>
{
    typename Derived::Base* p; // OK: Derived::Base significa Derived<T>::Base,
                               // que es Base<T*>
};
template<class T, template<class> class U = T::template Base>
struct Third {};
Third<Derived<int>> t; // OK: el argumento por defecto usa el nombre de clase inyectado como plantilla

Una búsqueda que encuentra un nombre de clase inyectado puede resultar en una ambigüedad en ciertos casos (por ejemplo, si se encuentra en más de una clase base). Si todos los nombres de clase inyectados que se encuentran se refieren a especializaciones de la misma plantilla de clase, y si el nombre se utiliza como nombre de plantilla, la referencia se refiere a la plantilla de clase misma y no a una especialización de la misma, y no es ambigua.

template<class T>
struct Base {};
template<class T>
struct Derived: Base<int>, Base<char>
{
    typename Derived::Base b;         // error: ambiguo
    typename Derived::Base<double> d; // OK
};

nombre de clase inyectado y constructores

Los constructores no tienen nombres, pero el nombre de clase inyectado de la clase envolvente se considera que nombra un constructor en las declaraciones y definiciones de constructores.

En un nombre calificado C::D , si

  • la búsqueda de nombres no ignora los nombres de funciones, y
  • la búsqueda de D en el ámbito de la clase C encuentra su nombre de clase inyectado

el nombre calificado siempre se considera que nombra C 's constructor. Tal nombre solo puede usarse en la declaración de un constructor (por ejemplo, en una declaración de constructor friend, una especialización de plantilla de constructor, una instanciación de plantilla de constructor, o una definición de constructor) o usarse para heredar constructores (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;         // Error: A::A se considera que nombra un constructor, no un tipo
struct A::A a2; // OK, igual que 'A a2;'
B::A b;         // OK, igual que 'A b;'

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 1004 C++98 un injected-class-name no podía
ser un template template argument
permitido, se refiere a la plantilla
de clase en este caso
CWG 2637 C++98 el template-id completo podía ser un injected-class-name solo el nombre de plantilla puede