C++ – Lambdas

Lambdas or Lambda Expressions were introduced into the standard in C++11.

Lambda expressions let us write compact code. It is just a way to write function definitions right where we need to use them and thus save us the trouble of declaring and defining the functions elsewhere before calling them. C++ has traditionally being considered as a procedural language as well as an object oriented language. I feel that Lambda expressions are amongst those new constructs that have brought the functional programming style to C++.

The syntactic structure of a generic lambda expression looks like below.
[captures] (parameters)->return_type {body}

1) captures Any variable that needs to be captured from the enclosing scope can be added here. Variables can be captured either by value or by reference. For a variable named a,

    [a] - Capture a by value. The value is copied as a const. Therefore it cannot be 
modified within the lambda body.
    [&a] - Capture a by reference. If a is modified within the lambda body, it gets 
reflected in the outer scope.
    [&] - Capture all variables by reference.
    [=] - Capture all variables by value.
    [] - No Capture.
    [a,&] - Capture a by value and all other variables by reference.
    [&a,=] - Capture a by reference and all other variables by value.
    [this] - Capture the containing object's this pointer.

From C++14 onwards, it is possible to declare and initialize variables within the capture clause. This is very useful as it allows the use of std::move() operation within the capture clause. For example, a unique_ptr that can only be moved can be captured like this.

#include <memory>
using namespace std;
int main(){
unique_ptr<int> a(new int);
auto func = [b=move(a)](){};
return 0;
}
view raw Lambdas2 hosted with ❤ by GitHub

2) parameters Any parameters that need to passed to the lambda expression can be placed here. auto keyword can also be used here which creates a templated lambda expression that can accept arguments of different types.

3) return_type Specify the return type. This is an optional field. Compiler can deduce the type automatically as well.

4) body This is the body of the lambda expression.

Let us look at a few examples that illustrate the use of Lambdas.

#include <iostream>
using namespace std;
int main(){
int multiplier = 25;
/*Takes an integer input by reference and multiplies it by 2.*/
auto func1 = [](int& a){a *=2;};
/*Takes an integer input by value, multiplies it by 2 and returns the result.*/
auto func2 = [](int a)->int {a *=2; return a;};
/*Takes an integer input by value, multiplies it by multiplier whose value is captured from the outer scope and returns the result.*/
auto func3 = [multiplier](int a)->int{a *= multiplier; return a;};
int temp = 5;
func1(temp);
cout << temp<<endl;
cout << func2(temp)<<endl;
cout << func3(temp)<<endl;
}
view raw Lambdas1 hosted with ❤ by GitHub

Output:

    10
    20
    250

Lambdas can also be passed as arguments to functions that expect a function pointer or a functor as one of the arguments. The built-in functions within the algorithm library are prime examples of this. For example,

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
vector<int>arr = {4,5,6,3,2};
/* Sort elements in descending order. */
sort(arr.begin(), arr.end(),
[](int&a, int&b)->bool{return a>b;});
/* Add 2 to all the elements of the array */
for_each(arr.begin(), arr.end(),
[](int& a){ a+=2;});
}
view raw BlogSnippets hosted with ❤ by GitHub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: