2016-11-26 3 views
17

Die Unterscheidung zwischen rvalue Referenzen und Spedition Referenzen wurde von Scott Meyers in diesem Beispiel deutlich genug gemacht:Ist dies eine Weiterleitungsreferenz?

Widget&& var1 = someWidget;  // here, “&&” means rvalue reference (1) 

auto&& var2 = var1;    // here, “&&” does not mean rvalue reference (2) 

template<typename T> 
void f(std::vector<T>&& param); // here, “&&” means rvalue reference (3) 

template<typename T> 
void f(T&& param);    // here, “&&”does not mean rvalue reference (4) 

Im Wesentlichen geschieht die Unterscheidung, wenn wir einen ableitbar Kontext haben, daher Fall (3) heißt es ausdrücklich, dass wir habe eine vector<...>&& wobei die T im Fall (4) abzuleiten ist und (nach Anwendung der Referenz-Kollabierungsregeln) in "Wertkategorie" kategorisiert wird.

Aber was passiert mit einem etwas komplexeren Mustervergleich? Nehmen Sie den folgenden Fall zum Beispiel:

template <template <class...> class Tuple, class... Ts> 
void f(Tuple<Ts...>&& arg) 
{ 

} 

Was hier bedeutet &&?

+1

Deduzierbarer Kontext ist nicht wichtig. (3) und (4) sind beide ableitbar. – Oktalist

Antwort

14

In Ihrem letzten Beispiel ist arg eine rvalue-Referenz.

A Forwarding Referenz ist eine rvalue Bezugnahme auf einen CV-unqualifizierten Template-Parameter

und Tuple<Ts...> kein Template-Parameter ist.

(Zitat aus [temp.deduct.call].)

9

Es ist eine rvalue Referenz, keine Forwarding Referenz.

Der einfachste Weg, um sicher zu sein, zu versuchen, einen L-Wert zu übergeben, wenn es scheitert, dann ist es eine rvalue Referenz, wenn nicht, dann eine Weiterleitung Referenz:

template<typename... Ts> 
struct foo {}; 

//f function definition 

int main() { 
    foo<int, double> bar; 
    f(bar); // fails! Cannot bind lvalue to rvalue reference 
    f(foo<int, double>{}); // ok, rvalue is passed 
} 
1

Das Referenzkonzept Weiterleitung ist nicht ein Standardkonzept, es ist nützlich, es zu erkennen, wenn Sie es sehen, aber wenn Sie es richtig verstehen und damit umgehen wollen, müssen Sie Referenzarithmetik verstehen.(Ich glaube, Meyers Buch hat auch ein Kapitel darüber)

Was verbirgt sich hinter dem Begriff des Forwarding Referenz ist die Referenz-Arithmetik:

  • & & & & = & &
  • & & & = &
  • & & & = &
  • & & = &

Lassen Sie uns Compiler Template-Typ Abzug mit einer Spedition Referenz

template<class T> 
void foo(T&&); 
//... 
const int i=42; 
foo(i); // the compiler will defines T = const int & 
     //   T&& = const int & && = const int & 
     // => the compiler instantiates void foo<const int &>(const int &); 
foo(6*7);// the compiler will defines T = int 
     //   T&& = int && 
     // the compiler instantiates void foo<int>(int &&); 

in einer solchen Situation die Instanziierung der Vorlage foo simulieren kann erzeugt eine Funktion wich nimmt Argument durch lvalue-Referenz oder Funktionen, die Argumente rvalue Bezug nimmt: eine Weiterleitungsreferenz ist entweder eine R-Wert-Referenz oder eine L-Wert-Referenz, abhängig vom Vorlagentyp-Abzug. Es ist wie folgt benannt, weil in einer solchen Situation muss der Parameter entweder als L-Wert oder als xValue, und dies ist die Aufgabe der T&& std::forward<T>(T&& a)

weitergegeben werden, wenn Sie eine Funktion deklarieren hat:

template<class T> 
void foo(ATemplateClass<T> && a); 

Unabhängig vom Typ, den der Compiler für T abgeleitet hat, erhalten Sie einen Rvalue-Referenzparameter.

+0

Sind Sie sich über Ihre Probe sicher? Ich glaube, dass foo (42) und foo (6 * 7) hier im gleichen Boot sind: https://godbolt.org/g/jOEK9b – RTempete

+0

@RTempete Dieser Teil der Post scheint falsch zu sein: wie du gesehen hast, beide folge zu "int &&" - das gleiche und nicht "const". Wenn Oliv erklären würde, warum sie denken, dass entweder "const" sein sollte und/oder es einen Unterschied geben sollte, basierend darauf, ob ein (trivialer, optimierter Weg auch bei "-O0" Ausdruck involviert ist), wäre das viel mehr sinnvoll. –

+0

Es gab zwei Fehler im Beispielcode. f (42) -> rvalue Referenz und f (6 * 7) auch. – Oliv

Verwandte Themen