C++ Lambda

C++ Lambda expression allows us to define anonymous function objects (functors) which can either be used inline or passed as an argument.

Lambda expression was introduced in C++11 for creating anonymous functors in a more convenient and concise way.

They are more convenient because we don't need to overload the () operator in a separate class or struct.

Creating a Lambda Expression in C++

A basic lambda expression can look something like this:

auto greet = []() < // lambda function body >;

The above code is equivalent to:

void greet() < // function body >

Now, just like the normal functions, we can simply invoke the lambda expression using:

greet();

Note: We have used the auto keyword to automatically deduce the return type for lambda expression.

Example: C++ Lambda Function

#include using namespace std; int main() < 
// create a lambda function that prints "Hello World!" auto greet = []() < cout ;
// call lambda function greet(); return 0; >

Output

Hello World!

In the above example, we have created a simple program that prints Hello World! using a C++ lambda expression.

First, we created the lambda function and assigned it to a variable named greet .

auto greet = []() < cout ;

Then, we have called the lambda function using the greet variable along with the () operator:

// displays "Hello World!" greet(); 

C++ Lambda Function With Parameters

Just like a regular function, lambda expressions can also take parameters. For example,

#include using namespace std; int main() < // lambda function that takes two integer // parameters and displays their sum auto add = [] (int a, int b) < cout C++ Lambda Function With Return Type 

Like with normal functions, C++ lambda expressions can also have a return type.

The compiler can implicitly deduce the return type of the lambda expression based on the return statement(s).

auto add = [] (int a, int b) < // always returns an 'int' return a + b; >;

In the above case, we have not explicitly defined the return type for the lambda function. This is because there is a single return statement which always returns an integer value.

But for multiple return statements of different types, we have to explicitly define the type. For example,

auto operation = [] (int a, int b, string op) -> double < if (op == "sum") < // returns integer value return a + b; >else < // returns double value return (a + b) / 2.0; >>;

Notice the code -> double above. This explicitly defines the return type as double , since there are multiple statements which return different types based on the value of op .

So no matter what type of value is returned by the various return statements, they are all explicitly converted to double type.

Example 2: C++ Lambda - Explicit Return Type

#include using namespace std; int main() < 
// lambda function with explicit return type 'double' // returns the sum or the average depending on operation auto operation = [] (int a, int b, string op) -> double < if (op == "sum") < return a + b; >else < return (a + b) / 2.0; >>;
int num1 = 1; int num2 = 2; // find the sum of num1 and num2 auto sum = operation(num1, num2, "sum"); cout else < // returns a 'double' return (a + b) / 2.0; >>;

In main() , we first find the sum of num1 and num2 by passing "sum" as the third argument:

auto sum = operation(num1, num2, "sum");

Here, even though the lambda returns an integer value, it is explicitly converted to double type.

Then, we find the average by passing some other string as the argument:

auto avg = operation(num1, num2, "avg");

C++ Lambda Function Capture Clause

By default, lambda functions cannot access variables of the enclosing function. In order to access those variables, we use the capture clause.

We can capture the variables in two ways:

Capture by Value

This is similar to calling a function by value. Here, the actual value is copied when the lambda is created.

Note: Here, we can only read the variable inside the lambda body but cannot modify it.

A basic lambda expression with capture by value looks as follows:

int num_main = 100; // get access to num_main from the enclosing function auto my_lambda = [num_main] () < cout ;

Here, [num_main] allows the lambda to access the num_main variable.

If we remove num_main from the capture clause, we will get an error since num_main cannot be accessed from the lambda body.

Capture by Reference

This is similar to calling a function by reference i.e. the lambda has access to the variable address.

Note: Here, we can read the variable as well as modify it inside the lambda body.

A basic lambda expression with capture by reference looks as follows:

int num_main = 100; // access the address of num_main variable auto my_lambda = [&num_main] () < num_main = 900; >;

Notice the use of the & operator in [&num_main] . This indicates that we are capturing the address of the num_main variable.

Example 3: C++ Lambda Capture by Value

#include using namespace std; int main() < int initial_sum = 100; 
// capture initial_sum by value auto add_to_sum = [initial_sum] (int num) < // here inital_sum = 100 from local scope return initial_sum + num; >;
int final_sum = add_to_sum(78); cout

In the above example, we have created a lambda expression that returns the sum of a local variable named initial_sum and an integer parameter num.

auto add_to_sum = [initial_sum] (int num) < return initial_sum + num; >;

Here, [initial_sum] captures initial_sum from the enclosing function by value.

