Injected-class-name
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:
-
Es seguido por
<. - Se utiliza como un template template argument .
- Es el identificador final en el elaborated class specifier de una declaración friend class template.
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
Den el ámbito de la claseCencuentra 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 |