Ich fand heraus, dass lvalue
Lambda-Verschlüsse immer als rvalue
Funktionsparameter übergeben werden können.
Siehe die folgende einfache Demonstration.
#include <iostream>
#include <functional>
using namespace std;
void foo(std::function<void()>&& t)
{
}
int main()
{
// Case 1: passing a `lvalue` closure
auto fn1 = []{};
foo(fn1); // works
// Case 2: passing a `lvalue` function object
std::function<void()> fn2 = []{};
foo(fn2); // compile error
return 0;
}
Fall 2 ist das Standardverhalten (ich habe a nur std::function
zu Demonstrationszwecken verwendet, aber jeder andere Typ würde sich gleich verhalten).
Wie und warum funktioniert Fall 1? Wie ist der fn1
Schließzustand nach der Rückgabe der Funktion?
fn1
implizit in einstd::function
In konvertiert wirdfoo(fn1)
. Diese temporäre Funktion ist dann ein Wert.std::function
aus einem Lambda abgeleitet werden?" Ihr Programm versucht nicht, die Vorlagenargumente von abzuleitenstd::function
, daher gibt es kein Problem mit der impliziten Konvertierung.std::function
hat einen nicht expliziten Konstruktor, der Lambda-Abschlüsse akzeptiert, sodass eine implizite Konvertierung erfolgt. Unter den Umständen der verknüpften Frage kann die Instanziierung der Vorlage vonstd::function
jedoch nicht aus dem Lambda-Typ abgeleitet werden. (Zum Beispielstd::function<void()>
kann aus konstruiert werden[](){return 5;}
, obwohl es einen nicht leeren Rückgabetyp hat.Antworten:
Für das Aufrufen ist
foo
eine Instanz erforderlichstd::function<void()>
, die an eine rvalue-Referenz gebunden ist .std::function<void()>
kann aus jedem aufrufbaren Objekt erstellt werden , das mit dervoid()
Signatur kompatibel ist .Zunächst wird ein temporäres
std::function<void()>
Objekt aus erstellt[]{}
. Der Konstruktor verwendet wird , ist # 5 hier , die Kopien der Verschluss in diestd::function
Instanz:Dann wird die temporäre
function
Instanz an die r-Wert-Referenz gebunden.Gleich wie zuvor, da es in eine
std::function
Instanz kopiert wurde . Der ursprüngliche Verschluss bleibt unberührt.quelle
Ein Lambda ist kein
std::function
. Die Referenz ist nicht direkt bindend .Fall 1 funktioniert, weil Lambdas in
std::function
s konvertierbar sind . Dies bedeutet, dass ein Temporärstd::function
durch Kopieren materialisiert wirdfn1
. Das temporäre Element kann an eine r-Wert-Referenz gebunden werden, sodass das Argument mit dem Parameter übereinstimmt.Und das Kopieren ist auch der Grund, warum
fn1
nichts, was in passiert, völlig unberührt bleibtfoo
.quelle
fn1
ist staatenlos, da es nichts erfasst.Dies funktioniert, weil das Argument einen anderen Typ hat als der Typ, auf den rvalue verweist. Aufgrund eines anderen Typs werden implizite Konvertierungen berücksichtigt. Da das Lambda für die Argumente hierfür aufrufbar ist
std::function
, kann es implizit über den Template-Konvertierungskonstruktor von in dieses konvertiert werdenstd::function
. Das Ergebnis der Konvertierung ist ein Wert und kann daher an die Referenz rvalue gebunden werden.quelle