Ich habe versucht, einen Lambda-Vektor zu erstellen, bin aber gescheitert:
auto ignore = [&]() { return 10; }; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() { return 100; }); //3
Bis zu Zeile 2 wird es gut kompiliert . Die Zeile 3 gibt jedoch einen Kompilierungsfehler aus :
Fehler: Keine Übereinstimmungsfunktion für den Aufruf von 'std :: vector <main () :: <lambda () >> :: push_back (main () :: <lambda ()>)'
Ich möchte keinen Vektor von Funktionszeigern oder einen Vektor von Funktionsobjekten. Ein Vektor von Funktionsobjekten, die echte Lambda-Ausdrücke einkapseln , würde jedoch für mich funktionieren. Ist das möglich?
Antworten:
Jedes Lambda hat einen anderen Typ - auch wenn es dieselbe Signatur hat. Sie müssen einen Laufzeit-Kapselungscontainer verwenden, z. B.
std::function
wenn Sie so etwas tun möchten.z.B:
quelle
std::function<int()
ich, anstatt es zu beschränken , verschiedene Funktionsprototypen verwenden?vector
Speicherung für beide erstellenstd::function
undstd::string
?" Und die Antwort ist dieselbe: Nein, denn das ist nicht die beabsichtigte Verwendung. Sie können eine Klasse im Stil einer Variante verwenden, um eine ausreichende Typlöschung durchzuführen, um unterschiedliche Elemente in einen Container einzufügen, und gleichzeitig eine Methode einschließen, mit der ein Benutzer den Typ "real" bestimmen und damit auswählen kann, was zu tun ist (z. B. wie aufgerufen werden soll). jedes Element ... aber warum noch einmal so weit gehen? Gibt es eine echte Begründung?Alle Lambda-Ausdrücke haben einen anderen Typ, auch wenn sie zeichenweise identisch sind . Sie schieben ein Lambda eines anderen Typs (weil es ein anderer Ausdruck ist) in den Vektor, und das funktioniert offensichtlich nicht.
Eine Lösung besteht darin,
std::function<int()>
stattdessen einen Vektor zu erstellen.Außerdem ist es keine gute Idee, sie zu verwenden,
[&]
wenn Sie nichts erfassen.quelle
()
Benötigen Sie keine Lambdas, die keine Argumente enthalten.Während das, was andere gesagt haben, relevant ist, ist es immer noch möglich, einen Lambda-Vektor zu deklarieren und zu verwenden, obwohl dies nicht sehr nützlich ist:
Sie können also eine beliebige Anzahl von Lambdas darin aufbewahren, solange es sich um eine Kopie / Bewegung handelt
lambda
!quelle
Wenn Ihr Lambda zustandslos ist, dh in
[](...){...}
C ++ 11, kann es in einen Funktionszeiger umgewandelt werden. Theoretisch könnte ein C ++ 11-kompatibler Compiler dies kompilieren:quelle
auto ignore = *[] { return 10; };
würdeignore
einint(*)()
.explicit
erforderlich ist, ist die Dereferenzierung eines Lambda-Ausdrucks gültig und dereferenziert den aus der Konvertierung resultierenden Zeiger. Verwenden Sie dannauto
Zerfälle, die auf einen Zeiger verweisen. (Verwendenauto&
oderauto&&
hätte die Referenz behalten.)()
beabsichtigt oder versehentlich?Sie könnten eine Lambda-Generierungsfunktion verwenden (aktualisiert mit dem von Nawaz vorgeschlagenen Fix):
Aber ich denke, Sie haben zu diesem Zeitpunkt im Grunde Ihre eigene Klasse gemacht. Andernfalls müssen Sie wahrscheinlich ein Tupel verwenden, wenn die Lambdas völlig unterschiedliche Caputres / Args usw. haben.
quelle
lambda_gen
sie wiederum ein Lambda selbst sein kann. Allerdingsauto a = lambda_gen(1);
macht einen unnötigen Anruf, die vermieden werden können , wenn wir dies schreibendecltype(lambda_gen(1))
.decltype
befindet , wird nicht bewertet , sodass der Anruf nicht tatsächlich getätigt wird. So ist es auch mitsizeof
. Außerdem funktioniert dieser Code in C ++ 11 nicht, selbst wenn Sie einen nachfolgenden Rückgabetyp hinzufügen !!Jedes Lambda ist ein anderer Typ. Sie müssen
std::tuple
anstelle von verwendenstd::vector
.quelle