Was ist ein lambda-Ausdruck in C++11?
Was ist ein lambda-Ausdruck in C++11? Wann sollte ich Sie verwenden? Welche Klasse von problem, das Sie lösen nicht möglich war, vor Ihrer Einführung?
Wenige Beispiele und Anwendungsfälle nützlich sein.
Ich habe gesehen, ein Fall, in dem der lambda war sehr nützlich: Ein Kollege von mir war dabei, code, hat Millionen von Iterationen zur Lösung einer Raum-Optimierungs-problem. Der Algorithmus wurde viel mehr schnelle, wenn mit einem lambda-Ausdruck als eine richtige Funktion! Der compiler ist Visual C++ 2013.
InformationsquelleAutor Nawaz | 2011-10-02
Du musst angemeldet sein, um einen Kommentar abzugeben.
Das problem
C++ enthält nützliche generische Funktionen wie
std::for_each
undstd::transform
, die sehr nützlich sein kann. Leider können Sie auch ziemlich umständlich zu bedienen, besonders wenn die Funktor Sie sich bewerben möchten, ist einzigartig für die bestimmte Funktion.Wenn Sie nur
f
einmal und in dieser speziellen Stelle scheint es übertrieben zu schreiben, eine ganze Klasse nur etwas zu tun, was trivial ist und man sich ab.In C++03, könnten Sie versucht sein, etwas zu schreiben, wie die folgenden, um den Funktor lokal:
dies ist jedoch nicht erlaubt,
f
übergeben werden können, um eine Vorlage - Funktion in C++03.Die neue Lösung
C++11 führt lambdas erlauben, Sie zu schreiben, inline, anonyme Funktor zu ersetzen, die
struct f
. Für kleine einfache Beispiele, die diese sauberer zu Lesen ist (es hält sich noch alles in einem Ort) und möglicherweise einfacher zu erhalten, zum Beispiel in der einfachsten form:Lambda-Funktionen sind nur syntaktischer Zucker für anonyme funktoren.
Rückgabetypen
In einfachen Fällen, den Rückgabetyp von lambda abgeleitet wird, wie zum Beispiel:
aber wenn Sie anfangen, mehr zu schreiben, komplexe Lambda-Ausdrücke schnell werden Sie stoßen Fällen, in denen der return-Typ kann abgeleitet werden, indem der compiler, z.B.:
Beheben diese Sie sind berechtigt, geben Sie explizit einen Rückgabetyp für eine lambda-Funktion, mit
-> T
:"Einfangen" Variablen
Bisher haben wir nicht genutzt, alles andere als das, was übergeben wurde, um den lambda-innerhalb der it, aber wir können auch andere Variablen, die innerhalb der lambda. Wenn Sie möchten, um Zugriff auf die anderen Variablen, die Sie verwenden können, die capture-Klausel (die
[]
des Ausdrucks), die bislang ungenutzt in diese Beispiele, z.B.:Können Sie erfassen, indem sowohl Referenz-und Wert, den Sie angeben können mit
&
und=
jeweils:[&epsilon]
erfassen, durch einen Verweis[&]
erfasst alle Variablen, die im lambda-Verweis[=]
erfasst alle Variablen, die im lambda-Wert von[&, epsilon]
fängt Variablen, wie z.B. mit [&], aber epsilon von Wert[=, &epsilon]
fängt Variablen, wie z.B. mit [=], aber epsilon durch VerweisDen generierten
operator()
istconst
standardmäßig mit der Implikation, dass erfasst wirdconst
beim Zugriff standardmäßig. Dies hat den Effekt, dass jeder Aufruf mit dem gleichen input würde zum gleichen Ergebnis führen, jedoch können Sie markieren Sie die lambdaveränderlich
zu verlangen, dass dieoperator()
dass produziert wird, ist nichtconst
.const
immer...oh sneaky -- und es geschieht, wenn Sie aufrufen
()
- es ist vergangen, als ein null-argument, lambda, aber da() const
passt nicht die lambda, sieht es für eine Art Bekehrung, die es erlaubt, das beinhaltet implizit-cast-Funktion-Zeiger und ruft dann das! Sneaky!Interessant - ich hatte ursprünglich gedacht, dass Lambda-Ausdrücke waren anonym Funktionen eher als funktoren, und war verwirrt, wie fängt gearbeitet.
Wenn Sie möchten, Lambda-Ausdrücke, die als Variablen in Ihrem Programm, die Sie verwenden können:
std::function<double(int, bool)> f = [](int a, bool b) -> double { ... };
Aber in der Regel lassen wir den compiler Rückschlüsse auf die Art:auto f = [](int a, bool b) -> double { ... };
(und vergessen Sie nicht#include <functional>
)Ich nehme an, nicht jeder versteht, warum
return d < 0.00001 ? 0 : d;
garantiert zurück verdoppeln, wenn einer der Operanden eine integer-Konstante (es ist, weil von einer impliziten Förderung in der Regel der ?: Betreiber wo der 2. und 3. Operanden werden gegeneinander aufgewogen durch die üblichen arithmetischen Umwandlungen egal welche, die wird abgeholt). Wechsel zu0.0 : d
würde vielleicht das Beispiel einfacher zu verstehen ist.InformationsquelleAutor Flexo
Was ist eine lambda-Funktion?
Dem C++ - Konzept der lambda-Funktion stammt aus dem lambda-Kalkül und funktionale Programmierung. Lambda ist eine Unbenannte Funktion, die nützlich ist (in der Programmierung, nicht Theorie) für kurze code-Schnipsel, die unmöglich sind, um die Wiederverwendung und die es nicht Wert sind zu benennen.
In C++ eine lambda-Funktion, die wie folgt definiert
oder in seiner ganzen Pracht
[]
ist die capture-Liste()
die Liste der Argumente und{}
den Rumpf der Funktion.Der capture-Liste
Der capture-Liste definiert, was von außen von der lambda sollte sich innerhalb der Funktion Körper, und wie.
Es kann sein, entweder:
Können Sie mischen alle der oben genannten in eine Komma-separierte Liste
[x, &y]
.Die Liste der Argumente
Das argument Liste ist die gleiche wie in jedem anderen C++ - Funktion.
Die Funktion Körper
Den code, der ausgeführt wird, wenn die lambda eigentlich heißt.
Rückgabetyp Abzug
Wenn eine lambda hat nur eine return-Anweisung die return-Typ kann weggelassen werden und hat die implizite Art der
decltype(return_statement)
.Veränderlich
Wenn ein lambda-Ausdruck ist gekennzeichnet von Mutationen (z.B.
[]() mutable { }
) es ist erlaubt zu mutieren, die Werte, die erfasst worden sind von Wert.Anwendungsfälle
Die Bibliothek, definiert durch den ISO-standard profitiert stark von lambdas und erhöht die usability, mehrere bars, wie jetzt Benutzer nicht zu verwirren, Ihren code mit kleinen funktoren in einigen zugänglichen Bereich.
C++14
In C++14 lambdas wurden erweitert um verschiedene Vorschläge.
Initialisierte Lambda-Captures
Element der capture-Liste kann nun entsprechend mit
=
. Dies ermöglicht das umbenennen von Variablen und erfassen von Bewegung. Ein Beispiel aus dem standard:und stammt aus der Wikipedia zeigt, wie capture mit
std::move
:Generische Lambdas
Lambda-Ausdrücke können nun generische (
auto
wäre äquivalent zuT
hier, wennT
waren eine Art template-argument irgendwo in den umgebenden Bereich):Verbessert Rückgabetyp Abzug
C++14 erlaubt abgeleitet return-Typen für jede Funktion und nicht darauf beschränken, es mit Funktionen der form
return expression;
. Dies gilt auch für Lambda-Ausdrücke.1) die () aufzurufen sind die lambda direkt nach der Definition und y seinen Wert zurück. Die variable y ist eine ganze Zahl, die nicht die lambda. 2) Nein, x=5 ist lokale, um die lambda (eine Erfassung von Wert, die nur zufällig den gleichen Namen haben wie der äußere Umfang variable x), dann x+2 = 5+2 zurückgegeben. Die Umverteilung von den äußeren Variablen x erfolgt durch die Referenz r:
r = &x; r += 2;
, aber dies geschieht auf den ursprünglichen Wert von 4.InformationsquelleAutor pmr
Lambda-Ausdrücke werden in der Regel eingesetzt zur Kapselung von algorithmen, so dass Sie übergeben werden kann, um eine weitere Funktion. Allerdings es möglich ist, zum ausführen einer lambda-sofort nach der definition:
ist funktionell äquivalent zu
Das macht die lambda-Ausdrücke ein leistungsfähiges Werkzeug für das refactoring von komplexen Funktionen. Starten Sie durch das einwickeln von einem code-Abschnitt in eine lambda-Funktion, wie oben gezeigt. Der Prozess der expliziten Parametrisierung kann dann durchgeführt werden allmählich mit der Zwischenprüfung nach jedem Schritt. Sobald Sie den code-block vollständig parametriert (wie gezeigt durch die Entfernung der
&
), verschieben Sie den code, um einen externen Standort, und machen es eine normale Funktion.Ebenso können Sie die Verwendung von lambda-Ausdrücken zu initialisieren Sie Variablen basierend auf dem Ergebnis eines Algorithmus...
Als eine Methode zum partitionieren deiner Programm-Logik, man könnte sogar finden es nützlich, um pass ein lambda-Ausdruck als argument an eine andere lambda-Ausdruck...
Lambda-Ausdrücke ermöglichen die Erstellung von namens verschachtelte Funktionen, das kann ein bequemer Weg, vermeidet doppelte Logik. Mithilfe von named lambdas neigt auch dazu, ein wenig leichter auf die Augen (im Vergleich zu anonymen inline-Lambda-Ausdrücke) bei der übergabe eines nicht-trivialen Funktion, die als parameter an eine andere Funktion. Hinweis: vergessen Sie nicht das Semikolon nach der schließenden geschweiften Klammer.
Wenn die nachfolgenden profiling zeigt deutliche Initialisierungs-overhead für die function-Objekt, Sie können wählen, um diese umschreiben als eine normale Funktion.
Vielen Dank für das gleichzeitige bestimmen-und-ausführen-Tipp! Ich denke, es ist erwähnenswert, dass das funktioniert, dass als contidion für
if
Aussagen:if ([i]{ for (char j : i) if (!isspace(j)) return false ; return true ; }()) // i is all whitespace
, vorausgesetzti
ist einstd::string
So das folgende ist eine juristische Ausdruck:
[](){}();
.Pfui! Python ist
(lambda: None)()
syntax ist so viel besser lesbar ist.du hast Recht, ich vertippt. Das ist legal (getestet habe ich es dieses mal)
main() {{{{((([](){{}}())));}}}}
InformationsquelleAutor nobar
Antworten
Q: Was ist ein lambda-Ausdruck in C++11?
Ein: Unter der Haube, es ist das Objekt eine automatisch generierte Klasse mit überlastung operator - () const. Solche Objekte nennt Schließung wird und vom compiler.
Dieser "Verschluss" - Konzept ist in der Nähe mit der bind-Konzept von C++11.
Aber lambdas in der Regel besseren code generieren. Und ruft durch Verschlüsse erlauben die volle inlining.
Q: Wann sollte ich Sie verwenden?
A: definieren Sie "einfache und kleine Logik" und bitten compiler durchführen generation von der vorherigen Frage. Sie geben ein compiler einige Ausdrücke, die Sie wollen, um im operator(). Alle anderen Sachen compiler generiert für Sie.
Q: Welche Klasse von problem, das Sie lösen nicht möglich war, vor Ihrer Einführung?
A: Es ist eine Art syntax-Zucker wie Operatoren überladen statt-Funktionen für benutzerdefinierte hinzufügen, subrtact operations...Aber es sparen Sie mehr Linien von nicht benötigten code zu wickeln 1-3 Linien der realen Logik auf einige Klassen, und etc.! Einige Ingenieure glauben, dass, wenn die Anzahl von Zeilen kleiner ist, dann ist es weniger Chancen, Fehler zu machen (ich bin auch so denken)
Beispiel der Nutzung
Extras über lambdas, nicht fallenden Frage. Ignorieren Sie diesen Abschnitt, wenn Sie kein Interesse
1. Erfassten Werte. Was können Sie zu erfassen
1.1. Sie können einen Verweis auf eine variable mit static storage duration in lambdas. Sie alle sind gefangen.
1.2. Sie können lambda-capture-Werte "Wert". In einem solchen Fall erfasst vars kopiert werden, um die Funktion object (closure).
1.3. Sie können erfassen, werden Referenz. & - in diesem Kontext bedeuten, Referenz, keine Zeiger.
1.4. Es existiert notation für die Erfassung aller nicht-statischen vars per Wert oder per Referenz
1.5. Es existiert notation für die Erfassung aller nicht-statischen vars per Wert oder per Referenz angeben smth. mehr.
Beispiele:
Erfassung aller nicht-statische Variable durch einen Wert, sondern durch die Referenz capture Param2
Erfassung aller nicht-statischen vars, die durch Verweis, sondern durch den Wert zu erfassen, Param2
2. Rückgabetyp Abzug
2.1. Lambda-Rückgabetyp kann abgeleitet werden, wenn die lambda-Ausdruck ist ein Ausdruck. Oder Sie können explizit angeben.
Wenn die lambda hat mehr dann eines Ausdrucks, dann den Rückgabetyp angegeben werden muss, über trailing return type.
Auch, ähnliche syntax angewandt werden kann, um auto-Funktionen und member-Funktionen
3. Erfassten Werte. Was Sie nicht erfassen kann
3.1. Sie erfassen nur die lokale Variable, nicht die variable des Objekts.
4. Konvertierungen
4.1 !! Lambda ist nicht eine Funktion Zeiger, und es ist nicht eine anonyme Funktion, die aber capture-weniger lambdas kann implizit in einen Funktionszeiger.
p.s.
Mehr über lambda-Grammatik Informationen finden Sie im Working draft für die Programmiersprache C++ #337, 2012-01-16, 5.1.2. Lambda-Ausdrücke, p.88
In C++14, die zusätzliche Funktion, die mit dem Namen "init erfassen" Hinzugefügt wurden. Es erlauben Sie zu führen arbitarily Erklärung der Schließung von Daten-Mitglieder:
Ich append info über Aufnahme, Rückgabetyp Abzug in C++11 nach jemand geben Sie mir ein minus. Es wurde auch nicht erwähnt in Frage, aber ich Stell es zu beantworten! Vielleicht war es der Grund, der minus für meinen Beitrag ohne diese "extra-Abschnitt...."
Diese
[&,=Param2](int arg1){}
scheint keine gültige syntax. Die richtige form wäre[&,Param2](int arg1){}
Danke. Zuerst habe ich versucht zu kompilieren dieses snippet. Und es scheint seltsam assymetry in der zulässigen modificators in der capture-Liste // g++ -std=c++11 main.cpp -o test_bin; ./test_bin #include <stdio.h> int main() { #if 1 { int param = 0; auto f=[=,¶m](int arg1) mutable {param = arg1;}; f(111); printf("%i\n", param); } #endif #if 0 { int param = 0; auto f=[&,=param](int arg1) mutable {param = arg1;}; f(111); printf("%i\n", param); } #endif return 0; }
Sieht, dass die neue Linie nicht unterstützt Kommentar. Dann öffnete ich den 5.1.2 Lambda-Ausdrücke, p.88, "Working Draft, Standard für die Programmiersprache C ++", Dcoument-Nummer: #337, 2012-01-16. Und schaute in Grammatik, syntax. Und du hast Recht. Es gibt keine existiert so etwas wie capture via "= "arg"
InformationsquelleAutor bruziuz
Einer lambda-Funktion eine anonyme Funktion, die Sie erstellen in-line. Es kann capture Variablen wie einige bereits erläutert haben, (z.B. http://www.stroustrup.com/C++11FAQ.html#lambda), es gibt jedoch einige Einschränkungen. Zum Beispiel, wenn es eine callback-Schnittstelle, wie diese,
können Sie eine Funktion schreiben, auf der Stelle, es zu benutzen wie die, die bestanden bewerben unter:
Aber Sie können nicht dies tun:
aufgrund von Einschränkungen in der C++11 standard. Wenn Sie möchten, verwenden Sie erfasst, müssen Sie verlassen sich auf die Bibliothek und
(oder eine andere STL-Bibliothek Algorithmus wie man es indirekt) und dann mit std::function-anstatt die normalen Funktionen als Parameter wie folgt:
apply
wurde eine Vorlage angenommen, dass ein Funktor, es würde funktionierenAber das problem ist, dass wenn eine vorhandene Schnittstelle, können Sie nicht über den Luxus, in der Lage zu erklären, es anders als eine einfache alte Funktion. Der standard konnte wurden so entworfen, dass Sie eine neue Instanz von einem einfachen alten-Funktion, die generiert werden, jedes mal, wenn so ein lambda-Ausdruck, der ausgeführt wird, mit generierten hartcodierten Verweise auf die aufgenommenen Variablen. Es scheint eine lambda-Funktion erzeugt bei der Kompilierung. Gibt es andere Konsequenzen als gut. z.B., Wenn Sie deklarieren Sie eine statische variable, auch wenn Sie re-Evaluierung der lambda-Ausdruck, den Sie nicht bekommen, eine neue statische variable.
Funktionszeiger sind oft gedacht, um gerettet zu werden, und eine Lambda-Ausdrücke erfassen kann gehen out of scope. dass nur capture-weniger lambdas konvertieren-Funktion-Zeiger wurde von design
Haben Sie immer noch, um die Aufmerksamkeit auf stack-Variablen werden freigegeben, aus dem gleichen Grund so oder so. Siehe blogs.msdn.com/b/nativeconcurrency/archive/2012/01/29/... das Beispiel, Das ich schrieb mit der Ausgabe und anwenden ist so geschrieben, dass, wenn anstelle von Funktionszeigern waren erlaubt, und diese würde auch funktionieren. Der col bleibt zugeteilt, bis alle der Funktionsaufrufe von anwenden, fertig. Wie würden Sie das umschreiben dieser code funktioniert mit den vorhandenen anwenden-Schnittstelle? Würde Sie am Ende mit globalen oder statischen Variablen-oder einige mehr verborgene transformation des Codes?
oder vielleicht haben Sie einfach nur bedeuten, dass die lambda-Ausdrücke rvalues und daher temporäre, aber der code bleibt konstant (singleton/statische), so dass es genannt werden kann, in der Zukunft. In diesem Fall, vielleicht die Funktion sollte weiterhin zugeteilt bleibt, solange der stack-allokierten erfasst zugewiesen bleiben. Natürlich könnte es chaotisch abwickeln, wenn zum Beispiel viele Varianten der Funktion zugeordnet sind, in einer Schleife.
InformationsquelleAutor Ted
Einer der besten Erklärung
lambda expression
ist vom Autor des C++ Bjarne Stroustrup in seinem Buch***The C++ Programming Language***
Kapitel 11 (ISBN-13: 978-0321563842):What is a lambda expression?
When would I use one?
What class of problem do they solve that wasn't possible prior to their introduction?
Hier ich denke, jede Aktion erfolgt mit lambda-Ausdruck kann gelöst werden, ohne Sie, aber mit viel mehr code und die viel größere Komplexität. Lambda-Ausdruck dies ist der Weg der Optimierung für deinen code und einen Weg, um es attraktiver zu gestalten. Wie traurig von Stroustup :
Some examples
per lambda-Ausdruck
oder über die Funktion
oder sogar
wenn u müssen u können Namen
lambda expression
wie unten:Oder übernehmen ein anderes einfaches Beispiel
generiert nächsten
[]
- dies ist die capture-Liste oderlambda introducer
: wennlambdas
benötigen keinen Zugang zu Ihrem lokalen Umfeld können wir es verwenden.Zitat aus dem Buch:
Additional
Lambda expression
formatZusätzliche Verweise:
InformationsquelleAutor gbk
Gut, einen praktischen nutzen, ich habe herausgefunden, ist die Reduzierung von boiler plate code. Zum Beispiel:
Ohne lambda, müssen Sie möglicherweise tun Sie etwas für andere
bsize
Fällen. Natürlich könnte man eine Funktion erstellen, aber was ist, wenn Sie wollen, beschränken Sie die Nutzung im Rahmen der Seele-user-Funktion? die Natur des lambda-diesen Anspruch erfüllt und ich verwenden es für diesen Fall.InformationsquelleAutor Misgevolution
Einem problem, das es löst: Code einfacher als lambda für einen Aufruf im Konstruktor, der verwendet ein output-parameter-Funktion für die Initialisierung einer const-member
Können Sie die Initialisierung eines const-member der Klasse, mit einem Aufruf zu einer Funktion, die setzt seinen Wert, indem Sie Ihre output als output-parameter.
InformationsquelleAutor sergiol