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; | |
} |
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; | |
} |
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;}); | |
} |
Leave a Reply