Injected-class-name
Der eingefügte Klassenname ist der unqualifizierte Name einer Klasse innerhalb des Geltungsbereichs dieser Klasse.
In einer Klassenvorlage kann der eingefügte Klassenname entweder als Vorlagennamen verwendet werden, der sich auf die aktuelle Vorlage bezieht, oder als Klassenname, der sich auf die aktuelle Instanziierung bezieht.
Inhalt |
[bearbeiten] Erklärung
Im Klassengeltungsbereich werden der Klassenname der aktuellen Klasse oder der Vorlagennamen der aktuellen Klassenvorlage behandelt, als wären sie öffentliche Member-Namen; dies wird als eingefügter Klassenname bezeichnet. Der Deklarationspunkt des Namens liegt unmittelbar nach der öffnenden geschweiften Klammer der Klassen- (oder Vorlagen-) Definition.
int X; struct X { void f() { X* p; // OK, X is an injected-class-name ::X* q; // Error: name lookup finds a variable name, which hides the struct name } }; template<class T> struct Y { void g() { Y* p; // OK, Y is an injected-class-name Y<T>* q; // OK, Y is an injected-class-name, but Y<T> is not } };
Wie andere Member werden eingefügte Klassennamen vererbt. Bei privater oder geschützter Vererbung kann der eingefügte Klassenname einer indirekten Basisklasse in einer abgeleiteten Klasse unzugänglich werden.
struct A {}; struct B : private A {}; struct C : public B { A* p; // Error: injected-class-name A is inaccessible ::A* q; // OK, does not use the injected-class-name };
[bearbeiten] In Klassenvorlagen
Der eingefügte Klassenname einer Klassenvorlage kann als Vorlagennamen oder als Typnamen verwendet werden.
In den folgenden Fällen wird der eingefügte Klassenname als Vorlagennamen der Klassenvorlage selbst behandelt:
- Er wird von
<gefolgt. - Er wird als Vorlagen-Vorlagenargument verwendet.
- Er ist der letzte Bezeichner in der elaborierten Klassenspezifikation einer Deklaration einer Freundschaftsklassenvorlage.
Andernfalls wird er als Typnamen behandelt und ist gleichbedeutend mit dem Vorlagennamen, gefolgt von den Vorlagenparametern der Klassenvorlage, eingeschlossen in <>.
template<template<class, class> class> struct A; template<class T1, class T2> struct X { X<T1, T2>* p; // OK, X is treated as a template-name using a = A<X>; // OK, X is treated as a template-name template<class U1, class U2> friend class X; // OK, X is treated as a template-name X* q; // OK, X is treated as a type-name, equivalent to X<T1, T2> };
Innerhalb des Geltungsbereichs einer Klassenvorlagenspezialisierung oder partiellen Spezialisierung ist der eingefügte Klassenname, wenn er als Typnamen verwendet wird, gleichbedeutend mit dem Vorlagennamen, gefolgt von den Vorlagenargumenten der Klassenvorlagenspezialisierung oder partiellen Spezialisierung, eingeschlossen in <>.
template<> struct X<void, void> { X* p; // OK, X is treated as a type-name, equivalent to X<void, void> template<class, class> friend class X; // OK, X is treated as a template-name (same as in primary template) X<void, void>* q; // OK, X is treated as a template-name }; template<class T> struct X<char, T> { X* p, q; // OK, X is treated as a type-name, equivalent to X<char, T> using r = X<int, int>; // OK, can be used to name another specialization };
Der eingefügte Klassenname einer Klassenvorlage oder Klassenvorlagenspezialisierung kann als Vorlagennamen oder als Typnamen verwendet werden, wo immer er im Geltungsbereich ist.
template<> class X<int, char> { class B { X a; // meaning X<int, char> template<class, class> friend class X; // meaning ::X }; }; template<class T> struct Base { Base* p; // OK: Base means Base<T> }; template<class T> struct Derived : public Base<T*> { typename Derived::Base* p; // OK: Derived::Base means Derived<T>::Base, // which is Base<T*> }; template<class T, template<class> class U = T::template Base> struct Third {}; Third<Derived<int>> t; // OK: default argument uses injected-class-name as a template
Eine Suche, die einen eingefügten Klassennamen findet, kann in bestimmten Fällen zu einer Mehrdeutigkeit führen (z. B. wenn er in mehr als einer Basisklasse gefunden wird). Wenn alle gefundenen eingefügten Klassennamen sich auf Spezialisierungen derselben Klassenvorlage beziehen und wenn der Name als Vorlagennamen verwendet wird, bezieht sich die Referenz auf die Klassenvorlage selbst und nicht auf eine ihrer Spezialisierungen, und ist nicht mehrdeutig.
template<class T> struct Base {}; template<class T> struct Derived: Base<int>, Base<char> { typename Derived::Base b; // error: ambiguous typename Derived::Base<double> d; // OK };
[bearbeiten] Eingefügter-Klassenname und Konstruktoren
Konstruktoren haben keine Namen, aber der eingefügte Klassenname der umschließenden Klasse gilt als Benennung eines Konstruktors in Konstruktor-Deklarationen und -Definitionen.
In einem qualifizierten Namen C::D, wenn
- die Namenssuche Funktionsnamen nicht ignoriert und
- die Suche nach
Dim Geltungsbereich der KlasseCihren eingefügten Klassennamen findet
wird der qualifizierte Name immer als Benennung des Konstruktors von C betrachtet. Ein solcher Name kann nur in der Deklaration eines Konstruktors (z. B. in einer Freundschaftskonstruktor-Deklaration, einer Konstruktor-Vorlagenspezialisierung, einer Konstruktor-Vorlageninstanziierung oder einer Konstruktor-Definition) verwendet werden oder zum Vererben von Konstruktoren verwendet 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; // Error: A::A is considered to name a constructor, not a type struct A::A a2; // OK, same as 'A a2;' B::A b; // OK, same as 'A b;'
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 1004 | C++98 | Ein eingefügter Klassenname konnte nicht als Vorlagen-Vorlagenargument dienen |
zugelassen werden, er bezieht sich in diesem Fall auf die Klassenvorlage selbst selbst |
| CWG 2637 | C++98 | Das gesamte Template-ID konnte ein eingefügter Klassenname sein | nur der Vorlagenname kann |