Lambda functions in C++
The C++ language supports unnamed functions (lambda functions). In fact, such an object can be assigned to a variable, and the variable can then be invoked as if it were a function.
Thus, a lambda function consists of a syntactic construct that defines a function.
Syntaxe
[](Parameters )->return_type{ // Instructions }
After the parameter list, you put the arrow -> and the return type identifier, followed by parentheses with the function's parameters. The syntax begins with the brackets [] (the capture clause or lambda initializer). Following the parameter list, you describe the instructions to be executed when the function is called within curly braces.
- It is possible to omit the arrow -> and the return type identifier if the compiler can determine the return type from the function's instructions alone. When the lambda function does not have parameters, we may also omit the parentheses after the lambda initializer.
- Furthermore, we can specify the names of variables outside the lambda function in the lambda initializer.
- A lambda function that does not capture external variables is known as a stateless lambda function.
Variables can be assigned to the statement describing a lambda function.
By using the "auto" keyword, we are automatically determining the type of the variable based on the lambda expression used to define it.
As the lambda function is an object that can be called, it belongs to a certain type, but it does not have a name. Therefore, it is not possible to specify the type explicitly.
Here is an example of assigning a lambda function to the variable "sum":
Example 1
auto sum=[](int n)->int{ int s=0; for(int k=1;k<=n;k++){ s+=k; } return s; };
Here, we define the variable "sum," which behaves like a function.
Using lambda, we can compute the sum of natural numbers from 1 to "n". If we call the function with an argument (as in the statement "sum(7)"), we will obtain the sum of natural numbers from 1 to "n".
Example 2: A complete program in which we use lambda functions.
#include <iostream> using namespace std; int main() { auto sum=[](int n)->int{ int s=0; for(int k=1;k<=n;k++){ s+=k; } return s; }; cout << "The sum from 1 to "<< 7<<"="<<sum(7)<<endl; // Since the returned value defines the type, the return type identifier can be omitted. auto fact=[](int n){ int f=1; for(int k=1;k<=n;k++){ f*=k; } return f; }; cout << "The factorial of 7 = "<<fact(7); return 0; }
Result
The sum from 1 to 7=28 The factorial of 7 = 5040
Using lambda functions, we are able to capture external variables and use them to calculate the result. The variables are listed in brackets when defining the lambda function. For example, the following code defines the lambda function "evaluer()" with an argument "x" of type double and captures two external variables, "a" and "b."
Example 3
#include <iostream> using namespace std; int main() { double a=2.5,b=3; auto evaluer=[a,&b](double x)->double{ return a*x+b; }; cout << "evaluer(2)= "<<evaluer(2)<<endl; cout << "evaluer(4.5)= "<<evaluer(4.5); return 0; }
Résultat
evaluer(2)= 8 evaluer(4.5)= 14.25
The variables "a" and "b," along with the parameter "x," are used to calculate the function's result. These variables must be initialized before the lambda function is defined. In addition, variable "a" is captured by its value, while variable "b" is captured by its reference (we used the "&" symbol before the variable's name). Variables that are captured by value will be used in the lambda function at the same value as at the time the lambda function was created. When a variable is captured by reference, the lambda function uses the value of the variable at the time it is called.
Example 4
#include <iostream> using namespace std; int main() { double a=2.5,b=3; auto evaluer=[a,&b](double x)->double{ return a*x+b; }; cout <<"evaluer(2)= "<evaluer(2)<<endl; a=3; b= 2.5; cout <"evaluer(2)= "<evaluer(2); return 0; }
Result
evaluer(2)= 8 evaluer(2)= 7.5
As we have seen above, the variables "a" and "b" are defined with values of 2.5 and 3, respectively, in the program above. In this step, we create the lambda function "evaluer()" that results in 8 when "x" is the parameter value. For example, for the parameter value 2, the function returns 8. We then assign new values to the variables a and b using the statements a = 3 and b = 2.5. Calling the "evaluer()" function with the same parameter results in the value 7.5.
As the lambda function is based on capturing values, changing the value of variable "a" does not change the lambda function. In contrast, the variable "b" is captured by reference and remains the same value of 2.5. Therefore, the lambda function uses the new value of 2.5 after assigning the variable the value 2.5. Thus, the lambda function returns the value of 2 * 2.5 + 2.5, which is 7.5.
The "=" symbol within brackets means that all external variables are captured (by value) in the lambda function description, whereas the "&" symbol indicates that all external variables are captured by reference.
Example 5
#include <iostream> using namespace std; int main() { double a=2.5,b=3; auto evaluer=[&](double x)->double{ return a*x+b; }; cout <<"evaluer(2)= "<<evaluer(2)<<endl; a=3; b= 2.5; cout <<"evaluer(2)= "<<evaluer(2); return 0; }
Result
evaluer(2)= 8 evaluer(2)= 8.5