0

Kürzlich habe ich versucht, move Semantik zu verstehen und kam mit einer Frage.Unterschied zwischen std :: forward implementation

Die Frage wurde bereits diskutiert here.

implementiert ich die erste Variante und geprüft, ob es l-Wert oder r-Wert zurückgibt:

#include <iostream> 
using namespace std; 

template <typename T> 
T&& my_forward(T&& x) { 
    return static_cast<T&&> (x); 
} 

int main() { 
    int a = 5; 
    &my_forward(a); // l-value 
    return 0; 
} 

Also, wenn ich l-Wert übergeben, gibt sie l-Wert (compiliert, weil ich nehmen kann eine Adresse von l-Wert), und wenn ich das tun:

&my_forward(int(5)); // r-value with int&& type 

Mein Code kompiliert nicht, weil my_forward r-Wert zurückgegeben. In der obigen Frage sagen sie, dass der Unterschied zwischen dieser Implementierung und Standart (mit std :: remove_reference und 2 verschiedenen Argumenten mit & und & &) ist, dass meine Implementierung den l-Wert die ganze Zeit zurückgibt, aber wie ich gezeigt habe es gibt sowohl den r-Wert als auch den l-Wert zurück.

Also frage ich mich, warum kann ich nicht std :: forward wie das implementieren? In welchen konkreten Fällen wird es einen Unterschied zwischen den Standardfällen geben? Warum sollte ich T auch als Vorlage angeben und darf es sich nicht mit einem Argumenttyp definieren lassen?

+0

Warum sind Sie Adresse von rvalue Bezug zu nehmen versuchen? – xinaiz

+0

@BlackMoses Um die r-Wertigkeit zu überprüfen. – LogicStuff

+0

@LogicStuff Ah, okay, dachte, es war ein Missverständnis von '&' Verwendung :) – xinaiz

Antwort

3

Versuchen Sie es wie STD vorwärts in einem echten Kontext. Deines funktioniert nicht;

void test(std::vector<int>&&){} 

template<class T> 
void foo(T&&t){ 
    test(my_forward<T>(t)); 
} 

foo(std::vector<int>{}); 

Das obige wird nicht kompiliert. Es tut mit std::forward.

Ihr Weiterleiten macht nichts nützliches, außer der Referenzlebensdauerverlängerung. Unterdessen ist std::forward eine bedingte std::move.

Alles mit einem Namen ist ein L-Wert, aber vorwärts bewegt R-Wert-Referenzen mit Namen.

Rvalue-Referenzen mit Namen sind lvalues.

+0

Vielen Dank! Ich habe es mit diesem [code] (http://ideone.com/XPePam) überprüft und es scheint, dass ich falsch lag. Ich habe es nicht in einem realen Kontext überprüft, weil ich (teoretisch) dachte, dass diese Implementierungen die gleichen wären. Ich kann nicht wirklich verstehen, was der Unterschied ist. Kannst du es erklären? – fminkin

+0

Und warum funktioniert meine Implementierung genau so? Wie wir in dem Thema gesehen haben, gibt es r-Wert zurück, warum funktioniert es dann nicht? – fminkin

+0

** Rvalue Referenzen mit Namen sind lvalues. ** Bis Sie verstehen, dass Sie verwirrt bleiben. – Yakk

1

Leider ist die Adresse unter in Ihrem Kontext nicht eine nützliche Operation, weil es an der falschen Art von Wertkategorie aussieht:

  • Sie die Adresse eines glvalue nehmen können, aber nicht von einem prvalue . Ein gl-Wert repräsentiert einen "Ort" (d. H. Wo ein Objekt ist), ein pr-Wert repräsentiert "Initialisierung" (d. H. Welchen Wert ein Objekt hat).

  • Sie können Ressourcen aus einem R-Wert, aber nicht aus einem L-Wert stehlen. Lvalue-Referenzen binden an lvalues, rvalue-Referenzen an rvalues. Der Punkt besteht darin, ein Argument in einen rvalue zu übergeben, wenn ein rvalue angegeben wurde, und auf einen lvalue, wenn ein lvalue angegeben wurde.

Wenn std::forward einen R-Wert zurückgibt, es gibt tatsächlich eine xValue und XValues ​​sind beide rvalues ​​und glvalues:

    lvalue  f() for "T& f();", decltype(f()) is T& 
       /
      glvalue 
     /  \ 
    value    xvalue  f() for "T&& f();", decltype(f()) is T&& 
     \  /
      rvalue 
        \ 
        prvalue  f() for "T f();", decltype(f()) is T 
+0

Ich denke du meintest. "Sie können Ressourcen aus einem R-Wert stehlen, aber NICHT aus einem L-Wert." – Lenz

+0

@Lenz: Hab ich, danke :-) –

Verwandte Themen