Identifiers
Ein Identifier ist eine beliebig lange Folge von Ziffern, Unterstrichen, lateinischen Klein- und Großbuchstaben sowie den meisten Unicode-Zeichen.
Das erste Zeichen eines gültigen Identifikators muss eines der folgenden sein:
- Großbuchstaben des lateinischen Alphabets A-Z
- Kleinbuchstaben des lateinischen Alphabets a-z
- Unterstrich
- jedes Unicode-Zeichen mit der Unicode-Eigenschaft XID_Start
Jedes andere Zeichen eines gültigen Bezeichners muss eines der folgenden sein:
- Ziffern 0-9
- lateinische Großbuchstaben A-Z
- lateinische Kleinbuchstaben a-z
- Unterstrich
- jedes Unicode-Zeichen mit der Unicode-Eigenschaft XID_Continue
Die Listen der Zeichen mit den Eigenschaften XID_Start und XID_Continue können in DerivedCoreProperties.txt gefunden werden.
Bezeichner sind case-sensitive (Klein- und Großbuchstaben werden unterschieden), und jedes Zeichen ist signifikant. Jeder Bezeichner muss Normalization Form C entsprechen.
Hinweis: Die Unterstützung von Unicode-Identifikatoren ist in den meisten Implementierungen eingeschränkt, z.B. gcc (bis Version 10) .
Inhaltsverzeichnis |
In Deklarationen
Ein Bezeichner kann verwendet werden um zu benennen Objekte, Referenzen, Funktionen, Enumeratoren, Typen, Klassenmitglieder, Namensräume, Templates, Templatespezialisierungen, Parameter Packs (since C++11) , goto-Labels und andere Entitäten, mit folgenden Ausnahmen:
- Die Bezeichner, die Schlüsselwörter sind, können nicht für andere Zwecke verwendet werden.
|
(seit C++11) |
- Die Bezeichner, die alternative Darstellungen für bestimmte Operatoren und Interpunktionszeichen sind, können nicht für andere Zwecke verwendet werden.
|
(seit C++11) |
-
Bezeichner
die als Token oder Präprozessor-Token auftreten (d.h. nicht in
user-defined-string-literal
wie
operator
""
id
)
(seit C++11)
in einer der folgenden Formen sind reserviert:
- im globalen Namensraum, Bezeichner die mit einem Unterstrich beginnen
- Bezeichner die einen doppelten Unterstrich enthalten oder mit einem Unterstrich gefolgt von einem Großbuchstaben beginnen, mit Ausnahme der folgenden Bezeichner:
-
-
- vordefinierte Makros (einschließlich Sprachfeature-Testmakros ) (seit C++20)
-
| (seit C++11) |
|
(seit C++11) |
| (seit C++20) |
„Reserviert“ bedeutet hier, dass die Standardbibliotheks-Header #define oder solche Bezeichner für ihre internen Anforderungen deklarieren, der Compiler möglicherweise nicht-normative Bezeichner dieser Art vordefiniert und dass der Name-Mangling-Algorithmus davon ausgehen kann, dass einige dieser Bezeichner nicht in Verwendung sind. Wenn der Programmierer solche Bezeichner verwendet, ist das Programm fehlerhaft, keine Diagnose erforderlich.
Zusätzlich ist es undefiniertes Verhalten, #define oder #undef für bestimmte Namen in einer Übersetzungseinheit zu verwenden. Weitere Details finden Sie unter reservierte Makronamen .
Zombie-Identifikatoren
Ab C++14 wurden einige Bezeichner aus der C++-Standardbibliothek entfernt. Sie sind in der Liste der Zombie-Namen aufgeführt.
Allerdings sind diese Bezeichner in einem bestimmten Kontext weiterhin für frühere Standardisierungen reserviert. Entfernte Member-Funktionsnamen dürfen nicht als Name für funktionsähnliche Makros verwendet werden, und andere entfernte Member-Namen dürfen nicht als Name für objektähnliche Makros in portablem Code verwendet werden.
In Ausdrücken
Ein Bezeichner, der eine Variable, eine Funktion, eine Spezialisierung eines Konzepts , (seit C++20) oder einen Enumerator benennt, kann als Ausdruck verwendet werden. Das Ergebnis eines Ausdrucks, der nur aus dem Bezeichner besteht, ist die durch den Bezeichner benannte Entität. Die Wertkategorie des Ausdrucks ist Lvalue , wenn der Bezeichner eine Funktion, eine Variable , ein Template-Parameter-Objekt (seit C++20) oder ein Datenelement benennt, und Rvalue (bis C++11) Prvalue (seit C++11) andernfalls (z.B. ist ein Enumerator ein Rvalue (bis C++11) ein Prvalue (seit C++11) -Ausdruck , eine Spezialisierung eines Konzepts ist ein boolescher Prvalue (seit C++20) ).
Typ
Der Typ eines Identifikatorausdrucks ist derselbe wie der Typ der Entität, die er benennt.
|
Folgende Ausnahmen existieren:
void f() { float x, &r = x; [=] { decltype(x) y1; // y1 has type float decltype((x)) y2 = y1; // y2 has type float const& because this lambda // is not mutable and x is an lvalue decltype(r) r1 = y1; // r1 has type float& decltype((r)) r2 = y2; // r2 has type float const& }; }
|
(seit C++11) |
Unqualifizierte Bezeichner
Neben entsprechend deklarierten Bezeichnern können folgende Elemente in Ausdrücken dieselbe Rolle übernehmen:
- ein überladener Operator in Funktionsnotation, wie operator + oder operator new ;
- ein benutzerdefinierter Konvertierungsoperator , wie operator bool ;
|
(seit C++11) |
- ein Template -Name gefolgt von seiner Argumentenliste, wie MyTemplate < int > ;
- das Zeichen ~ gefolgt von einem Klassennamen, wie ~MyClass ;
|
(seit C++11) |
|
(seit C++26) |
Zusammen mit Bezeichnern werden sie als unqualified identifier expressions bezeichnet.
Qualifizierte Bezeichner
Ein qualifizierter Identifikatorausdruck ist ein unqualifizierter Identifikatorausdruck, dem ein Bereichsauflösungsoperator :: vorangestellt ist, und optional eine Sequenz von beliebigen der folgenden, durch Bereichsauflösungsoperatoren getrennten Elementen:
- ein Namespace-Name;
- ein Klassenname;
|
(seit C++11) |
|
(seit C++26) |
Beispielsweise ist der Ausdruck std:: string :: npos ein Ausdruck, der das statische Mitglied npos in der Klasse string im Namensraum std benennt. Der Ausdruck :: tolower benennt die Funktion tolower im globalen Namensraum. Der Ausdruck :: std:: cout benennt die globale Variable cout im Namensraum std , welcher ein oberster Namensraum ist. Der Ausdruck boost :: signals2 :: connection benennt den Typ connection , der im Namensraum signals2 deklariert ist, welcher wiederum im Namensraum boost deklariert ist.
Das Schlüsselwort template kann in qualifizierten Identifikatoren erscheinen, wenn es notwendig ist, um abhängige Template-Namen zu disambiguieren.
Siehe qualified lookup für die Details der Namenssuche für qualifizierte Identifikatoren.
Implizite Member-Zugriffstransformation
Wenn ein Bezeichnerausdruck
E
ein nicht-statisches Datenelement einer Klasse
C
bezeichnet und alle folgenden Bedingungen erfüllt sind,
wird
E
in den Klassenmember-Zugriffsausdruck
this
-
>
E
transformiert:
- E ist nicht der rechte Operand eines Member-Zugriffsoperators .
- Wenn E ein qualifizierter Identifikatorausdruck ist, E nicht der ungeklammerte Operand eines Adressoperators ist.
- Eine der folgenden Bedingungen ist erfüllt:
-
- E wird potenziell ausgewertet .
-
Cist die innerste umschließende Klasse an E . -
Cist eine Basisklasse der innersten umschließenden Klasse an E .
Diese Transformation findet im Template-Definitionskontext keine Anwendung (siehe dependent names ).
struct X { int x; }; struct B { int b; }; struct D : B { X d; void func() { d; // OK, wird in this->d transformiert b; // OK, wird in this->b transformiert x; // Fehler: this->x ist ungültig d.x; // OK, wird in this->d.x transformiert // anstelle von d.this->x oder this->d.this->x } };
Namen
Ein name ist die Verwendung einer der folgenden Möglichkeiten, um sich auf eine Entität zu beziehen:
- ein Bezeichner
- ein überladener Operatorname in Funktionsschreibweise ( operator + , operator new )
- ein Name einer benutzerdefinierten Konvertierungsfunktion ( operator bool )
|
(seit C++11) |
- ein Template-Name gefolgt von seiner Argumentenliste ( MyTemplate < int > )
Jeder Name wird in das Programm durch eine Deklaration eingeführt. Ein Name, der in mehr als einer Übersetzungseinheit verwendet wird, kann sich auf dieselbe oder verschiedene Entitäten beziehen, abhängig von der Linkage .
Wenn der Compiler auf einen unbekannten Namen in einem Programm stößt, verknüpft er ihn mit der Deklaration, die den Namen mittels Namenssuche eingeführt hat, mit Ausnahme der dependent names in Template-Deklarationen und -Definitionen (für diese Namen bestimmt der Compiler, ob sie einen Typ, ein Template oder eine andere Entität bezeichnen, was explizite Disambiguierung erfordern kann).
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 1440 | C++11 |
decltype-Ausdrücke vor
::
konnten jeden Typ bezeichnen
|
können nur Klassen-
oder Aufzählungstypen bezeichnen |
| CWG 1963 | C++11 |
implementierungsdefinierte Zeichen außer Ziffern, Nicht-Ziffern
und universellen Zeichennamen konnten in einem Bezeichner verwendet werden |
verboten |
| CWG 2521 | C++11 |
der Bezeichner in
user-defined-string-literal
eines
Literaloperators war wie üblich reserviert |
die Regeln sind unterschiedlich |
| CWG 2771 | C++98 | & a wurde nicht in & this - > a in Klassenkontexten transformiert | wird transformiert |
| CWG 2777 | C++20 |
der Typ eines Identifikatorausdrucks war unklar,
wenn er ein Template-Parameterobjekt benennt |
klargestellt |
| CWG 2818 | C++98 | vordefinierte Makronamen sind reserviert | sie sind nicht reserviert |
Siehe auch
|
C-Dokumentation
für
Identifiers
|