rvalue - lvalue
-
Hi
Schon wieder eine Frage zu meinem Buch. Dieses mal bringen mich die rValues und lValues durcheinander.
Hier ein Programm, womit ich herumprobiere:
#include <iostream> #include <type_traits> class Foo { public: Foo() { } Foo(const Foo& src) { std::cout << "Kopierkonstruktor" << std::endl; } Foo(Foo&& src) { std::cout << "Verschiebekonstruktor" << std::endl; } }; template <class T> T* Clone(const T& src) { std::cout << "Clone" << std::endl; std::cout << "r value reference" << std::is_rvalue_reference<T>::value << std::endl; std::cout << "r value reference" << std::is_rvalue_reference<T&>::value << std::endl; std::cout << "r value reference" << std::is_rvalue_reference<T&&>::value << std::endl; std::cout << "l value reference" << std::is_lvalue_reference<T>::value << std::endl; std::cout << "l value reference" << std::is_lvalue_reference<T&>::value << std::endl; std::cout << "l value reference" << std::is_lvalue_reference<T&&>::value << std::endl; return new T(src); } int main(int argc, char *argv[]) { Foo foo1; Foo* foo2 = Clone(foo1); Foo* foo3 = Clone(std::move(*foo2)); return 0; }
Und das ist die Ausgabe:
Clone
r value reference0
r value reference0
r value reference1
l value reference0
l value reference1
l value reference0
Kopierkonstruktor
Clone
r value reference0
r value reference0
r value reference1
l value reference0
l value reference1
l value reference0
KopierkonstruktorHier gibts noch 2 Seltsamkeiten, wobei ich momentan aber nur ein interessiert.
Und zwar die Ausgaben in der Clone-Funktion. T ist scheinbar einerseits ein rvalue T&&, andererseits ein lvalue T&.
Wie kann denn etwas gleichzeitig ein rvalue und ein lvalue sein?
-
Nein, T& ist ein lvalue und T&& ein rvalue.
-
r- und lvalues sind Wertkategorien, die mit dem Typ des Ausdrucks (also was du bekommst wenn du
decltype
darauf anwendest) fast nichts zu tun haben.Eine rvalue-Referenz ist eine Referenz.
is_rvalue_reference
testet einfach, ob das Template-Argument eine rvalue-Referenz ist. Hier sindT
,T&
,T&&
drei verschiedene Typen - das zweite ist hier eine lvalue-Referenz, das dritte eine rvalue-Referenz.Wenn du einen Typ mit && qualifizierst, machst du aus ihm eine rvalue-Referenz (außer T ist selbst eine Referenz, dann greifen die reference-collapsing Regeln).
Und hängst du an den Typ ein &, machst du aus ihm eine lvalue-Referenz (ist der Typ selber eine Referenz, dann wird dasconst
entfernt).Nathan schrieb:
Nein, T& ist ein lvalue und T&& ein rvalue.
T& ist eine rvalue**-Referenz**, das ist ein Typ.
-
Arcoth schrieb:
Nathan schrieb:
Nein, T& ist ein lvalue und T&& ein rvalue.
T& ist eine rvalue**-Referenz**, das ist ein Typ.
Ich weiß.
Ich wollte ihn lediglich darauf aufmerksam machen, dass das nicht T ist, sonder T& bzw. T&&, die laut Ausgabe l/rvalues sind.
-
Nehmen wir mal die Zeilen 30, 31, 17 und 19 her:
30: Foo foo1;
31: Foo* foo2 = Clone(foo1);
17: T* Clone(const T& src) {
19: std::cout << "r value reference" << std::is_rvalue_reference<T>::value << std::endl;Was habe ich denn in diesen Zeilen?
In 30 ist foo1 ein lvalue, richtig?
In 31 wird dieser lvalue übergeben.
Was habe ich jetzt in Zeile 17? Was ist T&? Eine lvalue-reference?
Und was habe ich dann in Zeile 19 beim T?
-
In 30 ist foo1 ein lvalue, richtig?
Richtig. Der Ausdruck
foo1
ist ein lvalue.In 31 wird dieser lvalue übergeben.
Jo.
Was habe ich jetzt in Zeile 17? Was ist T&? Eine lvalue-reference?
Korrekt.
Und was habe ich dann in Zeile 19 beim T?
Ein T.
Diese Tautologie soll klar stellen, dassT
einfach der deduzierte Typ ist, in diesem FallFoo
. Er ist keine rvalue-Referenz.
-
Aber was ist das T dann in der Zeile 19? Ein lvalue?
EDIT:
Ich finde leider keine C++-Funktion is_lvalue oder is_rvalue
http://en.cppreference.com/w/cpp/types/is_reference habe ich jetzt gefunden. Referenz ist es keine, das habe ich schon gecheckt.
-
tröröö schrieb:
Aber was ist das T dann in der Zeile 19? Ein lvalue?
Gar nichts. T ist ein Typ. Bloss weil es Ausdruecke gibt, die den Typ einer rvalue-Referenz (oder lvalue-Referenz) haben, macht das den Typen selber noch nicht zum rvalue/lvalue. Die Begriffe rvalue und lvalue beziehen sich immer auf Ausdruecke, nicht auf Typen.
Typen sind so Sachen wie
int
,double
,string
, usw.Ausdruecke sind so Sachen wie
2 + 3
,"Hallo Welt"
,cos(x)
,cout << foo(7)
,i++
, usw.EDIT:
Ich finde leider keine C++-Funktion is_lvalue oder is_rvalue
http://en.cppreference.com/w/cpp/types/is_reference habe ich jetzt gefunden. Referenz ist es keine, das habe ich schon gecheckt.Kann es aufgrund obiger Erklaerung auch nicht geben.
-
Kann es aufgrund obiger Erklaerung auch nicht geben.
template<typename T> bool is_rvalue( T&& ) { return true; } template<typename T> bool is_rvalue( T& ) { return false; }
?
Alle drei Wertkategorien - lvalues, xvalues und prvalues - werden eindeutig von einer Funktion angenommen (keine Ambiguitäten).
-
Ich hatte gedacht, dass der TE etwas meint, das, so wie std::is_reference, auf einer Typangabe operiert.
-
SeppJ schrieb:
Ich hatte gedacht, dass der TE etwas meint, das, so wie std::is_reference, auf einer Typangabe operiert.
Nein, das ist offensichtlich unmöglich.
Lässt sich übrigens reduzieren:auto is_rvalue = [] (auto&& p) { return std::is_rvalue_reference<decltype(p)>::value; };