Ausdrücke
Ein Ausdruck ist eine Sequenz von Operatoren und ihren Operanden, die eine Berechnung spezifiziert.
Die Auswertung eines Ausdrucks kann ein Ergebnis liefern (z. B. liefert die Auswertung von 2 + 2 das Ergebnis 4) und Nebenwirkungen hervorrufen (z. B. druckt die Auswertung von std::printf("%d", 4) das Zeichen '4' auf der Standardausgabe).
Jeder C++-Ausdruck wird durch zwei unabhängige Eigenschaften charakterisiert: einen Typ und eine Wertkategorie.
Inhalt |
[bearbeiten] Allgemein
- Wertkategorien (lvalue, rvalue, glvalue, prvalue, xvalue(seit C++11)) klassifizieren Ausdrücke nach ihren Werten
- Auswertungsreihenfolge von Argumenten und Teilausdrücken spezifiziert die Reihenfolge, in der Zwischenergebnisse erzielt werden
[bearbeiten] Operatoren
| Häufige Operatoren | ||||||
|---|---|---|---|---|---|---|
| Zuweisung | Inkrement Dekrement |
Arithmetik | Logisch | Vergleich | Member Zugriff |
Sonstiges |
|
a = b |
++a |
+a |
!a |
a == b |
a[...] |
Funktionsaufruf a(...) |
| Komma a, b | ||||||
| Ternär a ? b : c | ||||||
| Spezielle Operatoren | ||||||
|
static_cast konvertiert einen Typ in einen anderen verwandten Typ | ||||||
- Operatorpriorität definiert die Reihenfolge, in der Operatoren an ihre Operanden gebunden werden
- alternative Darstellungen sind alternative Schreibweisen für einige Operatoren
- Operatorüberladung ermöglicht es, das Verhalten von Operatoren für benutzerdefinierte Klassen zu definieren.
[bearbeiten] Konvertierungen
- Standardkonvertierungen implizite Konvertierungen von einem Typ zu einem anderen
-
const_cast-Konvertierung -
static_cast-Konvertierung -
dynamic_cast-Konvertierung -
reinterpret_cast-Konvertierung - explizite Casts Konvertierung mittels C-Stil-Cast-Notation und Funktions-Notation
- benutzerdefinierte Konvertierung ermöglicht die Definition von Konvertierungen aus benutzerdefinierten Klassen
[bearbeiten] Speicherzuweisung
- new-Ausdruck weist Speicher dynamisch zu
- delete-Ausdruck gibt Speicher dynamisch frei
[bearbeiten] Sonstiges
- Konstante Ausdrücke können zur Kompilierzeit ausgewertet und im Kontext der Kompilierzeit verwendet werden (Template-Argumente, Array-Größen usw.)
-
sizeof -
alignof -
typeid - throw-Ausdruck
[bearbeiten] Primärausdrücke
Die Operanden eines jeden Operators können andere Ausdrücke oder Primärausdrücke sein (z. B. in 1 + 2 * 3 sind die Operanden von operator+ der Teilausdruck 2 * 3 und der Primärausdruck 1).
Primärausdrücke sind einer der folgenden
-
this - Literale (z. B. 2 oder "Hello, world")
- Bezeichner-Ausdrücke, einschließlich
- geeignet deklarierte unqualifizierte Bezeichner (z. B. n oder cout),
- geeignet deklarierte qualifizierte Bezeichner (z. B. std::string::npos), und
- Bezeichner, die in Deklaratoren deklariert werden sollen
| (seit C++26) |
| (seit C++11) | |
| (seit C++17) | |
| (seit C++20) |
Jeder Ausdruck in Klammern wird ebenfalls als Primärausdruck klassifiziert: Dies garantiert, dass die Klammern eine höhere Priorität als jeder Operator haben. Klammern erhalten Wert, Typ und Wertkategorie.
[bearbeiten] Literale
Literale sind die Token eines C++-Programms, die Konstanten Werte darstellen, die im Quellcode eingebettet sind.
- Ganzzahl-Literale sind dezimale, oktale, hexadezimale oder binäre Zahlen vom Ganzzahltyp.
- Zeichen-Literale sind einzelne Zeichen vom Typ
- char oder wchar_t
|
(seit C++11) |
|
(seit C++20) |
- Gleitkomma-Literale sind Werte vom Typ float, double oder long double
- Zeichenketten-Literale sind Zeichensequenzen vom Typ
- const char[] oder const wchar_t[]
|
(seit C++11) |
|
(seit C++20) |
- Boolesche Literale sind Werte vom Typ bool, nämlich true und false
|
(seit C++11) |
[bearbeiten] Vollständige Ausdrücke
Ein konstituierender Ausdruck wird wie folgt definiert
- Der konstituierende Ausdruck eines Ausdrucks ist dieser Ausdruck.
- Die konstituierenden Ausdrücke einer in geschweifte Klammern eingeschlossenen Initialisierungsliste oder einer (möglicherweise geklammerten) Auswahlliste sind die konstituierenden Ausdrücke der Elemente der jeweiligen Liste.
- Die konstituierenden Ausdrücke eines Initialisierers, der mit
=beginnt, sind die konstituierenden Ausdrücke der Initializer-Klausel.
int num1 = 0; num1 += 1; // Case 1: the constituent expression of “num += 1” is “num += 1” int arr2[2] = {2, 22} // Case 2: the constituent expressions // of “{2, 22}” are “2” and “22” // Case 3: the constituent expressions of “= {2, 22}” // are the constituent expressions of “{2, 22}” // (i.e. also “2” and “22”)
Die unmittelbaren Teilausdrücke eines Ausdrucks E sind
- die konstituierenden Ausdrücke von Es Operanden,
|
(seit C++14) |
|
(seit C++11) |
- jeder Funktionsaufruf, den E implizit aufruft, oder
- wenn E ein Funktionsaufruf ist oder implizit eine Funktion aufruft, die konstituierenden Ausdrücke jedes Standardarguments, das im Aufruf verwendet wird.
Ein Teilausdruck eines Ausdrucks E ist ein unmittelbarer Teilausdruck von E oder ein Teilausdruck eines unmittelbaren Teilausdrucks von E. Beachten Sie, dass Ausdrücke, die im „Funktionskörper“ von Lambda-Ausdrücken vorkommen, keine Teilausdrücke des Lambda-Ausdrucks sind.(seit C++11)
Die folgenden Ausdrücke sind vollständige Ausdrücke
| (seit C++20) |
- Deklaratoren von einfachen Deklarationen oder Member-Initialisierern, einschließlich der konstituierenden Ausdrücke der Initialisierer
- Aufrufe von Destruktoren, die am Ende der Lebensdauer von Objekten (außer temporären Objekten, deren Lebensdauer nicht verlängert wurde) erzeugt werden
|
(seit C++26) |
- Ausdrücke, die kein Teilausdruck eines anderen Ausdrucks sind und die nicht anderweitig Teil eines vollständigen Ausdrucks sind
Wenn eine Sprachkonstruktion definiert ist, einen impliziten Funktionsaufruf zu erzeugen, wird die Verwendung der Sprachkonstruktion für die Zwecke dieser Definition als Ausdruck betrachtet. Konvertierungen, die auf das Ergebnis eines Ausdrucks angewendet werden, um die Anforderungen der Sprachkonstruktion zu erfüllen, in der der Ausdruck vorkommt, gelten ebenfalls als Teil des vollständigen Ausdrucks.
Bei einem Initialisierer gilt die Durchführung der Initialisierung der Entität (einschließlich der Auswertung von Standard-Member-Initialisierern eines Aggregats)(seit C++14) ebenfalls als Teil des vollständigen Ausdrucks.
[bearbeiten] Potenziell ausgewertete Ausdrücke
|
Ein Ausdruck ist potenziell ausgewertet, es sei denn
|
(bis C++11) | ||
|
Die folgenden Operanden sind nicht ausgewertete Operanden, sie werden nicht ausgewertet
Ein Ausdruck ist potenziell ausgewertet, es sei denn
|
(seit C++11) |
Potenziell ausgewertete Ausdrücke sind ODR-use.
| Dieser Abschnitt ist unvollständig Grund: Beispiel für nicht ausgewertete Operanden |
[bearbeiten] Ausdrücke mit verworfenem Wert
Ein Ausdruck mit verworfenem Wert ist ein Ausdruck, der nur wegen seiner Nebenwirkungen verwendet wird. Der aus einem solchen Ausdruck berechnete Wert wird verworfen. Solche Ausdrücke umfassen den vollständigen Ausdruck jedes Ausdrucks-Statements, den linken Operanden des eingebauten Komma-Operators oder den Operanden eines Cast-Ausdrucks, der zu void castet.
Array-zu-Zeiger- und Funktions-zu-Zeiger-Konvertierungen werden niemals auf den von einem Ausdruck mit verworfenem Wert berechneten Wert angewendet. Die lvalue-zu-rvalue-Konvertierung wird genau dann angewendet, wenn der Ausdruck ein volatile-qualifizierter glvalue ist und eine der folgenden Formen hat (eingebaute Bedeutung erforderlich, möglicherweise geklammert)
- id-expression,
- Array-Subskript-Ausdruck,
- Klassen-Member-Zugriffs-Ausdruck,
- Indirektion,
- Zeiger-auf-Member-Operation,
- bedingter Ausdruck, bei dem sowohl der zweite als auch der dritte Operand einer dieser Ausdrücke sind,
- Komma-Ausdruck, bei dem der rechte Operand einer dieser Ausdrücke ist.
Zusätzlich ist, wenn das lvalue von einem volatile-qualifizierten Klassentyp ist, ein volatile-Kopierkonstruktor erforderlich, um das resultierende rvalue-Temporär-Objekt zu initialisieren.
|
Wenn der Ausdruck ein nicht-void prvalue ist (nach allen möglicherweise stattgefundenen lvalue-zu-rvalue-Konvertierungen), erfolgt eine temporäre Materialisierung. Compiler können Warnungen ausgeben, wenn ein Ausdruck (außer Cast zu void) einen als |
(seit C++17) |
Ausdrucks-ÄquivalenzEine Anzahl von Ausdrücken e1, e2, ..., eN sind ausdrucks-äquivalent, wenn alle folgenden Bedingungen erfüllt sind
e1 ist ausdrucks-äquivalent zu e2, wenn und nur wenn e1 und e2 ausdrucks-äquivalent sind (was bedeutet, dass e2 auch ausdrucks-äquivalent zu e1 ist). |
(seit C++20) |
[bearbeiten] Defect Reports
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 1054 | C++98 | Zuweisung eines Wertes an eine volatile Variable kann zu einer unnötigen Lesung führen aufgrund der lvalue-zu- rvalue-Konvertierung, die auf das Zuweisungsergebnis angewendet wird |
Ausdrücke mit verworfenem Wert einführen und diesen Fall aus der Liste ausschließen der Fälle, die die Konvertierung erfordern |
| CWG 1343 | C++98 | Die Sequenzierung von Destruktoraufrufen in der Aggregat-Initialisierung war nicht ausreichend spezifiziert |
Vollständige Ausdrücke in der Aggregat-Initialisierung sind gut spezifiziert |
| CWG 1383 | C++98 | Die Liste der Ausdrücke, bei denen die lvalue-zu-rvalue- Konvertierung auf Ausdrücke mit verworfenem Wert angewendet wird deckte auch überladene Operatoren ab |
nur Operatoren abdecken mit eingebauter Bedeutung |
| CWG 1576 | C++11 | lvalue-zu-rvalue-Konvertierungen wurden nicht angewendet auf volatile xvalue-Ausdrücke mit verworfenem Wert |
die Konvertierung anwenden in diesem Fall |
| CWG 2249 | C++98 | Bezeichner, die in Deklaratoren deklariert werden sollen waren keine id-expressions |
sie sind |
| CWG 2431 | C++11 | die Aufrufe der Destruktoren von Temporär-Objekten, die an Referenzen gebunden sind, waren keine vollständigen Ausdrücke |
sie sind |
[bearbeiten] Siehe auch
| C-Dokumentation für Ausdrücke
|