Was ist ein Lambda-Ausdruck in C ++ 11? Wann würde ich einen verwenden? Welche Problemklasse lösen sie, die vor ihrer Einführung nicht möglich war?
Ein paar Beispiele und Anwendungsfälle wären nützlich.
Was ist ein Lambda-Ausdruck in C ++ 11? Wann würde ich einen verwenden? Welche Problemklasse lösen sie, die vor ihrer Einführung nicht möglich war?
Ein paar Beispiele und Anwendungsfälle wären nützlich.
Antworten:
C ++ enthält nützliche generische Funktionen wie std::for_each
und std::transform
, die sehr praktisch sein können. Leider kann die Verwendung auch sehr umständlich sein, insbesondere wenn der Funktor, den Sie anwenden möchten, für die jeweilige Funktion eindeutig ist.
#include <algorithm>
#include <vector>
namespace {
struct f {
void operator()(int) {
// do something
}
};
}
void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}
Wenn Sie nur f
einmal und an diesem bestimmten Ort verwenden, scheint es übertrieben, eine ganze Klasse zu schreiben, nur um etwas Triviales und Einmaliges zu tun.
In C ++ 03 könnten Sie versucht sein, Folgendes zu schreiben, um den Funktor lokal zu halten:
void func2(std::vector<int>& v) {
struct {
void operator()(int) {
// do something
}
} f;
std::for_each(v.begin(), v.end(), f);
}
Dies ist jedoch nicht zulässig und f
kann in C ++ 03 nicht an eine Vorlagenfunktion übergeben werden.
In C ++ 11 werden Lambdas eingeführt, mit denen Sie einen anonymen Inline-Funktor schreiben können, der den ersetzt struct f
. Für kleine einfache Beispiele kann dies sauberer zu lesen sein (es hält alles an einem Ort) und möglicherweise einfacher zu warten, zum Beispiel in der einfachsten Form:
void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}
Lambda-Funktionen sind nur syntaktischer Zucker für anonyme Funktoren.
In einfachen Fällen wird für Sie der Rückgabetyp des Lambda abgeleitet, z.
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) { return d < 0.00001 ? 0 : d; }
);
}
Wenn Sie jedoch anfangen, komplexere Lambdas zu schreiben, werden Sie schnell auf Fälle stoßen, in denen der Rückgabetyp vom Compiler nicht abgeleitet werden kann, z.
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
Um dies zu beheben, können Sie explizit einen Rückgabetyp für eine Lambda-Funktion angeben, indem Sie Folgendes verwenden -> T
:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
Bisher haben wir nichts anderes verwendet als das, was an das Lambda darin übergeben wurde, aber wir können auch andere Variablen innerhalb des Lambda verwenden. Wenn Sie auf andere Variablen zugreifen möchten, können Sie die Capture-Klausel (die []
des Ausdrucks) verwenden, die in diesen Beispielen bisher nicht verwendet wurde, z.
void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
} else {
return d;
}
});
}
Sie können sowohl von Referenz- und Wert erfassen, die Sie verwenden können angeben &
und =
jeweils:
[&epsilon]
Erfassung durch Referenz[&]
erfasst alle im Lambda verwendeten Variablen als Referenz[=]
Erfasst alle im Lambda verwendeten Variablen nach Wert[&, epsilon]
Erfasst Variablen wie mit [&], aber epsilon nach Wert[=, &epsilon]
erfasst Variablen wie mit [=], jedoch epsilon als ReferenzDie Generierung operator()
erfolgt const
standardmäßig mit der Folge, dass die Erfassung standardmäßig erfolgt, const
wenn Sie darauf zugreifen. Dies hat zur Folge, dass jeder Aufruf mit derselben Eingabe dasselbe Ergebnis liefert. Sie können jedoch das Lambda markieren, ummutable
zu fordern, dass das operator()
erzeugte nicht vorhanden ist const
.
const
immer ...
()
- es wird als Lambda mit null Argumenten übergeben, aber da () const
es nicht mit dem Lambda übereinstimmt, sucht es nach einer Typkonvertierung, die dies ermöglicht, einschließlich impliziter Umwandlung -to-function-pointer und ruft das dann auf! Hinterhältig!
std::function<double(int, bool)> f = [](int a, bool b) -> double { ... };
Normalerweise lassen wir den Compiler den Typ ableiten: auto f = [](int a, bool b) -> double { ... };
(und vergessen Sie nicht #include <functional>
)
return d < 0.00001 ? 0 : d;
garantiert doppelt zurückgegeben wird, wenn einer der Operanden eine ganzzahlige Konstante ist (dies liegt an einer impliziten Heraufstufungsregel des Operators ?:, Bei der der 2. und 3. Operand durch die übliche Arithmetik gegeneinander abgewogen werden Konvertierungen, egal welche ausgewählt wird). Ein Wechsel zu 0.0 : d
würde das Beispiel vielleicht leichter verständlich machen.
Das C ++ - Konzept einer Lambda-Funktion stammt aus dem Lambda-Kalkül und der funktionalen Programmierung. Ein Lambda ist eine unbenannte Funktion, die (in der eigentlichen Programmierung, nicht in der Theorie) für kurze Codeausschnitte nützlich ist, die nicht wiederverwendet werden können und deren Benennung nicht wert ist.
In C ++ ist eine Lambda-Funktion wie folgt definiert
[]() { } // barebone lambda
oder in all seiner Pracht
[]() mutable -> T { } // T is the return type, still lacking throw()
[]
ist die Erfassungsliste, ()
die Argumentliste und {}
der Funktionskörper.
Die Erfassungsliste definiert, was von außerhalb des Lambda innerhalb des Funktionskörpers verfügbar sein soll und wie. Es kann entweder sein:
Sie können eine der oben genannten Optionen in einer durch Kommas getrennten Liste mischen [x, &y]
.
Die Argumentliste ist dieselbe wie in jeder anderen C ++ - Funktion.
Der Code, der ausgeführt wird, wenn das Lambda tatsächlich aufgerufen wird.
Wenn ein Lambda nur eine return-Anweisung hat, kann der return-Typ weggelassen werden und hat den impliziten Typ von decltype(return_statement)
.
Wenn ein Lambda als veränderlich markiert ist (z. B. []() mutable { }
), darf es die Werte mutieren, die durch den Wert erfasst wurden.
Die durch den ISO-Standard definierte Bibliothek profitiert stark von Lambdas und erhöht die Benutzerfreundlichkeit um mehrere Balken, da Benutzer ihren Code jetzt nicht mehr mit kleinen Funktoren in einem zugänglichen Bereich überladen müssen.
In C ++ 14 wurden Lambdas um verschiedene Vorschläge erweitert.
Ein Element der Erfassungsliste kann jetzt mit initialisiert werden =
. Dies ermöglicht das Umbenennen von Variablen und das Erfassen durch Verschieben. Ein Beispiel aus dem Standard:
int x = 4;
auto y = [&r = x, x = x+1]()->int {
r += 2;
return x+2;
}(); // Updates ::x to 6, and initializes y to 7.
und eine aus Wikipedia, die zeigt, wie man mit std::move
:
auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [ptr = std::move(ptr)] {return *ptr;};
Lambdas können jetzt generisch sein ( auto
wäre hier äquivalent, T
wenn
T
sich irgendwo im umgebenden Bereich ein Typvorlagenargument befindet ):
auto lambda = [](auto x, auto y) {return x + y;};
C ++ 14 erlaubt abgeleitete Rückgabetypen für jede Funktion und beschränkt sie nicht auf Funktionen des Formulars return expression;
. Dies gilt auch für Lambdas.
r = &x; r += 2;
, dies geschieht jedoch mit dem ursprünglichen Wert von 4.
Lambda-Ausdrücke werden normalerweise verwendet, um Algorithmen zu kapseln, damit sie an eine andere Funktion übergeben werden können. Allerdings ist es möglich , eine Lambda unmittelbar nach Definition auszuführen :
[&](){ ...your code... }(); // immediately executed lambda expression
ist funktional äquivalent zu
{ ...your code... } // simple code block
Dies macht Lambda-Ausdrücke zu einem leistungsstarken Werkzeug für die Umgestaltung komplexer Funktionen . Sie beginnen, indem Sie einen Codeabschnitt wie oben gezeigt in eine Lambda-Funktion einschließen. Der Prozess der expliziten Parametrisierung kann dann nach jedem Schritt schrittweise mit Zwischentests durchgeführt werden. Sobald Sie den Codeblock vollständig parametrisiert haben (wie durch das Entfernen des Codeblocks gezeigt &
), können Sie den Code an einen externen Speicherort verschieben und zu einer normalen Funktion machen.
Ebenso können Sie Lambda-Ausdrücke verwenden, um Variablen basierend auf dem Ergebnis eines Algorithmus zu initialisieren ...
int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!
Als eine Möglichkeit , Ihre Programmlogik der Partitionierung , könnten Sie sogar finden es sinnvoll , einen Lambda - Ausdruck als Argument für einen anderen Lambda - Ausdruck passieren ...
[&]( std::function<void()> algorithm ) // wrapper section
{
...your wrapper code...
algorithm();
...your wrapper code...
}
([&]() // algorithm section
{
...your algorithm code...
});
Mit Lambda-Ausdrücken können Sie auch benannte verschachtelte Funktionen erstellen. Dies kann eine bequeme Möglichkeit sein, doppelte Logik zu vermeiden. Die Verwendung von benannten Lambdas ist auch für die Augen etwas einfacher (im Vergleich zu anonymen Inline-Lambdas), wenn eine nicht triviale Funktion als Parameter an eine andere Funktion übergeben wird. Hinweis: Vergessen Sie das Semikolon nach der schließenden geschweiften Klammer nicht.
auto algorithm = [&]( double x, double m, double b ) -> double
{
return m*x+b;
};
int a=algorithm(1,2,3), b=algorithm(4,5,6);
Wenn die nachfolgende Profilerstellung einen erheblichen Initialisierungsaufwand für das Funktionsobjekt ergibt, können Sie dies als normale Funktion umschreiben.
if
Aussagen funktioniert : if ([i]{ for (char j : i) if (!isspace(j)) return false ; return true ; }()) // i is all whitespace
Vorausgesetzt, es i
handelt sich um einstd::string
[](){}();
.
(lambda: None)()
Syntax von Python ist viel besser lesbar.
main() {{{{((([](){{}}())));}}}}
Antworten
F: Was ist ein Lambda-Ausdruck in C ++ 11?
A: Unter der Haube ist es das Objekt einer automatisch generierten Klasse mit Überladungsoperator () const . Ein solches Objekt wird als Closure bezeichnet und vom Compiler erstellt. Dieses 'Closure'-Konzept kommt dem Bind-Konzept aus C ++ 11 nahe. Aber Lambdas generieren normalerweise besseren Code. Und Anrufe durch Verschlüsse ermöglichen ein vollständiges Inlining.
F: Wann würde ich einen verwenden?
A: Um "einfache und kleine Logik" zu definieren und den Compiler zu bitten, führen Sie die Generierung aus der vorherigen Frage durch. Sie geben einem Compiler einige Ausdrücke, die Sie in operator () haben möchten. Alle anderen Sachen, die der Compiler für Sie generiert.
F: Welche Klasse von Problemen lösen sie, die vor ihrer Einführung nicht möglich waren?
A: Es ist eine Art Syntaxzucker wie das Überladen von Operatoren anstelle von Funktionen für benutzerdefinierte Add-, Subrtact- Operationen ... Es werden jedoch mehr Zeilen nicht benötigten Codes gespeichert , um 1-3 Zeilen echte Logik in einige Klassen usw. zu verpacken! Einige Ingenieure sind der Meinung, dass bei einer geringeren Anzahl von Zeilen die Wahrscheinlichkeit geringer ist, dass Fehler auftreten (ich denke auch).
Anwendungsbeispiel
auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);
Extras über Lambdas, nicht in Frage gestellt. Ignorieren Sie diesen Abschnitt, wenn Sie nicht interessiert sind
1. Erfasste Werte. Was können Sie erfassen
1.1. Sie können auf eine Variable mit statischer Speicherdauer in Lambdas verweisen. Sie alle werden gefangen genommen.
1.2. Sie können Lambda verwenden, um Werte "nach Wert" zu erfassen. In diesem Fall werden erfasste Variablen in das Funktionsobjekt kopiert (Abschluss).
[captureVar1,captureVar2](int arg1){}
1.3. Sie können als Referenz erfassen. & - bedeutet in diesem Zusammenhang Referenz, keine Zeiger.
[&captureVar1,&captureVar2](int arg1){}
1.4. Es gibt eine Notation, um alle nicht statischen Variablen nach Wert oder Referenz zu erfassen
[=](int arg1){} // capture all not-static vars by value
[&](int arg1){} // capture all not-static vars by reference
1.5. Es gibt eine Notation, um alle nicht statischen Variablen nach Wert oder Referenz zu erfassen und smth anzugeben. Mehr. Beispiele: Erfassen Sie alle nicht statischen Variablen nach Wert, aber nach Referenzerfassung Param2
[=,&Param2](int arg1){}
Erfassen Sie alle nicht statischen Variablen anhand der Referenz, aber anhand der Werterfassung Param2
[&,Param2](int arg1){}
2. Geben Sie den Typabzug zurück
2.1. Der Lambda-Rückgabetyp kann abgeleitet werden, wenn Lambda ein Ausdruck ist. Oder Sie können es explizit angeben.
[=](int arg1)->trailing_return_type{return trailing_return_type();}
Wenn Lambda mehr als einen Ausdruck hat, muss der Rückgabetyp über den nachfolgenden Rückgabetyp angegeben werden. Eine ähnliche Syntax kann auch auf automatische Funktionen und Elementfunktionen angewendet werden
3. Erfasste Werte. Was Sie nicht erfassen können
3.1. Sie können nur lokale Variablen erfassen, keine Mitgliedsvariable des Objekts.
4. versUmwandlungen
4.1 !! Lambda ist kein Funktionszeiger und keine anonyme Funktion, aber lambdas ohne Erfassung können implizit in einen Funktionszeiger konvertiert werden.
ps
Weitere Informationen zur Lambda-Grammatik finden Sie im Arbeitsentwurf für die Programmiersprache C ++ # 337, 16.01.2012, 5.1.2. Lambda Expressions, S.88
In C ++ 14 wurde die zusätzliche Funktion "Init Capture" hinzugefügt. Es ermöglicht die willkürliche Deklaration von Mitgliedern der Schließungsdaten:
auto toFloat = [](int value) { return float(value);};
auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
[&,=Param2](int arg1){}
scheint keine gültige Syntax zu sein. Die richtige Form wäre[&,Param2](int arg1){}
Eine Lambda-Funktion ist eine anonyme Funktion, die Sie inline erstellen. Es kann Variablen erfassen, wie einige erklärt haben (z. B. http://www.stroustrup.com/C++11FAQ.html#lambda ), es gibt jedoch einige Einschränkungen. Wenn es beispielsweise eine solche Rückrufschnittstelle gibt,
void apply(void (*f)(int)) {
f(10);
f(20);
f(30);
}
Sie können eine Funktion an Ort und Stelle schreiben, um sie wie die unten verwendete zu verwenden:
int col=0;
void output() {
apply([](int data) {
cout << data << ((++col % 10) ? ' ' : '\n');
});
}
Aber das kannst du nicht machen:
void output(int n) {
int col=0;
apply([&col,n](int data) {
cout << data << ((++col % 10) ? ' ' : '\n');
});
}
aufgrund von Einschränkungen im C ++ 11-Standard. Wenn Sie Captures verwenden möchten, müssen Sie sich auf die Bibliothek und verlassen
#include <functional>
(oder einen anderen STL-Bibliotheks-ähnlichen Algorithmus, um ihn indirekt abzurufen) und dann mit std :: function zu arbeiten, anstatt normale Funktionen als Parameter wie diesen zu übergeben:
#include <functional>
void apply(std::function<void(int)> f) {
f(10);
f(20);
f(30);
}
void output(int width) {
int col;
apply([width,&col](int data) {
cout << data << ((++col % width) ? ' ' : '\n');
});
}
apply
es eine Vorlage wäre, die einen Funktor akzeptiert, würde sie funktionieren
Eine der besten Erklärungen dafür lambda expression
gibt der Autor von C ++ Bjarne Stroustrup in seinem Buch ***The C++ Programming Language***
Kapitel 11 ( ISBN-13: 978-0321563842 ):
What is a lambda expression?
Ein Lambda-Ausdruck , der manchmal auch als Lambda- Funktion oder (streng genommen falsch, aber umgangssprachlich) als Lambda bezeichnet wird , ist eine vereinfachte Notation zum Definieren und Verwenden eines anonymen Funktionsobjekts . Anstatt eine benannte Klasse mit einem Operator () zu definieren, später ein Objekt dieser Klasse zu erstellen und es schließlich aufzurufen, können wir eine Kurzform verwenden.
When would I use one?
Dies ist besonders nützlich, wenn wir eine Operation als Argument an einen Algorithmus übergeben möchten. Im Zusammenhang mit grafischen Benutzeroberflächen (und anderswo) werden solche Vorgänge häufig als Rückrufe bezeichnet .
What class of problem do they solve that wasn't possible prior to their introduction?
Hier denke ich, dass jede Aktion, die mit Lambda-Ausdruck ausgeführt wird, ohne sie gelöst werden kann, aber mit viel mehr Code und viel größerer Komplexität. Lambda-Ausdruck Dies ist die Art der Optimierung Ihres Codes und eine Möglichkeit, ihn attraktiver zu machen. So traurig von Stroustup:
effektive Möglichkeiten zur Optimierung
Some examples
über Lambda-Ausdruck
void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0
{
for_each(begin(v),end(v),
[&os,m](int x) {
if (x%m==0) os << x << '\n';
});
}
oder über Funktion
class Modulo_print {
ostream& os; // members to hold the capture list int m;
public:
Modulo_print(ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{
if (x%m==0) os << x << '\n';
}
};
oder auch
void print_modulo(const vector<int>& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
class Modulo_print {
ostream& os; // members to hold the capture list
int m;
public:
Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{
if (x%m==0) os << x << '\n';
}
};
for_each(begin(v),end(v),Modulo_print{os,m});
}
Wenn du brauchst, kannst du lambda expression
wie folgt benennen :
void print_modulo(const vector<int>& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; };
for_each(begin(v),end(v),Modulo_print);
}
Oder nehmen Sie eine andere einfache Probe an
void TestFunctions::simpleLambda() {
bool sensitive = true;
std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7});
sort(v.begin(),v.end(),
[sensitive](int x, int y) {
printf("\n%i\n", x < y);
return sensitive ? x < y : abs(x) < abs(y);
});
printf("sorted");
for_each(v.begin(), v.end(),
[](int x) {
printf("x - %i;", x);
}
);
}
wird als nächstes generieren
0
1
0
1
0
1
0
1
0
1
0 sortiert x - 1; x - 3; x - 4; x - 5; x - 6; x - 7; x - 33;
[]
- Dies ist eine Erfassungsliste oder lambda introducer
: Wenn lambdas
kein Zugriff auf die lokale Umgebung erforderlich ist, können wir sie verwenden.
Zitat aus dem Buch:
Das erste Zeichen eines Lambda-Ausdrucks ist immer [ . Ein Lambda-Einführer kann verschiedene Formen annehmen:
• [] : Eine leere Erfassungsliste. Dies impliziert, dass im Lambda-Körper keine lokalen Namen aus dem umgebenden Kontext verwendet werden können. Für solche Lambda-Ausdrücke werden Daten aus Argumenten oder aus nichtlokalen Variablen erhalten.
• [&] : implizit als Referenz erfassen. Alle lokalen Namen können verwendet werden. Auf alle lokalen Variablen wird als Referenz zugegriffen.
• [=] : implizit nach Wert erfassen. Alle lokalen Namen können verwendet werden. Alle Namen beziehen sich auf Kopien der lokalen Variablen, die am Aufrufpunkt des Lambda-Ausdrucks erstellt wurden.
• [Erfassungsliste]: explizite Erfassung; Die Erfassungsliste ist die Liste der Namen lokaler Variablen, die erfasst werden sollen (dh im Objekt gespeichert sind), nach Referenz oder Wert. Variablen mit Namen vor & werden als Referenz erfasst. Andere Variablen werden nach Wert erfasst. Eine Erfassungsliste kann auch diese und Namen enthalten, gefolgt von ... als Elemente.
• [&, Erfassungsliste] : Erfassen Sie implizit alle lokalen Variablen mit Namen, die nicht in der Liste aufgeführt sind. Die Erfassungsliste kann dies enthalten. Aufgelistete Namen dürfen nicht vor & stehen. In der Erfassungsliste genannte Variablen werden nach Wert erfasst.
• [=, Erfassungsliste] : Erfasst implizit alle lokalen Variablen mit Namen, die nicht in der Liste aufgeführt sind, nach Wert. Die Erfassungsliste kann dies nicht enthalten. Vor den aufgeführten Namen muss & stehen. In der Erfassungsliste genannte Variablen werden als Referenz erfasst.
Beachten Sie, dass ein lokaler Name, dem & vorangestellt ist, immer als Referenz erfasst wird und ein lokaler Name, dem & nicht vorangestellt ist, immer als Wert erfasst wird. Nur die Erfassung durch Referenz ermöglicht das Ändern von Variablen in der aufrufenden Umgebung.
Additional
Lambda expression
Format
Zusätzliche Referenzen:
for (int x : v) { if (x % m == 0) os << x << '\n';}
Nun, eine praktische Anwendung, die ich herausgefunden habe, ist das Reduzieren des Kesselplattencodes. Zum Beispiel:
void process_z_vec(vector<int>& vec)
{
auto print_2d = [](const vector<int>& board, int bsize)
{
for(int i = 0; i<bsize; i++)
{
for(int j=0; j<bsize; j++)
{
cout << board[bsize*i+j] << " ";
}
cout << "\n";
}
};
// Do sth with the vec.
print_2d(vec,x_size);
// Do sth else with the vec.
print_2d(vec,y_size);
//...
}
Ohne Lambda müssen Sie möglicherweise etwas für verschiedene bsize
Fälle tun . Natürlich könnten Sie eine Funktion erstellen, aber was ist, wenn Sie die Verwendung im Rahmen der Soul-User-Funktion einschränken möchten? Die Natur von Lambda erfüllt diese Anforderung und ich benutze sie für diesen Fall.
Die Lambdas in c ++ werden als "on the go available function" behandelt. Ja, es ist buchstäblich unterwegs. Sie definieren es. benutze es; und wenn der übergeordnete Funktionsumfang beendet ist, ist die Lambda-Funktion weg.
c ++ führte es in c ++ 11 ein und jeder begann es wie an jedem möglichen Ort zu benutzen. Das Beispiel und was Lambda ist, finden Sie hier https://en.cppreference.com/w/cpp/language/lambda
Ich werde beschreiben, was nicht da ist, aber für jeden C ++ - Programmierer unbedingt zu wissen
Lambda soll nicht überall verwendet werden und jede Funktion kann nicht durch Lambda ersetzt werden. Es ist auch nicht das schnellste im Vergleich zur normalen Funktion. weil es einige Gemeinkosten hat, die von Lambda gehandhabt werden müssen.
In einigen Fällen wird dies sicherlich dazu beitragen, die Anzahl der Zeilen zu verringern. Es kann grundsätzlich für den Codeabschnitt verwendet werden, der einmal oder mehrmals in derselben Funktion aufgerufen wird, und dieser Code wird an keiner anderen Stelle benötigt, sodass Sie eine eigenständige Funktion dafür erstellen können.
Unten sehen Sie das grundlegende Beispiel für Lambda und was im Hintergrund passiert.
Benutzercode:
int main()
{
// Lambda & auto
int member=10;
auto endGame = [=](int a, int b){ return a+b+member;};
endGame(4,5);
return 0;
}
Wie compile es erweitert:
int main()
{
int member = 10;
class __lambda_6_18
{
int member;
public:
inline /*constexpr */ int operator()(int a, int b) const
{
return a + b + member;
}
public: __lambda_6_18(int _member)
: member{_member}
{}
};
__lambda_6_18 endGame = __lambda_6_18{member};
endGame.operator()(4, 5);
return 0;
}
Wie Sie sehen können, wird der Overhead hinzugefügt, wenn Sie ihn verwenden. Es ist also keine gute Idee, sie überall zu verwenden. Es kann an Orten verwendet werden, an denen sie anwendbar sind.
Ein Problem, das es löst: Code einfacher als Lambda für einen Aufruf im Konstruktor, der eine Ausgabeparameterfunktion zum Initialisieren eines const-Elements verwendet
Sie können ein const-Mitglied Ihrer Klasse mit einem Aufruf einer Funktion initialisieren, die ihren Wert festlegt, indem Sie ihre Ausgabe als Ausgabeparameter zurückgeben.