Inhaltsverzeichnis
Lambda-Ausdrücke
Aus diesem Grunde kratzen die folgenden Beispiele nur an der Oberfläche.
Andererseits können wir nur an der Oberfläche kratzen, denn wenn wir tiefer kratzen, sind wir nicht mehr an der Oberfläche.— Lawrence J. Peter
Ad-hoc-Funktionen
Algorithmen der Standard-Bibliothek wie for_each() erwarten oft eine Funktion oder einen Funktor, der auf Elemente eines Bereichs angewendet wird. Mit einem Lambda-Ausdruck kann diese Funktion an Ort und Stelle erzeugt werden:
#include <algorithm> #include <iostream> #include <string> void lambdademo() { std::string s = "Hello, Lambda Expressions in C++11!"; std::for_each(s.begin(), s.end(), [] (char c) { std::cout << c; } // <-- hier ); std::cout << std::endl; }
Lambdas sind anonyme, lokal definierte Funktionen.
Der Rückgabetyp wird, sofern möglich, automatisch ermittelt.
Er kann hinter der Parameterliste mit -> Zieltyp
angegeben werden.
std::string uppercase; std::copy_if(s.begin(), s.end(), std::back_inserter(uppercase), [] (char c) -> bool { return ('A' <= c && c <= 'Z'); } ); std::cout << uppercase << std::endl;
Man beachte den neuen Algorithmus copy_if()
in <algorithm>
.
Lambdas sind als Variablenwerte speicherbar, um sie mehrfach zu nutzen. Das Schlüsselwort auto ist hierbei hilfreich:
auto fromAtoZ = [] (char c) -> char { return ('A' <= c && c <= 'Z') ? c : '.'; }; std::list<char> aList; std::transform(s.begin(), s.end(), std::back_inserter(aList), fromAtoZ);
Closure
Lambda-Ausdrücke beginnen mit einer eckigen Klammer. In dieser kann angegeben werden, welche lokalen Variablen(werte) der Umgebung innerhalb des Lambda-Ausdrucks bekannt sein sollen. Dieses Einbeziehen der Umgebung wird Closure (Einschluss) genannt.
#include <algorithm> #include <iostream> #include <vector> #include <string> void closuredemo() { std::string s = "Hello, lambda expressions in C++11!"; char low = 'A', high = 'Z'; std::for_each(s.begin(), s.end(), [low, high] (char c) // closure by value { if (low <= c && c <= high) std::cout << c; } ); std::cout << std::endl; }
Hier werden die bei der Lambda-Definition aktuellen Werte der Variablen low
und high
übernommen.
Auch referenzieller Einschluss ist möglich und manchmal erwünscht:
int count = 0; std::for_each(s.begin(), s.end(), [low, high, &count] (char c) // closure by reference: &count { if (low <= c && c <= high) ++count; } ); std::cout << count << std::endl;
Durch die Angabe [&]
werden alle Variablen der Umgebung als Referenz übernommen.
Durch [=]
werden alle Werte der Umgebung kopiert.
Auch gemischte Angaben [=, &count]
sind möglich.
In Methoden definierte Lambdas können [this]
(als Wert) einschließen,
um an Attribute eines Objektes heranzukommen.
Weitere Beispiele sind im
Visual Team Blog
zu finden.
Lambda-capture-Ausdrücke
C++14 erlaubt bei der Definition des Lambda-Ausdrucks neue lokale Variablen einzuführen, die ihre Werte durch Ausdrücke erhalten:
void tabulate(double a, double b, int n) { auto f = [a, dy = (b-a)/n] (int i) { return a + i * dy; }; for (int i = 0; i <= n; ++i) { std::cout << i << '\t' << f(i) << '\n'; } }
Generische Lambda-Ausdrücke
Der Typ von Lambda-Parametern kann vom Compiler ermittelt werden (ab C++14):
void generic_demo() { std::vector<std::string> v { "generic", "lambdas", "in", "C++14" }; std::sort(v.begin(), v.end(), [](auto a, auto b) { return a.size() < b.size(); }); for (auto e : v) std::cout << e << ' '; std::cout << '\n'; }