2016-04-25 22 views
-2

Ich lese this (unglaublich gut geschrieben) Artikel über Forwarding Referenz in C++ 11 von Scott Meyers.C++: Verwirrung über Weiterleitung Referenz

Nun konzentrieren sich auf diesem Teil des Artikels:

template <class... Args> 
void emplace_back(Args&&... args); // deduced parameter types ⇒ type deduction; 
...        // && ≡ universal references 

Also, im Gegensatz zu anderen Fällen, die Ellipsen machen nicht die && rvalue Referenz, aber es ist noch universal Referenzen.

Von dem, was ich verstanden habe, wenn wir universelle Referenzen haben wir die Funktion sowohl rvalue anrufen und lvalues ​​vorbei (wow, so cool)

Jetzt habe ich diese Funktion implementiert:

template <typename ReturnType, typename... Args> 
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) { ... 

Also (&&) (die gleiche Logik des vorherigen Beispiels verwendend) bedeutet Weiterleitungsreferenzen.

Aber wenn ich versuche, diesen Anruf zu machen:

typedef vector<double> vecD; 
vecD vec; 
mem.callFunction<vecD, vecD>(sortFunc, vec); 

Der Compiler mit You cannot bind an lvalue to an rvalue reference

beschweren wird, warum dies geschieht?

der gesamte Code:

#include <functional> 
#include <vector> 

using namespace std; 
struct MultiMemoizator { 
    template <typename ReturnType, typename... Args> 
    ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) { 

    } 
}; 

typedef vector<double> vecD; 

vecD sort_vec (vecD const& vec) { 
    return vec; 
} 

int main() 
{ 
    vecD vec; 
    std::function<vecD(vecD)> sortFunc(sort_vec); 
    MultiMemoizator mem; 
    mem.callFunction<vecD, vecD>(sortFunc, vec); 
} 
+5

* Universal * Referenzen war schrecklich von Anfang an, und jetzt ist es endlich mit viel mehr geeignet * Weiterleitung * Verweis ersetzt. – SergeyA

+2

Sind Sie sicher, dass "Args" tatsächlich * in Ihrem Anruf * abgeleitet wurde? –

+1

Ich würde gerne echte MCVE sehen. Aus dem Snippet sollte es gut funktionieren. – SergeyA

Antwort

7

Also zunächst einmal, bitte auf die "Forwarding Referenz" anstelle von "Universal-Referenz" verwenden. Es repräsentiert besser, was es ist und was es beabsichtigt ist.

Das erste, was zu beachten ist, dass nicht jede && eine Weiterleitungsreferenz ist. Es kann auch eine rvalue-Referenz sein.

Vereinfachen T&& ist eine Speditions Referenz, wenn und nur wenn:

  • T ist eine einfache (einfach wie unten gezeigt) geben (so zum Beispiel vector<int>&& oder vector<T>&& ist nicht eine Weiterleitung Referenz).
  • und T wird abgeleitet.

In Ihrem Beispiel Args ist nicht abgeleitet.Das ist, weil Sie explizit die Funktion Template-Argument Args angeben, wenn Sie es nennen:

mem.callFunction<vecD, vecD>(sortFunc, vec); 
         ^~~~ 

Lassen Sie uns die Arbeit mit etwas einfacher, besser zu verstehen:

Lässt die Szene ein:

struct X {}; 

template <class T> 
auto foo(T&& p) {} 

In den nächsten 2 Aufrufen haben wir Forwarding-Referenzen:

X x; 
foo(x); 

foo(X{}); 

Im ersten T wird als X& und durch Kollabieren Regeln abgeleitet werden: X& &&X& wird, deshalb haben wir eine lvalue Referenz. Wie Sie es erwarten würden.

Im zweiten T wird als X und durch Kollabieren Regeln abgeleitet werden X &&X&& wird, deshalb haben wir eine rvalue Referenz.

Aber wenn man es so nennen:

foo<X>(x); 

T nicht mehr abgeleitet. Du sagst grundsätzlich T sei X. Also, wenn T ist X dann T && ist X&&, und Sie haben den Fehler: dessen Typ ist jetzt X&& kann nicht an einen Lvalue binden.


Holt auch hinzugefügt:

Also note that because of the declaration of sortFunc, this would not work even if you did not specify the function template arguments explicitely.

Ich neige dazu, mit ihm einverstanden, aber ich müsste weiter untersuchen sicher davon sein.

+0

Beachten Sie auch, dass dies wegen der Deklaration von 'sortFunc' nicht funktioniert, auch wenn Sie die Argumente der Funktionsvorlage nicht explizit angegeben haben. – Holt

+0

Ich denke, dass ich Ihre Antwort verstanden habe, aber meine nächste Frage ist: Es gibt eine Möglichkeit, meinen Code "Forwarding referencable" zu machen (und so den Args-Typ abzuleiten). – justHelloWorld

+0

@justHelloWorld auf den ersten Blick würde ich nein sagen (zumindest nicht ohne einige böse hässliche Hacks). Sie müssen 'Args' für' sortFunc' angeben. Vielleicht, wenn du 'memFunc' den letzten Parameter machst (weiß nicht, ob es möglich ist), so dass' Args' Abzug zuerst stattfindet, aber dann würde es die Signatur von 'memFunc' ändern. Sie könnten jedoch 'remove_reference_t' zur Signatur von' memFuc' hinzufügen. Wie ich schon sagte, hässliche hässliche Hacks. – bolov