Die Implementierung von std::forward
Bin ich beim Lesen Überblick über die Neue C++ (C++11/14) (nur PDF), mit Folie 288 es gibt eine Implementierung von std::forward
:
template<typename T> //For lvalues (T is T&),
T&& std::forward(T&& param) //take/return lvalue refs.
{ //For rvalues (T is T),
return static_cast<T&&>(param); //take/return rvalue refs.
}
... Und gibt dann anderen die Implementierung im text:
Den üblichen std::forward-Implementierung:
template<typename T>
struct identity {
typedef T type;
};
template<typename T>
T&& forward(typename identity<T>::type&& param)
{ return static_cast<identity<T>::type&&>(param); }
Was ist der Unterschied? Warum ist letzteres der üblichen Umsetzung?
- Im ersten Fall, Sie bekommen konnte Weg mit
std::forward(x)
, aber in der zweiten, müssen Sie explizit den template-Parameter, da Sie nicht entnommen werden kann. - Nein, tun Sie nicht. Warum wäre das notwendig? Referenz einstürzenden arbeiten außerhalb des unmittelbaren Weiterleitung Referenzrahmen.
- verpasst, es ist Identität, nicht remove_reference
- Du hast Recht, lvalues müssen akzeptiert werden. Allerdings rvalues nicht benötigen, so ist die Lösung nicht eine zweite überladung, die Lösung ist immer eine lvalue-Referenz in der einen, die da ist.
- Stellt sich heraus, ich bin falsch, der standard erfordert rvalues akzeptiert zu werden.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Das problem mit dem ersten ist, dass Sie schreiben können
std::forward(x)
, die nicht tun, was Sie wollen, da es immer eine lvalue-Referenzen.Das argument im zweiten Fall ist eine nicht-abgeleitet Kontext, verhindern der automatischen Abzug der template-argument. Dies zwingt Sie zu schreiben
std::forward<T>(x)
, welche ist die richtige Sache zu tun.Auch, das argument-Typ für die zweite überladung sollte
typename identity<T>::type&
weil der Eingang zur idiomatischen Verwendung vonstd::forward
ist immer ein lvalue.Edit: Der standard tatsächlich Mandate eine Signatur entspricht (die, nebenbei bemerkt, ist genau das, was die libc++ hat):
return static_cast<T &&>(param);
?static_cast<T&&>(param)
ist entweder ein move oder nach vorne, je nachdem, ob T ist eine Universelle Referenz. Die utility-Funktionen hilft der Lesbarkeit und der Vermeidung ungewollter Bewegungen.Die Implementierung in der libc++ verwendet
std::remove_reference
und zwei überladungen. Hier ist die Quelle (nach entfernen der Makros):aber beachten Sie, dass in C++14,
std::forward
istconstexpr
.Ersten Fall als Sebastian Redl sagte immer geben Sie eine lvalue-Referenz. Der Grund dafür ist, dass eine rvalue-Referenz im parameter übergeben werden würde, als eine lvalue-Referenz und parameter -
T&&
Typ ist ein universal-Referenz eher als eine rvalue-Referenz.Eigentlich, wenn der erste Fall ist richtig, wir brauchen noch nicht einmal
forward
mehr. Hier ist ein experiment, um zu demonstrieren, wie universal-Referenz-Parameter übergeben werdenDas Programm stellt sich heraus, dass beide
t
undu
bestanden ausf
zug
ist lvalue Referenzen, trotz, dassu
ist eine rvalue-Referenz inf
. Also im ersten Fall werden die parameter vonforward
einfach nicht haben eine chance auf eine rvalue-Referenz.Den
identity
zum ändern der parameter-Typ von universal Verweis auf eine rvalue Referenz (wie erwähnt von Redl, es ist präziser zu benutzenstd::remove_reference
). Aber diese änderung ist die Vorlage geben Abzug nicht mehr möglich, so dass der Typ-parameter fürforward
ist zwingend erforderlich, da ein Ergebnis, das wir schreiben sollforward<T>(t)
.Aber der zweite Fall in Ihre Frage ist nicht korrekt, wie auch erwähnt Redl, der richtige Ansatz ist eine überlastung, deren parameter ist ein lvalue-Referenz.
Die einfachste Implementierung, die ich finden kann, ist diese
Er arbeitet für universal-Referenzen, zum Beispiel