Injected-class-name
Der injizierte Klassenname ist der unqualifizierte Name einer Klasse innerhalb des Geltungsbereichs dieser Klasse.
In einer class template kann der injizierte Klassenname entweder als Template-Name, der sich auf das aktuelle Template bezieht, oder als Klassenname, der sich auf die aktuelle Instanziierung bezieht, verwendet werden.
Inhaltsverzeichnis |
Erklärung
In einem Klassenbereich wird der Klassenname der aktuellen Klasse oder der Template-Name des aktuellen Klassentemplates so behandelt, als ob es sich um einen öffentlichen Member-Namen handelt; dies wird als injected-class-name bezeichnet. Der Punkt der Deklaration des Namens ist unmittelbar nach der öffnenden geschweiften Klammer der Klassen-(Template-)Definition.
int X; struct X { void f() { X* p; // OK, X ist ein injizierter Klassenname ::X* q; // Fehler: Namenssuche findet einen Variablennamen, der den Strukturnamen verdeckt } }; template<class T> struct Y { void g() { Y* p; // OK, Y ist ein injizierter Klassenname Y<T>* q; // OK, Y ist ein injizierter Klassenname, aber Y<T> ist es nicht } };
Wie andere Mitglieder werden injizierte Klassennamen vererbt. Bei privater oder geschützter Vererbung kann der injizierte Klassenname einer indirekten Basisklasse in einer abgeleiteten Klasse möglicherweise unzugänglich werden.
struct A {}; struct B : private A {}; struct C : public B { A* p; // Fehler: injizierter Klassenname A ist unzugreifbar ::A* q; // OK, verwendet nicht den injizierten Klassennamen };
In Klassentemplate
Der injizierte Klassenname einer Klassenvorlage kann als Vorlagenname oder als Typname verwendet werden.
In den folgenden Fällen wird der injizierte Klassenname als Template-Name des Klassen-Templates selbst behandelt:
-
Es folgt
<. - Es wird als Template-Template-Argument verwendet.
- Es ist der letzte Bezeichner in der elaborated class specifier einer Friend-Klassen-Template-Deklaration.
Andernfalls wird es als Typname behandelt und entspricht dem Template-Namen gefolgt von den Template-Parametern der Klassen-Vorlage, eingeschlossen in
<>
.
template<template<class, class> class> struct A; template<class T1, class T2> struct X { X<T1, T2>* p; // OK, X wird als Template-Name behandelt using a = A<X>; // OK, X wird als Template-Name behandelt template<class U1, class U2> friend class X; // OK, X wird als Template-Name behandelt X* q; // OK, X wird als Typ-Name behandelt, äquivalent zu X<T1, T2> };
Im Rahmen einer Klassen-
Template-Spezialisierung
oder
partiellen Spezialisierung
, wenn der injizierte Klassenname als Typname verwendet wird, entspricht dies dem Template-Namen gefolgt von den Template-Argumenten der Klassen-Template-Spezialisierung oder partiellen Spezialisierung, eingeschlossen in
<>
.
template<> struct X<void, void> { X* p; // OK, X wird als Typname behandelt, äquivalent zu X<void, void> template<class, class> friend class X; // OK, X wird als Template-Name behandelt (wie im Primär-Template) X<void, void>* q; // OK, X wird als Template-Name behandelt }; template<class T> struct X<char, T> { X* p, q; // OK, X wird als Typname behandelt, äquivalent zu X<char, T> using r = X<int, int>; // OK, kann zur Benennung einer anderen Spezialisierung verwendet werden };
Der injizierte Klassenname einer Klassenvorlage oder einer Klassenvorlagenspezialisierung kann entweder als Vorlagenname oder als Typname verwendet werden, wo immer er im Gültigkeitsbereich ist.
template<> class X<int, char> { class B { X a; // bedeutet X<int, char> template<class, class> friend class X; // bedeutet ::X }; }; template<class T> struct Base { Base* p; // OK: Base bedeutet Base<T> }; template<class T> struct Derived : public Base<T*> { typename Derived::Base* p; // OK: Derived::Base bedeutet Derived<T>::Base, // was Base<T*> ist }; template<class T, template<class> class U = T::template Base> struct Third {}; Third<Derived<int>> t; // OK: Standardargument verwendet injizierten Klassennamen als Template
Eine Suche, die einen injizierten Klassennamen findet, kann in bestimmten Fällen zu einer Mehrdeutigkeit führen (zum Beispiel, wenn er in mehr als einer Basisklasse gefunden wird). Wenn alle gefundenen injizierten Klassennamen auf Spezialisierungen derselben Klassenvorlage verweisen und wenn der Name als Vorlagenname verwendet wird, bezieht sich die Referenz auf die Klassenvorlage selbst und nicht auf eine Spezialisierung davon und ist nicht mehrdeutig.
template<class T> struct Base {}; template<class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // Fehler: mehrdeutig typename Derived::Base<double> d; // OK };
Injected-Class-Name und Konstruktoren
Konstruktoren haben keine Namen, aber der injizierte Klassenname der umschließenden Klasse wird in Konstruktordeklarationen und -definitionen als Bezeichnung für einen Konstruktor betrachtet.
In einem qualifizierten Namen
C::D
, wenn
- Name Lookup ignoriert Funktionsnamen nicht, und
-
Lookup von
Dim Scope der KlasseCfindet deren injizierten Klassennamen
der qualifizierte Name wird stets als Bezeichnung für den Konstruktor von
C
betrachtet. Ein solcher Name kann nur in der Deklaration eines Konstruktors verwendet werden (z.B. in einer Friend-Konstruktordeklaration, einer Konstruktor-Templatespezialisierung, Konstruktor-Templateinstanziierung oder Konstruktordefinition)
oder zur Vererbung von Konstruktoren genutzt werden
(seit 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; // Fehler: A::A wird als Konstruktor betrachtet, nicht als Typ struct A::A a2; // OK, gleichbedeutend mit 'A a2;' B::A b; // OK, gleichbedeutend mit 'A b;'
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 1004 | C++98 |
ein injizierter Klassenname konnte nicht
als Template-Template-Argument verwendet werden |
erlaubt, es bezieht sich in diesem Fall auf das
Klassentemplate selbst |
| CWG 2637 | C++98 | die gesamte Template-ID konnte ein injizierter Klassenname sein | nur der Template-Name kann es sein |