2015-09-27 2 views
6

Von was ich verstehe, std::forward<T>(x) entspricht static_cast<T&&>(x).C++ std :: vorwärts <T> vs static_cast <T>

Aber von dem, was ich gesehen habe, scheint static_cast<T>(x) das Gleiche zu tun, wie in der folgenden code

Meine Frage ist also, warum std::forward<T> als static_cast<T&&>(x) implementiert zu sehen ist, und nicht static_cast<T>(x), wenn beide gleich haben bewirken?

+1

Sie haben nicht mit 'int &' versucht. – Quentin

+0

@Quentin In diesem Fall gibt es immer einen Lvalue zurück. – Mikrosaft

+0

'static_cast ' würde eine Kopie von rvalues ​​ –

Antwort

10

Da perfektes Forwarding erlaubt sowohl r-Wert Referenzen passieren undL-Wert Referenzen. Dies geschieht über reference collapsing getan:

T = int --> T&& = int&& 
T = int& --> T&& = int& && = int& 
T = int&& --> T&& = int&& && = int&& 

In Ihrem Beispiel mit static_cast<T> Sie einfach r-Wert Referenzen zu verlieren. Es funktioniert gut für primitive Typen (weil die Übergabe int normalerweise einen CPU-Registerwert kopiert), aber schrecklich für komplexe Typen, weil es dazu führt, temporäre Objekte durch Kopier-Ctors zu erzeugen.

+0

Ich habe es gerade überprüft, und es ist in der Tat ruft den Kopierkonstruktor für rvalue. Aber warum? Ich lese, dass, wenn wir func() mit einem rvalue aufrufen, T zu int && abgeleitet wird, so dass static_cast (x) static_cast wird (x). Warum also eine Kopie erstellt? – Mikrosaft

+2

'static_cast ' kann eine Referenz zurückgeben: Die obige Antwort impliziert, dass dies nicht möglich ist. Kannst du klarstellen, dass das Problem nur in einem "Fall" auftritt? – Yakk

+0

@Mikrosaft: nein, 'T' kann nicht zu' int && 'abgeleitet werden, es kann nur' int' oder 'int &' sein. – myaut

2

Wenn T&& eine rvalue Referenz, dann T ein Wert ist, dann static_cast<T> macht eine Kopie keine rvalue Referenz.

Diese Kopie wird an Rvalue-Referenzen (genau wie die Referenz) binden, aber kopieren/verschieben Ctors könnte unnötig aufgerufen werden, und es ist kein Kandidat für elision.

static_cast<T&&> wird in der Zwischenzeit nur auf einen R-Wert Referenz zu werfen.

Sie sind ansonsten identisch.

0

Ich stimme Yakk zu, aber es ist schlimmer als das.

void foo(const std::vector<int> &vec); 

template<typename T> 
void callFoo(T &&data) 
{ 
    foo(static_cast<T>(data)); 
} 

int main() 
{ 
    callFoo(std::vector<int>{/*...*/}); 
} 

Dies wird immer eine Kopie erstellen. Der Vektor ist nicht verschoben, weil data, als Ausdruck, ein Lvalue des Typs std::vector<int> ist, obwohl der ersetzte Typ std::vector<int>&& ist. Beachten Sie, dass Tstd::vector<int>, nicht std::vector<int> && ist. Moral der Geschichte: Verwenden Sie die Standard-Bibliothek, tut es das Richtige und der Name forward erfasst auch die Absicht weit besser als static_cast<something>.

Verwandte Themen