What is Lambda / Closure Function
A unnamed function that does not have a name, defined inside other
function.
Why Closures Are Needed?
1. Variable is kept alive between function calls without using global
variables. Global variables are risky because any part of your program
can accidentally change them
2. (Only C++) If some logic/function need to be called again and again,
then function is allocated on
stack. This save stacks
creation/deletion, jump instruction time
Syntax of Lambda
function_pointer = [ ] () mutable throw -> return_type {
.....function body ......
};
[ ] called Capture List
- captures local/Global variables defined outside lambda to be used inside lambda function.
- Changing Values of passed variables:
- Passed by value `[=]` are RO: These cannot be changed.
- Passed as reference `[&]`: Can be changed.
() called Parameter list which is Optional
- Function Parameters to be passed.
mutable keyword is Optional
throw keyword is Optional
return type is Optional. //if return type is not specified its Deduced Automatically
Examples
| Example |
Code |
Pass by Value (RO)
Outside variable cannot be modified in lambda.
|
| Passing 1 outside variable to lambda |
int i = 1;
auto p = [ i ] (int a, int b) -> int {
return a + b + i;
};
cout << p(2,3) << endl; //6
|
| Passing all outside variables to lambda |
int i = 1, j = 2;
auto p = [ = ] (int a, int b) -> int {
//j=3; //Error. assignment of read-only variable j
return a + b + i + j;
};
cout << p(3,4) << endl; //10
|
|
|
Pass by Reference(&) RW
|
| Passing 1 outside variable inside lambda |
int i = 1;
auto p = [ &i ] (int a, int b) -> int {
i = 5; return a + b + i;
};
cout << p(2,3) << endl; //10
|
| Passing all outside variables to lambda |
int i = 1, j = 2;
auto p = [ & ] (int a, int b) -> int {
return a + b + i + j;
};
cout << p(3,4); //10
|
|
|
Pass by ref and value in capture list
|
| Capture by reference all except 1 |
// Except "j" everything else is captured as reference
auto p7 = [ &, j ] (int a, int b) -> int {
i=7;
return a + b + i;
};
|
| Capture by Value all except 1 |
// Except "i" nothing can be changed.
auto p8 = [ =, &i ] (int a, int b) -> int {
i=95; return a + b + i;
};
|
|
return, break in lambda
int main() {
string s = "abcdfg";
for_each(s.begin(), s.end(), [&um, &out](const char ele){
auto it = um.find(ele);
if (it == um.end()) {
out = ele;
return; //break cannot be used in lambda. This break will exit lambda not function
} else {
um[ele]--;
if (um[ele] == 0)
um.erase(it);
}
});
}
Generic Lambda (C++14)
auto can be used inside lambda. Earlier this use to give error.
auto ptr = [](auto x, auto y){ return x+y; };
string a = "Never", b = "GiveUp";
cout << ptr(1,2) << endl; //3
cout << ptr(a,b) << endl; //NeverGiveUp
Lambda capture initializers
// Allows lambda captures initialized with arbitrary expressions.
auto f = [x = test(2)] { return x; }; //20
Accessing class members inside lambda
Call by Value
class A {
int a = 3;
public:
void f(){
auto ptr = [*this] { // this has to be captured to access members
//a = 3; // Error. Changing value of RO Object is not allowed
cout << a;
};
}
};