Value categories
Jeder C++ Ausdruck (ein Operator mit seinen Operanden, ein Literal, ein Variablenname, etc.) ist durch zwei unabhängige Eigenschaften charakterisiert: einen Typ und eine Wertkategorie . Jeder Ausdruck hat einen bestimmten Nicht-Referenz-Typ, und jeder Ausdruck gehört zu genau einer der drei primären Wertkategorien: prvalue , xvalue , und lvalue .
- ein glvalue („generalisierter“ lvalue) ist ein Ausdruck, dessen Auswertung die Identität eines Objekts oder einer Funktion bestimmt;
- ein prvalue („reiner“ rvalue) ist ein Ausdruck, dessen Auswertung
-
- berechnet den Wert eines Operanden eines eingebauten Operators (ein solcher Prvalue hat kein Ergebnisobjekt ), oder
- initialisiert ein Objekt (ein solcher Prvalue wird als mit einem Ergebnisobjekt bezeichnet).
-
Das Ergebnisobjekt kann eine Variable, ein durch
new-expression
erzeugtes Objekt, ein durch
temporary materialization
erzeugtes Temporärobjekt oder ein Mitglied davon sein. Beachten Sie, dass nicht-
void
discarded
Ausdrücke ein Ergebnisobjekt haben (das materialisierte Temporärobjekt). Außerdem hat jeder Klassen- und Array-Prvalue ein Ergebnisobjekt, außer wenn er der Operand von
decltypeist;
- ein xvalue (ein "eXpiring"-Wert) ist ein Glvalue, das ein Objekt bezeichnet, dessen Ressourcen wiederverwendet werden können;
- ein lvalue ist ein Glvalue, das kein xvalue ist;
| Erweiterter Inhalt |
|---|
|
Historisch so genannt, weil lvalues auf der linken Seite eines Zuweisungsausdrucks erscheinen konnten. Im Allgemeinen trifft dies nicht immer zu: void foo(); void baz() { int a; // Expression `a` is lvalue a = 4; // OK, could appear on the left-hand side of an assignment expression int &b{a}; // Expression `b` is lvalue b = 5; // OK, could appear on the left-hand side of an assignment expression const int &c{a}; // Expression `c` is lvalue c = 6; // ill-formed, assignment of read-only reference // Expression `foo` is lvalue // address may be taken by built-in address-of operator void (*p)() = &foo; foo = baz; // ill-formed, assignment of function } |
- ein rvalue ist ein prvalue oder ein xvalue;
| Erweiterter Inhalt |
|---|
|
Historisch so genannt, weil rvalues auf der rechten Seite einer Zuweisung erscheinen konnten. Im Allgemeinen trifft dies jedoch nicht immer zu:
Code ausführen
#include <iostream> struct S { S() : m{42} {} S(int a) : m{a} {} int m; }; int main() { S s; // Expression `S{}` is prvalue // May appear on the right-hand side of an assignment expression s = S{}; std::cout << s.m << '\n'; // Expression `S{}` is prvalue // Can be used on the left-hand side too std::cout << (S{} = S{7}).m << '\n'; } Ausgabe: 42 7 |
Hinweis: Diese Taxonomie durchlief erhebliche Änderungen mit früheren C++-Standardrevisionen, siehe Verlauf unten für Details.
| Erweiterter Inhalt |
|---|
|
Trotz ihrer Namen klassifizieren diese Begriffe Ausdrücke, nicht Werte.
Diesen Code ausführen
#include <type_traits> #include <utility> template <class T> struct is_prvalue : std::true_type {}; template <class T> struct is_prvalue<T&> : std::false_type {}; template <class T> struct is_prvalue<T&&> : std::false_type {}; template <class T> struct is_lvalue : std::false_type {}; template <class T> struct is_lvalue<T&> : std::true_type {}; template <class T> struct is_lvalue<T&&> : std::false_type {}; template <class T> struct is_xvalue : std::false_type {}; template <class T> struct is_xvalue<T&> : std::false_type {}; template <class T> struct is_xvalue<T&&> : std::true_type {}; int main() { int a{42}; int& b{a}; int&& r{std::move(a)}; // Expression `42` is prvalue static_assert(is_prvalue<decltype((42))>::value); // Expression `a` is lvalue static_assert(is_lvalue<decltype((a))>::value); // Expression `b` is lvalue static_assert(is_lvalue<decltype((b))>::value); // Expression `std::move(a)` is xvalue static_assert(is_xvalue<decltype((std::move(a)))>::value); // Type of variable `r` is rvalue reference static_assert(std::is_rvalue_reference<decltype(r)>::value); // Type of variable `b` is lvalue reference static_assert(std::is_lvalue_reference<decltype(b)>::value); // Expression `r` is lvalue static_assert(is_lvalue<decltype((r))>::value); } |
Inhaltsverzeichnis |
Hauptkategorien
lvalue
Die folgenden Ausdrücke sind lvalue expressions :
- der Name einer Variable, einer Funktion , eines Template-Parameter-Objekts (seit C++20) oder eines Datenelements, unabhängig vom Typ, wie z.B. std:: cin oder std:: hex . Selbst wenn der Typ der Variable eine Rvalue-Referenz ist, ist der Ausdruck, der aus ihrem Namen besteht, ein Lvalue-Ausdruck (siehe jedoch Move-eligible expressions );
| Erweiterter Inhalt |
|---|
void foo() {} void baz() { // `foo` ist ein Lvalue // Adresse kann durch eingebauten Adressoperator genommen werden void (*p)() = &foo; } struct foo {}; template <foo a> void baz() { const foo* obj = &a; // `a` ist ein Lvalue, Template-Parameter-Objekt } |
- Ein Funktionsaufruf oder ein überladener Operatorausdruck, dessen Rückgabetyp ein Lvalue-Referenz ist, wie z.B. std:: getline ( std:: cin , str ) , std:: cout << 1 , str1 = str2 , oder ++ it ;
| Erweiterter Inhalt |
|---|
int& a_ref() { static int a{3}; return a; } void foo() { a_ref() = 5; // `a_ref()` ist ein Lvalue, Funktionsaufruf dessen Rückgabetyp eine Lvalue-Referenz ist } |
- a = b , a + = b , a % = b und alle anderen integrierten Zuweisungs- und zusammengesetzten Zuweisungsausdrücke ;
- ++ a und -- a , die integrierten Prä-Inkrement- und Prä-Dekrement-Ausdrücke ;
- * p , der integrierte Dereferenzierungsausdruck ;
- a [ n ] und p [ n ] , die integrierten Indexausdrücke , wobei ein Operand in a [ n ] ein Array-Lvalue ist (seit C++11) ;
-
a.
m
, der
Objektmitgliedzugriffsausdruck
, außer wenn
mein Mitgliedsenumerator oder eine nicht-statische Memberfunktion ist, oder wenn a ein Rvalue ist undmein nicht-statisches Datenelement vom Objekttyp ist;
| Erweiterter Inhalt |
|---|
struct foo { enum bar { m // member enumerator }; }; void baz() { foo a; a.m = 42; // ill-formed, lvalue required as left operand of assignment } struct foo { void m() {} // non-static member function }; void baz() { foo a; // `a.m` is a prvalue, hence the address cannot be taken by built-in // address-of operator void (foo::*p1)() = &a.m; // ill-formed void (foo::*p2)() = &foo::m; // OK: pointer to member function } struct foo { static void m() {} // static member function }; void baz() { foo a; void (*p1)() = &a.m; // `a.m` is an lvalue void (*p2)() = &foo::m; // the same } |
-
p
-
>
m
, der eingebaute
Member-von-Zeiger-Ausdruck
, außer wenn
mein Member-Enumerator oder eine nicht-statische Member-Funktion ist; -
a.
*
mp
, der
Zeiger-auf-Member-von-Objekt-Ausdruck
, wobei
a
ein Lvalue und
mpein Zeiger auf Datenmember ist; -
p
-
>
*
mp
, der eingebaute
Zeiger-auf-Member-von-Zeiger-Ausdruck
, wobei
mpein Zeiger auf Datenmember ist; - a, b , der eingebaute Komma-Ausdruck , wobei b ein Lvalue ist;
- a ? b : c , der ternäre bedingte Ausdruck für bestimmte b und c (z.B. wenn beide Lvalues desselben Typs sind, siehe jedoch Definition für Details);
- ein String-Literal , wie "Hello, world!" ;
- ein Cast-Ausdruck in Lvalue-Referenztyp, wie static_cast < int & > ( x ) oder static_cast < void ( & ) ( int ) > ( x ) ;
- ein konstanter Template-Parameter eines Lvalue-Referenztyps;
template <int& v> void set() { v = 5; // Template-Parameter ist Lvalue } int a{3}; // Statische Variable, feste Adresse ist zur Compilezeit bekannt void foo() { set<a>(); }
|
(seit C++11) |
Eigenschaften:
- Gleich wie glvalue (unten).
- Die Adresse eines lvalue kann mit dem eingebauten Adressoperator genommen werden: & ++ i [1] und & std:: hex sind gültige Ausdrücke.
- Ein modifizierbares lvalue kann als linker Operand der eingebauten Zuweisungs- und zusammengesetzten Zuweisungsoperatoren verwendet werden.
- Ein lvalue kann verwendet werden, um eine lvalue-Referenz zu initialisieren ; dies assoziiert einen neuen Namen mit dem durch den Ausdruck identifizierten Objekt.
prvalue
Die folgenden Ausdrücke sind prvalue-Ausdrücke :
- ein Literal (außer String-Literal ), wie 42 , true oder nullptr ;
- ein Funktionsaufruf oder ein überladener Operatorausdruck, dessen Rückgabetyp keine Referenz ist, wie str. substr ( 1 , 2 ) , str1 + str2 , oder it ++ ;
- a ++ und a -- , die eingebauten Postinkrement- und Postdekrement-Ausdrücke ;
- a + b , a % b , a & b , a << b , und alle anderen eingebauten arithmetischen Ausdrücke;
- a && b , a || b , ! a , die eingebauten logischen Ausdrücke;
- a < b , a == b , a >= b , und alle anderen eingebauten Vergleichs- Ausdrücke;
- & a , der eingebaute Adressoperator ;
-
a.
m
, der
Elementzugriffsausdruck für Objekte
, wobei
mein Enumerator oder eine nicht-statische Elementfunktion ist [2] ; -
p
-
>
m
, der eingebaute
Elementzugriffsausdruck für Zeiger
, wobei
mein Enumerator oder eine nicht-statische Elementfunktion ist [2] ; -
a.
*
mp
, der
Zeiger-auf-Element-Ausdruck für Objekte
, wobei
mpein Zeiger auf eine Elementfunktion ist [2] ; -
p
-
>
*
mp
, der eingebaute
Zeiger-auf-Element-Ausdruck für Zeiger
, wobei
mpein Zeiger auf eine Elementfunktion ist [2] ; - a, b , der eingebaute Kommaoperator , wobei b ein prvalue ist;
- a ? b : c , der bedingte ternäre Operator für bestimmte b und c (siehe Definition für Details);
- ein Cast-Ausdruck in einen Nicht-Referenztyp, wie static_cast < double > ( x ) , std:: string { } , oder ( int ) 42 ;
-
der
this-Zeiger; - ein Enumerator ;
- ein konstanter Template-Parameter eines skalaren Typs;
template <int v> void foo() { // kein Lvalue, `v` ist ein Template-Parameter vom skalaren Typ int const int* a = &v; // ungültig v = 3; // ungültig: Lvalue erforderlich als linker Operand der Zuweisung }
|
(seit C++11) |
|
(seit C++20) |
Eigenschaften:
- Gleich wie rvalue (unten).
- Ein prvalue kann nicht polymorph sein: Der dynamische Typ des bezeichneten Objekts entspricht immer dem Typ des Ausdrucks.
- Ein prvalue ohne Klassen- oder Array-Typ kann nicht cv-qualifiziert sein , es sei denn, es wird materialisiert , um an eine Referenz auf einen cv-qualifizierten Typ gebunden zu werden (seit C++17) . (Hinweis: Ein Funktionsaufruf oder eine Typumwandlung kann einen prvalue eines nicht-klassen cv-qualifizierten Typs ergeben, aber die CV-Qualifizierung wird in der Regel sofort entfernt.)
-
Ein prvalue kann keinen
unvollständigen Typ
haben (außer vom Typ
void
, siehe unten, oder bei Verwendung in einem
decltype-Spezifizierer). - Ein prvalue kann keinen abstrakten Klassentyp oder ein Array davon haben.
xvalue
Die folgenden Ausdrücke sind xvalue-Ausdrücke :
-
a.
m
, der
Member-of-Object-Ausdruck
, wobei
a
ein R-Wert und
mein nicht-statisches Datenelement eines Objekttyps ist; -
a.
*
mp
, der
Pointer-to-Member-of-Object-Ausdruck
, wobei
a
ein R-Wert und
mpein Zeiger auf ein Datenelement ist; - a, b , der eingebaute Komma-Operator , wobei b ein X-Wert ist;
- a ? b : c , der ternäre Bedingungsoperator für bestimmte b und c (siehe Definition für Details);
|
(seit C++11) |
|
(seit C++17) |
|
(seit C++23) |
Eigenschaften:
- Gleich wie Rvalue (unten).
- Gleich wie Glvalue (unten).
Insbesondere binden, wie alle R-Werte, X-Werte an R-Wert-Referenzen, und wie alle GL-Werte können X-Werte polymorph sein, und nicht-Klasse-X-Werte können CV-qualifiziert sein.
| Erweiterter Inhalt |
|---|
|
Code ausführen
#include <type_traits> template <class T> struct is_prvalue : std::true_type {}; template <class T> struct is_prvalue<T&> : std::false_type {}; template <class T> struct is_prvalue<T&&> : std::false_type {}; template <class T> struct is_lvalue : std::false_type {}; template <class T> struct is_lvalue<T&> : std::true_type {}; template <class T> struct is_lvalue<T&&> : std::false_type {}; template <class T> struct is_xvalue : std::false_type {}; template <class T> struct is_xvalue<T&> : std::false_type {}; template <class T> struct is_xvalue<T&&> : std::true_type {}; // Beispiel aus C++23 Standard: 7.2.1 Wertkategorie [basic.lval] struct A { int m; }; A&& operator+(A, A); A&& f(); int main() { A a; A&& ar = static_cast<A&&>(a); // Funktionsaufruf mit Rückgabetyp Rvalue-Referenz ist Xvalue static_assert(is_xvalue<decltype( (f()) )>::value); // Member eines Objektausdrucks, Objekt ist Xvalue, `m` ist ein nicht-statisches Datenelement static_assert(is_xvalue<decltype( (f().m) )>::value); // Ein Cast-Ausdruck zu Rvalue-Referenz static_assert(is_xvalue<decltype( (static_cast<A&&>(a)) )>::value); // Operatorausdruck, dessen Rückgabetyp Rvalue-Referenz auf Objekt ist static_assert(is_xvalue<decltype( (a + a) )>::value); // Ausdruck `ar` ist Lvalue, `&ar` ist gültig static_assert(is_lvalue<decltype( (ar) )>::value); [[maybe_unused]] A* ap = &ar; } |
Gemischte Kategorien
glvalue
Ein glvalue-Ausdruck ist entweder ein lvalue oder ein xvalue.
Eigenschaften:
- Ein glvalue kann implizit in einen prvalue mittels Lvalue-zu-Rvalue-, Array-zu-Zeiger- oder Funktion-zu-Zeiger- impliziter Konvertierung umgewandelt werden.
- Ein glvalue kann polymorph sein: Der dynamische Typ des Objekts, das es identifiziert, entspricht nicht notwendigerweise dem statischen Typ des Ausdrucks.
- Ein glvalue kann, sofern durch den Ausdruck erlaubt, einen unvollständigen Typ haben.
rvalue
Ein rvalue-Ausdruck ist entweder ein prvalue oder ein xvalue.
Eigenschaften:
- Die Adresse eines R-Werts kann nicht mit dem eingebauten Adressoperator genommen werden: & int ( ) , & i ++ [3] , & 42 und & std :: move ( x ) sind ungültig.
- Ein R-Wert kann nicht als linker Operand der eingebauten Zuweisungs- oder zusammengesetzten Zuweisungsoperatoren verwendet werden.
- Ein R-Wert kann verwendet werden, um eine konstante L-Wert-Referenz zu initialisieren , wobei die Lebensdauer des durch den R-Wert identifizierten temporären Objekts verlängert wird , bis der Gültigkeitsbereich der Referenz endet.
|
(seit C++11) |
Spezielle Kategorien
Ausstehender Member-Funktionsaufruf
Die Ausdrücke
a.
mf
und
p
-
>
mf
, wobei
mf
eine
nicht-statische Memberfunktion
ist, sowie die Ausdrücke
a.
*
pmf
und
p
-
>
*
pmf
, wobei
pmf
ein
Zeiger auf Memberfunktion
ist, werden als Prvalue-Ausdrücke klassifiziert. Sie können jedoch nicht zur Initialisierung von Referenzen, als Funktionsargumente oder für jegliche anderen Zwecke verwendet werden, außer als linkes Argument des Funktionsaufrufoperators, z.B.
(
p
-
>
*
pmf
)
(
args
)
.
Void-Ausdrücke
Funktionsaufrufausdrücke, die void zurückgeben, Cast-Ausdrücke zu void und Throw-Ausdrücke werden als Prvalue-Ausdrücke klassifiziert, können jedoch nicht zur Initialisierung von Referenzen oder als Funktionsargumente verwendet werden. Sie können in verworfenen Wertkontexten verwendet werden (z.B. in einer eigenen Zeile, als linke Operanden des Kommaoperators usw.) und in der return -Anweisung einer Funktion, die void zurückgibt. Zusätzlich können Throw-Ausdrücke als zweite und dritte Operanden des bedingten Operators ?: verwendet werden.
|
Void-Ausdrücke haben kein Ergebnisobjekt . |
(since C++17) |
Bitfelder
Ein Ausdruck, der ein Bit-Feld bezeichnet (z.B. a. m , wobei a ein L-Wert vom Typ struct A { int m : 3 ; } ist) ist ein Glvalue-Ausdruck: Er kann als linker Operand des Zuweisungsoperators verwendet werden, aber seine Adresse kann nicht genommen werden und eine nicht-konstante Lvalue-Referenz kann nicht daran gebunden werden. Eine konstante Lvalue-Referenz oder Rvalue-Referenz kann von einem Bit-Feld-Glvalue initialisiert werden, jedoch wird eine temporäre Kopie des Bit-Felds erstellt: Sie bindet nicht direkt an das Bit-Feld.
Move-eligible AusdrückeObwohl ein Ausdruck, der aus dem Namen einer beliebigen Variable besteht, ein Lvalue-Ausdruck ist, kann ein solcher Ausdruck move-eligible sein, wenn er als Operand erscheint von Wenn ein Ausdruck move-eligible ist, wird er für den Zweck der Überladungsauflösung behandelt entweder als Rvalue oder als Lvalue (bis C++23) als Rvalue (seit C++23) (daher kann er den Move-Konstruktor auswählen). Siehe Automatisches Verschieben von lokalen Variablen und Parametern für Details. |
(seit C++11) |
Geschichte
CPL
Die Programmiersprache CPL führte als erste Wertkategorien für Ausdrücke ein: Alle CPL-Ausdrücke können im "rechten Modus" ausgewertet werden, aber nur bestimmte Arten von Ausdrücken sind im "linken Modus" sinnvoll. Bei der Auswertung im rechten Modus wird ein Ausdruck als Regel zur Berechnung eines Werts betrachtet (der rechte Wert, oder rvalue ). Bei der Auswertung im linken Modus liefert ein Ausdruck effektiv eine Adresse (der linke Wert, oder lvalue ). "Links" und "Rechts" standen hier für "links der Zuweisung" und "rechts der Zuweisung".
C
Die Programmiersprache C folgte einer ähnlichen Taxonomie, mit der Ausnahme, dass die Rolle der Zuweisung nicht mehr signifikant war: C-Ausdrücke werden zwischen "Lvalue-Ausdrücken" und anderen (Funktionen und Nicht-Objekt-Werten) kategorisiert, wobei "Lvalue" einen Ausdruck bedeutet, der ein Objekt identifiziert, einen "Locator Value" [4] .
C++98
Pre-2011 C++ folgte dem C-Modell, stellte jedoch den Namen "Rvalue" für Nicht-Lvalue-Ausdrücke wieder her, machte Funktionen zu Lvalues und fügte die Regel hinzu, dass Referenzen an Lvalues gebunden werden können, aber nur Referenzen auf const an Rvalues gebunden werden können. Mehrere Nicht-Lvalue-C-Ausdrücke wurden in C++ zu Lvalue-Ausdrücken.
C++11
Mit der Einführung von Move-Semantik in C++11 wurden Wertkategorien neu definiert, um zwei unabhängige Eigenschaften von Ausdrücken zu charakterisieren [5] :
- hat Identität : es ist möglich zu bestimmen, ob der Ausdruck auf dieselbe Entität verweist wie ein anderer Ausdruck, beispielsweise durch Vergleich der Adressen der Objekte oder der Funktionen, auf die sie verweisen (direkt oder indirekt erhalten);
- kann verschoben werden : Move-Konstruktor , Move-Zuweisungsoperator , oder eine andere Funktionsüberladung, die Move-Semantik implementiert, kann an den Ausdruck gebunden werden.
In C++11, Ausdrücke, die:
- Identität besitzen und nicht verschoben werden können, werden lvalue -Ausdrücke genannt;
- Identität besitzen und verschoben werden können, werden xvalue -Ausdrücke genannt;
- keine Identität besitzen und verschoben werden können, werden prvalue ("pure rvalue")-Ausdrücke genannt;
- keine Identität besitzen und nicht verschoben werden können, werden nicht verwendet [6] .
Ausdrücke, die Identität besitzen, werden "glvalue-Ausdrücke" genannt (glvalue steht für "generalized lvalue"). Sowohl Lvalues als auch Xvalues sind glvalue-Ausdrücke.
Die Ausdrücke, von denen verschoben werden kann, werden "Rvalue-Ausdrücke" genannt. Sowohl Prvalues als auch Xvalues sind Rvalue-Ausdrücke.
C++17
In C++17 wurde Copy Elision in einigen Situationen verbindlich, was die Trennung von Prvalue-Ausdrücken von den durch sie initialisierten temporären Objekten erforderte, was zu dem heute vorhandenen System führte. Beachten Sie, dass im Gegensatz zum C++11-Schema Prvalues nicht mehr verschoben werden.
Fußnoten
- ↑ Unter der Annahme, dass i einen eingebauten Typ hat oder der Prä-Inkrement-Operator überladen ist, um eine Lvalue-Referenz zurückzugeben.
- ↑ 2.0 2.1 2.2 2.3 Spezielle Rvalue-Kategorie, siehe ausstehender Member-Funktionsaufruf .
- ↑ Unter der Annahme, dass i einen eingebauten Typ hat oder der Post-Inkrement-Operator nicht überladen ist, um eine Lvalue-Referenz zurückzugeben.
- ↑ "Eine Meinungsverschiedenheit innerhalb der C-Community drehte sich um die Bedeutung von Lvalue: Eine Gruppe betrachtete ein Lvalue als jede Art von Objektlokator, während eine andere Gruppe der Ansicht war, dass ein Lvalue auf der linken Seite eines Zuweisungsoperators bedeutungsvoll sei. Das C89-Komitee übernahm die Definition von Lvalue als Objektlokator." -- ANSI C Rationale, 6.3.2.1/10.
- ↑ "Neue" Wert-Terminologie von Bjarne Stroustrup, 2010.
-
↑
const-Prvalues (nur für Klassentypen erlaubt) und const-Xvalues binden nicht an
T&&Überladungen, aber sie binden an die const T && Überladungen, die ebenfalls vom Standard als "Move-Konstruktor" und "Move-Zuweisungsoperator" klassifiziert werden und damit die Definition von "kann verschoben werden" für diese Klassifikation erfüllen. Allerdings können solche Überladungen ihre Argumente nicht modifizieren und werden in der Praxis nicht verwendet; in deren Abwesenheit binden const-Prvalues und const-Xvalues an const T & Überladungen.
Referenzen
- C++23-Standard (ISO/IEC 14882:2024):
-
- 7.2.1 Wertkategorie [basic.lval]
- C++20-Standard (ISO/IEC 14882:2020):
-
- 7.2.1 Wertkategorie [basic.lval]
- C++17-Standard (ISO/IEC 14882:2017):
-
- 6.10 Lvalues und Rvalues [basic.lval]
- C++14-Standard (ISO/IEC 14882:2014):
-
- 3.10 Lvalues und Rvalues [basic.lval]
- C++11-Standard (ISO/IEC 14882:2011):
-
- 3.10 Lvalues und Rvalues [basic.lval]
- C++98-Standard (ISO/IEC 14882:1998):
-
- 3.10 Lvalues und Rvalues [basic.lval]
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 616 | C++11 |
Member-Zugriff und Member-Zugriff durch
Zeiger auf Member eines Rvalue ergab Prvalue |
neu klassifiziert als Xvalue |
| CWG 1059 | C++11 | Array-Prvalues konnten nicht cv-qualifiziert werden | erlaubt |
| CWG 1213 | C++11 | Indexierung eines Array-Rvalue ergab Lvalue | neu klassifiziert als Xvalue |
Siehe auch
|
C-Dokumentation
für
Wertkategorien
|
Externe Links
| 1. | C++ Wertkategorien und decltype entschlüsselt — David Mazières, 2021 | |
| 2. |
Wertkategorie eines Ausdrucks empirisch bestimmen
— StackOverflow
|