Espacios de nombres
Variantes
Acciones

Nombre de clase inyectado

De cppreference.com
< cpp‎ | language
 
 
 
 

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

En una plantilla de clase, el nombre de clase inyectado se puede usar 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.

[editar] Explicación

En un ámbito de clase, el nombre de la clase actual se trata como si fuera un nombre de miembro público; esto se llama nombre de clase inyectado. El punto de declaración del nombre sigue inmediatamente a la llave de apertura de la definición de clase.

int X;
struct X {
    void f() {
        X* p;   // de acuerdo: X se refiere al nombre de clase inyectado
        ::X* q; // ERROR: la búsqueda de nombres encuentra un nombre de variable,
                // que oculta el nombre de la estructura
    }
};

Al igual que otros miembros, los nombres de clase inyectados se heredan. En presencia de herencia privada o protegida, el nombre de clase inyectado 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: nombre de clase inyectado A es inaccesible
    ::A* q;     // de acuerdo, no usa el nombre de clase inyectado
};

[editar] En la plantilla de clase

Al igual que otras clases, las plantillas de clase tienen un nombre de clase inyectado. El nombre de clase inyectado se puede usar como nombre de plantilla o nombre de tipo.

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

  • es seguido por <;
  • se usa como argumento de plantilla que corresponde a un parámetro de plantilla de plantilla;
  • es el identificador final en el especificador de clase elaborado de una declaración de plantilla de clase amiga.

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 plantilla de clase incluida en <>.

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

Dentro del ámbito de una especialización de plantilla de clase o especialización parcial, cuando el nombre de clase inyectado se usa como nombre de tipo, es equivalente al nombre de plantilla seguido de los argumentos de plantilla de la especialización de plantilla de clase o especialización parcial incluida en <>.

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

El nombre de clase inyectado de una plantilla de clase o la especialización de plantilla de clase se puede usar como nombre de plantilla o nombre de tipo dondequiera que esté dentro del ámbito.

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

Una búsqueda que encuentra un nombre de clase inyectado puede dar lugar a 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 usa como nombre de plantilla, la referencia se refiere a la plantilla de clase en sí y no a una especialización de la misma, y ​​no es ambiguo.

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; // de acuerdo
};

[editar] Nombre de clase inyectado y constructores

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

En un nombre calificado C::D, si:

  • la búsqueda de nombre no ignora los nombres de función;
  • 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 denomina al constructor de C. Tal nombre solo se puede usar en la declaración de un constructor (p. ej., en una declaración de constructor amigo, una especialización de plantilla de un constructor, creación de instancias de constructor de una plantilla, o definición de constructor) o ser usado para heredar constructores (desde C++11).

struct A {
    A();
    A(int);
    template<typename 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 denomina a un constructor, no a un tipo
struct A::A a2; // de acuerdo: lo mismo que 'A a2;'
B::A b; // de acuerdo: lo mismo que 'A b;'