Konda.eu

C++ Lambda Expressions

zoom
No comments

C++ Lambda Expressions

C++ is currently going through some extensive updates started with the new C++11 standard back in 2011. One of the exciting and very powerful new features are anonymous functions also knows as lambdas. You can simply write them inline in your source code and pass them around as function pointers. An example of sorting vector of ints in a descending order:

vector<int> vec = { 10, 1, 5, 6, 7, 3, 5 };

sort(vec.begin(), vec.end(), [](int x, int y) { return x < y; });

Lambda Syntax

There are four variations of C++ lambda function syntax:

[ capture ] ( params ) mutable -> ret { body }

[ capture ] ( params ) -> ret { body }

[ capture ] ( params ) { body }

[ capture ] { body }

 

Lambda Closures (capture)

Capture specifies how the variables are visible inside lambda body:

[] => Variables aren't visible in lambda function body

[&] => Variables are visible and passed by reference.

[=] => Variables are visible and passed by value.

for (auto i = 0; i &lt; N; ++i) {
    [&]{ cout << i; }; // OK, passed by reference
    [=]{ cout << i; }; // OK: passed by value
    [ ]{ cout << i; }; // ERROR: i is not visible
    [i]{ cout << i; }; // OK: only i is passed (by value)

    [&, i] {}; // OK: i passed by value
    [=, &i] {}; // OK: i is passed by reference
    [=, i] {}; // ERROR: i already passed by value
    [i, i] {}; // ERROR: i is repeated
}

 

Lambda Function Parameters

Lambda function parameter list (lambda declarators) is used exactly the same way as the standard syntax. It's an optional parameter, therefore parenthesis can be skipped if not used.

[](int a) { cout << a; };
[](int a, int b) { cout << a + b; };
[]() { return 0; };
[] { return 0; }; // same as line above

 

Lambda Function Return Type

By default, compiler uses template deduction for determining which type lambda returns. But sometimes when there are multiple returns statements of a different return type, results a compile error. Therefore, you can explicitly specify lambda return type (-> double in an example below)

[] (int a, double b) -> double 
{
    if (a > b)
        return a;
    else
        return b;
};

 

Mutable

By default, all parameters are passed as const by value. mutable keyword removes const and enables that body of the lambda expression modifies all values capture by value. Parenthesis are required when specifying mutable lambdas.

int a = 0;

auto f1 = [&]() mutable { a += 100; printf("f1 %d", a); };
auto f2 = [&]()         { a += 100; printf("f2 %d", a); };
auto f3 = [=]() mutable { a += 100; printf("f3 %d", a); };
auto f4 = [=]()         { a += 100; }; // ERROR: a is const
    
f1(); // prints: "f1: 100"
f2(); // prints: "f2: 200"
f3(); // prints: "f3: 300"

printf("main: %d", a); // main: 200

 

Examples

Lambdas go great with STL (Standard Template Library) library. A quick example on how to fill a vector with random numbers between 10 and -10.

std::generate(vec.begin(), vec.end(), []{ return rand() % (20 + 1) - 10; });

Lambda function used as delegate:

template<typename F>
void measure_time(F &&f)
{
    auto begin = clock();
    f();
    auto end = clock();

    printf("%d seconds\n", (end - begin) / CLOCKS_PER_SEC);
}


int main(int argc, char *argv[])
{
    measure_time([]() 
    {
        for (int i = 0; i < INT_MAX; ++i);
    });


    return 0;
}

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.