Declarations
Deklarationen sind die Art und Weise, wie Namen in das C++-Programm eingeführt (oder wieder eingeführt) werden. Nicht alle Deklarationen deklarieren tatsächlich etwas, und jede Art von Entität wird unterschiedlich deklariert. Definitionen sind Deklarationen, die ausreichen, um die durch den Namen identifizierte Entität zu verwenden.
Eine Deklaration ist eines der folgenden Elemente:
- Funktionsdefinition
- Template-Deklaration (einschließlich Partielle Template-Spezialisierung )
- Explizite Template-Instanziierung
- Explizite Template-Spezialisierung
- Namespace-Definition
- Linkage-Spezifikation
|
(seit C++11) |
-
Leere Deklaration (
;) - Eine Funktionsdeklaration ohne decl-specifier-seq :
attr
(optional)
declarator
;
|
|||||||||
| attr | - | (since C++11) Folge beliebig vieler attributes |
| declarator | - | ein Funktionsdeklarator |
- Diese Deklaration muss einen Konstruktor, Destruktor oder eine benutzerdefinierte Konvertierungsfunktion deklarieren. Sie kann nur als Teil einer Template-Deklaration , expliziten Spezialisierung oder expliziten Instanziierung verwendet werden.
- block-declaration (eine Deklaration, die innerhalb eines Blocks erscheinen kann), die wiederum eine der folgenden sein kann:
| (seit C++11) |
| (seit C++20) | |
|
(seit C++11) |
-
- einfache Deklaration
Inhaltsverzeichnis |
Einfache Deklaration
Eine einfache Deklaration ist eine Anweisung, die einen oder mehrere Bezeichner, typischerweise Variablen, einführt, erstellt und optional initialisiert.
decl-specifier-seq
init-declarator-list
(optional)
;
|
(1) | ||||||||
attr
decl-specifier-seq
init-declarator-list
;
|
(2) | (seit C++11) | |||||||
| decl-specifier-seq | - | Folge von Spezifizierern |
| init-declarator-list | - | kommagetrennte Liste von init-declarator s (siehe unten) |
| attr | - | Folge beliebig vieler Attribute |
init-declarator-list
kann nur beim Deklarieren einer benannten Klasse oder einer benannten Enumeration weggelassen werden.
|
Eine strukturierte Bindungsdeklaration ist ebenfalls eine einfache Deklaration. |
(seit C++17) |
Die Syntax von
init-declarator
ist wie folgt definiert:
| declarator initializer | (1) | ||||||||
| declarator requires-clause (optional) contract-specs (optional) | (2) | ||||||||
| declarator | - | ein Deklarator |
| initializer | - | ein Initialisierer |
| requires-clause | - | (since C++20) eine requires -Klausel |
| contract-specs | - | (since C++26) eine Liste von Funktionsvertragsspezifizierern |
|
requires-clause darf nur erscheinen, wenn der declarator eine templated function deklariert. |
(since C++20) |
|
contract-specs dürfen nur erscheinen, wenn der declarator eine Funktion oder Funktionsvorlage deklariert. |
(since C++26) |
Spezifizierer
Deklarationsspezifizierer ( decl-specifier-seq ) ist eine Sequenz der folgenden, durch Leerzeichen getrennten Spezifizierer in beliebiger Reihenfolge:
-
der
typedef-Spezifizierer. Falls vorhanden, ist die gesamte Deklaration eine Typdeklaration und jeder Deklarator führt einen neuen Typnamen ein, kein Objekt oder eine Funktion. -
Funktionsspezifizierer (
inline,virtual,explicit), nur erlaubt in Funktionsdeklarationen .
|
(seit C++17) |
-
der
friendSpezifizierer, erlaubt in Klassen- und Funktionsdeklarationen.
|
(seit C++11) |
|
(seit C++20) |
- Speicherklassenspezifizierer ( register , (bis C++17) static , thread_local , (seit C++11) extern , mutable ). Nur ein Speicherklassenspezifizierer ist erlaubt , außer dass thread_local zusammen mit extern oder static auftreten darf (seit C++11) .
- Typspezifizierer ( type-specifier-seq ), eine Sequenz von Spezifizierern, die einen Typ benennt. Der Typ jeder durch die Deklaration eingeführten Entität ist dieser Typ, optional modifiziert durch den Deklarator (siehe unten). Diese Sequenz von Spezifizierern wird auch von type-id verwendet. Nur die folgenden Spezifizierer sind Teil von type-specifier-seq , in beliebiger Reihenfolge:
-
- Klassenspezifizierer
- Aufzählungsspezifizierer
- Einfacher Typspezifizierer
| (seit C++11) | |
| (seit C++26) |
-
-
- zuvor deklarierter Klassenname (optional qualifiziert )
- zuvor deklarierter Enum-Name (optional qualifiziert )
- zuvor deklarierter typedef-name oder type alias (seit C++11) (optional qualifiziert )
- Template-Name mit Template-Argumenten (optional qualifiziert , optional unter Verwendung des template disambiguator )
-
|
(seit C++17) |
-
-
- das Schlüsselwort class , struct , oder union , gefolgt vom Bezeichner (optional qualifiziert ), der zuvor als Name einer Klasse definiert wurde.
- das Schlüsselwort class , struct , oder union , gefolgt vom Template-Namen mit Template-Argumenten (optional qualifiziert , optional unter Verwendung des template Disambiguators ), der zuvor als Name eines Klassentemplates definiert wurde.
- das Schlüsselwort enum gefolgt vom Bezeichner (optional qualifiziert ), der zuvor als Name einer Enumeration deklariert wurde.
-
-
nur ein Typ-Spezifizierer ist in einer decl-specifier-seq erlaubt, mit folgenden Ausnahmen:
- const kann mit jedem Typ-Spezifizierer kombiniert werden, außer mit sich selbst.
- volatile kann mit jedem Typ-Spezifizierer kombiniert werden, außer mit sich selbst.
- signed oder unsigned kann kombiniert werden mit char , long , short , oder int .
- short oder long kann kombiniert werden mit int .
- long kann kombiniert werden mit double .
|
(seit C++11) |
Attribute können in decl-specifier-seq erscheinen, in welchem Fall sie auf den durch die vorhergehenden Spezifizierer bestimmten Typ angewendet werden.
Wiederholungen jeglicher Spezifizierer in einer decl-specifier-seq , wie const static const oder virtual inline virtual sind Fehler , außer dass long zweimal auftreten darf (seit C++11) .
Deklaratoren
Jeder init-declarator in einer init-declarator-list S D1, D2, D3 ; wird so verarbeitet, als wäre es eine eigenständige Deklaration mit denselben Spezifizierern: S D1 ; S D2 ; S D3 ; .
Jeder Deklarator führt genau ein Objekt, eine Referenz, eine Funktion oder (für typedef-Deklarationen) einen Typalias ein, dessen Typ durch die decl-specifier-seq bereitgestellt und optional durch Operatoren wie & (Referenz auf) oder [ ] (Array von) oder ( ) (Funktion zurückgebend) im Deklarator modifiziert wird. Diese Operatoren können rekursiv angewendet werden, wie unten gezeigt.
Ein Deklarator ist einer der folgenden:
| unqualified-id attr (optional) | (1) | ||||||||
| qualified-id attr (optional) | (2) | ||||||||
...
identifier
attr
(optional)
|
(3) | (seit C++11) | |||||||
*
attr
(optional)
cv
(optional)
declarator
|
(4) | ||||||||
nested-name-specifier
*
attr
(optional)
cv
(optional)
declarator
|
(5) | ||||||||
&
attr
(optional)
declarator
|
(6) | ||||||||
&&
attr
(optional)
declarator
|
(7) | (seit C++11) | |||||||
noptr-declarator
[
constant-expression
(optional)
]
attr
(optional)
|
(8) | ||||||||
noptr-declarator
(
parameter-list
)
cv
(optional)
ref
(optional)
except
(optional)
attr
(optional)
|
(9) | ||||||||
(
declarator
)
|
(10) | ||||||||
D
als einen Zeiger auf den durch
Deklarator-Spezifizierer-Sequenz
S
bestimmten Typ.
D
als einen Zeiger auf ein Mitglied von
C
vom Typ, bestimmt durch
Deklarationsspezifizierer-Sequenz
S
.
Verschachtelter-Namen-Spezifizierer
ist eine
Sequenz von Namen und Bereichsauflösungsoperatoren
::
D
als eine Lvalue-Referenz auf den durch
decl-specifier-seq
S
bestimmten Typ.
D
als eine Rvalue-Referenz auf den durch
Deklarator-Spezifizierer-Sequenz
S
bestimmten Typ.
|
In allen Fällen ist attr eine optionale Folge von Attributen . Wenn es unmittelbar nach dem Bezeichner erscheint, gilt es für das deklarierte Objekt. |
(since C++11) |
cv ist eine Sequenz von const- und volatile Qualifizierern, wobei jeder Qualifizierer höchstens einmal in der Sequenz vorkommen darf.
|
Dieser Abschnitt ist unvollständig
Grund: Erklären Sie die Regeln zur Deklarationsnamen-Verschattung; wie eine Variablen-/Funktionsdeklaration eine Klasse (aber nicht einen typedef) mit demselben Namen verdeckt |
Hinweise
Wenn eine block-declaration innerhalb eines Blocks erscheint und ein durch eine Deklaration eingeführter Bezeichner zuvor in einem äußeren Block deklariert wurde, wird die äußere Deklaration für den Rest des Blocks verborgen.
Wenn eine Deklaration eine Variable mit automatischer Speicherdauer einführt, wird sie initialisiert, wenn ihre Deklarationsanweisung ausgeführt wird. Alle automatischen Variablen, die in einem Block deklariert werden, werden beim Verlassen des Blocks zerstört (unabhängig davon, wie der Block verlassen wird: via exception , goto , oder durch Erreichen seines Endes), in umgekehrter Reihenfolge ihrer Initialisierung.
Beispiel
Hinweis: Dieses Beispiel demonstriert, wie einige komplexe Deklarationen gemäß der Sprachgrammatik geparst werden. Andere bekannte Merkhilfen sind: die Spiralregel , das Lesen von innen nach außen , und Deklaration spiegelt Verwendung . Es gibt auch einen automatisierten Parser unter https://cdecl.org .
#include <type_traits> struct S { int member; // decl-specifier-seq is "int" // declarator is "member" { obj, *pObj(&obj); // decl-specifier-seq is "struct S { int member; }" // declarator "obj" declares an object of type S // declarator "*pObj" declares a pointer to S, // and initializer "(&obj)" initializes it int i = 1, *p = nullptr, f(), (*pf)(double); // decl-specifier-seq is "int" // declarator "i" declares a variable of type int, // and initializer "= 1" initializes it // declarator "*p" declares a variable of type int*, // and initializer "= nullptr" initializes it // declarator "f()" declares (but doesn't define) // a function taking no arguments and returning int // declarator "(*pf)(double)" declares a pointer to function // taking double and returning int int (*(*var1)(double))[3] = nullptr; // decl-specifier-seq is "int" // declarator is "(*(*var1)(double))[3]" // initializer is "= nullptr" // 1. declarator "(*(*var1)(double))[3]" is an array declarator: // Type declared is: "(*(*var1)(double))" array of 3 elements // 2. declarator "(*(*var1)(double))" is a pointer declarator: // Type declared is: "(*var1)(double)" pointer to array of 3 elements // 3. declarator "(*var1)(double)" is a function declarator: // Type declared is: "(*var1)" function taking "(double)", // returning pointer to array of 3 elements. // 4. declarator "(*var1)" is a pointer declarator: // Type declared is: "var1" pointer to function taking "(double)", // returning pointer to array of 3 elements. // 5. declarator "var1" is an identifier. // This declaration declares the object var1 of type "pointer to function // taking double and returning pointer to array of 3 elements of type int" // The initializer "= nullptr" provides the initial value of this pointer. // C++11 alternative syntax: auto (*var2)(double) -> int (*)[3] = nullptr; // decl-specifier-seq is "auto" // declarator is "(*var2)(double) -> int (*)[3]" // initializer is "= nullptr" // 1. declarator "(*var2)(double) -> int (*)[3]" is a function declarator: // Type declared is: "(*var2)" function taking "(double)", returning "int (*)[3]" // ... int main() { static_assert(std::is_same_v<decltype(var1), decltype(var2)>); }
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 482 | C++98 | die Deklaratoren von Neudeklarationen konnten nicht qualifiziert werden | qualifizierte Deklaratoren erlaubt |
| CWG 569 | C++98 | ein einzelnes eigenständiges Semikolon war keine gültige Deklaration |
es ist eine leere Deklaration,
die keine Wirkung hat |
| CWG 1830 | C++98 | Wiederholung eines Funktionsspezifizierers in einer decl-specifier-seq war erlaubt | Wiederholung ist verboten |
Siehe auch
|
C-Dokumentation
für
Deklarationen
|