Then, we invoke the function and store its return value in the final_sum variable.

int final_sum = add_to_sum(78);

Inside the lambda function:

So the result becomes 100 + 78 which is 178.

Note: Suppose we want to capture multiple variables by value. For example,

auto my_lambda = [a, b, c, d, e] ()< // lambda body >

As you can see, this can be a very tedious task. To make our work easier, we can simply use implicit capture by value. For example,

auto my_lambda = [=] ()< // lambda body >

Here, [=] says all the variables of the enclosing function are captured by value.

Example 4: C++ Lambda Capture by Reference

#include using namespace std; int main() < int num = 0; cout // [&num] captures num by reference auto increment_by_one = [&num] () < cout ; // invoke lambda function increment_by_one(); cout ;

Here [&num] is used to capture num by reference.

Initially, the value of num is 0.

Then, we call the lambda expression increment_by_one() . This increases the value of num to 1.

Note: To capture all variables of the enclosing function, we can simply use implicit capture by reference. For example,

auto my_lambda = [&] ()< // lambda body >

Here, [&] indicates that all the variables are captured by reference.

Example: C++ Lambda Function as Argument in STL Algorithm

#include #include 
#include using namespace std; int main() < // initialize vector of integers vectornums = ;
int even_count = count_if(nums.begin(), nums.end(), [](int num) < return num % 2 == 0; >);
cout

Output

There are 5 even numbers.

In the above example, we have used a lambda function in the count_if algorithm to count the total even numbers in the nums vector:

int even_count = count_if(nums.begin(), nums.end(), [](int num) < return num % 2 == 0; >);

Notice that we have provided the lambda expression as the third argument to count_if . The lambda expression takes the integer num and returns true if num is even.

Also, we have passed the lambda expression inline.

[](int num)

Frequently Asked Questions

Can we use both capture by value and capture by reference in a single lambda capture clause?

Yes, we can use both capture by variable and capture by reference in a single lambda expression.

  • [&num1, num2] - capture num1 by reference and num2 by value
  • [&, num1, num2] - capture num1 and num2 by value and the rest by reference
  • [=, &num1, &num2] - capture num1 and num2 by reference and the rest by value
How can we write a lambda expression without using the auto keyword?

We can do that using the function<> template.

In order to do that, we first need to import header file.

#include 
#include using namespace std; int main() <
function add = [] (int a, int b) < cout ;
add(1, 2); return 0; >

Output

Sum: 3

Here, function explicitly tells that the lambda function is of void type and takes two integer parameters.

How to use a generic lamba?

In C++14, generic lambda was introduced to support generic template parameters in the lambda function.

#include using namespace std; int main() < 
auto display = [] (auto s) < cout ;
display(1); display(2.5); display("Kathmandu"); return 0; >

Output

1 2.5 Kathmandu

In the above example, we have used a single lambda expression to accept a generic type parameter and print the value.

auto display = [] (auto s)< cout ;

Notice the code auto s in the parameter list. This allows us to pass values of different types to the lambda expression.

What is mutable keyword in Lambda?

The lambda mutable keyword allows lambda to modify the variable captured by value inside the lambda body without affecting its original value in the enclosing function.

However the variables captured by reference are not affected. For example,

#include using namespace std; int main() < int a = 1; int b = 1; cout auto add_one = [a, &b] () mutable < // modify both a & b a++; b++;cout ; add_one(); cout 
How to create an immediately invoked lambda expression?

Immediately invoked lambda expression is a lambda expression which is immediately invoked as soon as it is defined. For example,

#include using namespace std; int main() < int num1 = 1; int num2 = 2; 
// invoked as soon as it is defined auto sum = [] (int a, int b) < return a + b; >(num1, num2);
cout

Output

The sum of 1 and 2 is 3

In the above example, we have created a lambda expression to calculate sum of two integers, which is immediately invoked with arguments num1 and num2 :

auto sum = [] (int a, int b) < return a + b; >(num1, num2);
What is the extended syntax of the C++ Lambda Expression?

The extended syntax of the C++ Lambda Expression is:

[capture_list] (parameter_list) mutable -> return_type < // lambda body >

As you can see, this syntax is far more comprehensive compared to the basic syntax we have provided in the beginning of our tutorial.

This is because it consists of all the lambda elements we have discussed up to this point:

  • [capture_list] - captures the variables of the enclosing function
  • (parameter_list) - parameters to be used inside the lambda expression
  • mutable - allows variables captured by value to be modified inside the lambda
  • return_type - explicitly defines the return type of the lambda expression