Namespaces
Variants

Injected-class-name

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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:

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 D im Scope der Klasse C findet 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