Namensräume
Varianten
Aktionen

Injected-class-name

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

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:

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 D im Geltungsbereich der Klasse C ihren 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