lambda-Funktionen

Ein Feature, auf das viele C++-Programmierer lang gewartet haben: lambda-Funktionen (manchmal auch: Closures) ermöglichen die schnelle und unkomplizierte Definitionen von Funktionobjekten direkt vor Ort. Man kann sie als Parameter für eine andere Funktion übergeben (wie in unserem Beispiel mit std::sort), in einer Variable speichern und später aufrufen. Hervorragend geeignet für kurze Callback-Funktionen, die bspw. zwei Objekte vergleichen.

Video

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <vector>
#include <algorithm>
 
struct Wrapper
{
    int value;
     
    Wrapper(int v)
        : value(v)
        {
        }
};
 
int main()
{
    std::vector<Wrapper> v;
    v.push_back(Wrapper(10));
    v.push_back(Wrapper(13));
    v.push_back(Wrapper(8));
    v.push_back(Wrapper(7));
    v.push_back(Wrapper(4));
     
    std::sort(v.begin(), v.end(), 
              [](Wrapper const &v1, Wrapper const &v2) { return v1.value > v2.value; };
             );
     
    for(Wrapper const &w : v) {
        std::cerr << w.value << std::endl;
    }
}

Erklärung

Das eigentlich interessante ist nur eine Zeile: Zeile 25 ist unsere lambda-Funktion. Eingeleitet durch [] (der sogenannten “capture specification”. Was das genau alles tun kann, dazu später mehr.), folgt danach eine Parameterliste wie bei einer normalen Funktion. Unsere hier nimmt also zwei Parameter jeweils vom Typ Wrapper const &. In den geschweiften Klammer danach steht der Funktionsbody. Der ist hier recht kurz. Schließlich soll die Funktion nur anhand der eingebetteten Werte die Frage beantworten, welcher von den beiden Wrappern bei der Sortierung zuerst kommt. Ergebnis dieser Zeile ist ein Objekt, welches laut C++ einen komplett eigenen Typ repräsentiert und sich verhält, wie ein Funktionsobjekt (so wird’s dann im allgemeinen auch implementiert sein).

Was auffällt: obwohl wir hier eine Funktion haben und diese ja üblicherweise einen Rückgabetyp angeben, fehlt die entsprechende Information hier. Das ist so gewollt: wenn der Compiler den Rückgabetyp ableiten kann, dann tut er das für lambda-Funktionen auch. Hier kann er das: die Rückgabe ist das Ergebnis des operator< im return-Statement der Funktion. Damit ist klar, dass der Rückgabetyp sinnigerweise nur bool sein kann. Das leitet der Compiler erfolgreich selbst ab und belästigt uns daher nicht mit der Frage.

Für alle, die’s noch etwas umfassende wollen und Englisch können: Alex Allain zum Thema lambda-Funktionen.