C ++ 0x zeigt ein Beispiel für die Verwendung von std::forward
:
template<class T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
Wann ist es immer vorteilhaft zu verwenden std::forward
?
Außerdem muss es &&
in der Parameterdeklaration verwendet werden. Ist es in allen Fällen gültig? Ich dachte, Sie &&
müssten temporäre Funktionen an eine Funktion übergeben, wenn die Funktion darin deklariert wurde. Kann foo also mit einem beliebigen Parameter aufgerufen werden?
Zum Schluss, wenn ich einen Funktionsaufruf wie diesen habe:
template<int val, typename... Params>
void doSomething(Params... args) {
doSomethingElse<val, Params...>(args...);
}
Soll ich das stattdessen verwenden:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}
Wenn Sie die Parameter zweimal in der Funktion verwenden, dh gleichzeitig an zwei Funktionen weiterleiten, ist es sinnvoll, sie zu verwenden std::forward
? std::forward
Konvertieren Sie dasselbe nicht zweimal in ein temporäres Element, verschieben Sie den Speicher und machen Sie ihn für eine zweite Verwendung ungültig? Wäre der folgende Code in Ordnung:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}
Ich bin ein bisschen verwirrt von std::forward
und würde gerne etwas aufräumen.
quelle
Args...&& args
?Kerreks Antwort ist sehr nützlich, beantwortet aber die Frage aus dem Titel nicht vollständig:
Um dies zu beantworten, sollten wir zunächst einen Begriff universeller Referenzen einführen . Scott Meyers gab diesen Namen und heutzutage werden sie oft als Weiterleitungsreferenzen bezeichnet. Grundsätzlich, wenn Sie so etwas sehen:
Denken Sie daran, dass dies
param
keine Wertreferenz ist (wie man zu dem Schluss kommen könnte), sondern eine universelle Referenz *. Universelle Referenzen zeichnen sich durch eine sehr eingeschränkte Form (nurT&&
ohne const oder ähnliche Qualifikationsmerkmale) und durch Typabzug aus - der TypT
wird beimf
Aufrufen abgeleitet. Kurz gesagt, universelle Referenzen entsprechen r-Wert-Referenzen, wenn sie mit r-Werten initialisiert wurden, und l-Wert-Referenzen, wenn sie mit l-Werten initialisiert wurden.Jetzt ist es relativ einfach, die ursprüngliche Frage zu beantworten - bewerben Sie sich
std::forward
bei:Ein Beispiel für den ersten Fall:
Im obigen Code möchten wir
prop
nach Abschluss keinen unbekannten Wert mehrother.set(..)
haben, daher erfolgt hier keine Weiterleitung. Wennbar
wir jedoch anrufen , leiten wir weiter , sobaldprop
wir damit fertig sind, undbar
können damit machen, was immer wir wollen (z. B. bewegen).Ein Beispiel für den zweiten Fall:
Diese Funktionsvorlage sollte
prop
in den Rückgabewert verschoben werden, wenn es sich um einen r-Wert handelt, und in den Rückgabewert kopiert werden, wenn es sich um einen l-Wert handelt. Falls wirstd::forward
am Ende weggelassen haben , würden wir immer eine Kopie erstellen, was teurer ist, wennprop
es sich um einen Wert handelt.* Um genau zu sein, ist eine universelle Referenz ein Konzept, bei dem eine r-Wert-Referenz auf einen cv-nicht qualifizierten Vorlagenparameter verwendet wird.
quelle
Hilft dieses Beispiel? Ich hatte Mühe, ein nützliches, nicht generisches Beispiel für std :: forward zu finden, stieß jedoch auf ein Beispiel für ein Bankkonto, das wir als Argument für die Einzahlung weitergeben.
Wenn wir also eine const-Version eines Kontos haben, sollten wir erwarten, dass die const-Funktion aufgerufen wird, wenn wir sie an unsere Einzahlungsvorlage <> übergeben. und dies löst dann eine Ausnahme aus (die Idee war, dass dies ein gesperrter Account war!)
Wenn wir ein nicht konstantes Konto haben, sollten wir das Konto ändern können.
Bauen:
Erwartete Ausgabe:
quelle