C++ Lambda


C++ Lambda Functions: A Complete Guide

C++ Lambda Functions are one of the most powerful features introduced in C++11. They allow you to write anonymous functions directly in your code, making your programs more concise and expressive. Lambdas are particularly useful when you need a short, one-off function that doesn’t justify a separate function declaration or definition.


What are Lambda Functions in C++?

In simple terms, a lambda function is a function that is defined directly in the place where it’s invoked, typically used for short-term tasks. Lambdas are useful for tasks like sorting, filtering, or modifying data without the need for creating separate function definitions.

The syntax of a lambda function is:

[ capture ] ( parameters ) -> return_type { body }
  • Capture: Specifies which variables from the surrounding scope should be accessible inside the lambda.
  • Parameters: The input parameters of the lambda function.
  • Return type: The return type of the lambda (optional; can be inferred).
  • Body: The code that executes when the lambda is called.

Lambda Syntax Breakdown

Let’s break down the syntax of a C++ lambda function and understand each part:

[ capture ] ( parameters ) -> return_type { body }

1. Capture Clause [ capture ]

The capture clause specifies the variables from the outer scope that the lambda will use. The capture clause can be:

  • By value: [x] (captures x by value)
  • By reference: [&x] (captures x by reference)
  • Capture all by value: [=] (captures all variables used in the lambda by value)
  • Capture all by reference: [&] (captures all variables by reference)

2. Parameters ( parameters )

The parameters part of the lambda is like the parameters of a regular function. You can specify the types of parameters or omit them for type inference.

3. Return Type -> return_type

The return type is optional. If not specified, C++ will automatically deduce it. If the return type can’t be deduced automatically, you should specify it.

4. Body { body }

The body of the lambda contains the code that runs when the lambda is called. It can use the captured variables from the outer scope and take parameters, just like a regular function.


Example 1: Basic Lambda Function

Here’s a simple example of using a lambda to add two numbers:

#include <iostream>
using namespace std;

int main() {
    // Define a lambda that adds two integers
    auto add = [](int a, int b) { return a + b; };

    // Use the lambda
    cout << "Sum: " << add(5, 3) << endl;  // Output: Sum: 8

    return 0;
}

Explanation:

  • The lambda add takes two integers a and b and returns their sum.
  • The auto keyword is used to infer the type of the lambda.

Output:

Sum: 8

Example 2: Lambda with Capturing Variables

One of the key features of lambda functions is the ability to capture variables from the surrounding scope. Let's see an example where a lambda captures variables by reference and by value.

#include <iostream>
using namespace std;

int main() {
    int x = 10, y = 20;

    // Capture x by value and y by reference
    auto add = [x, &y](int z) { 
        return x + y + z; 
    };

    // Modify y to demonstrate capturing by reference
    y = 30;

    cout << "Result: " << add(5) << endl;  // Output: Result: 45

    return 0;
}

Explanation:

  • The lambda captures x by value and y by reference.
  • Even though y is modified after the lambda is defined, the lambda uses the updated value of y because it captures by reference.

Output:

Result: 45

Example 3: Lambda with No Parameters

Sometimes, a lambda function doesn't need to take any parameters. Here’s an example of a lambda that just prints a message.

#include <iostream>
using namespace std;

int main() {
    // Define a lambda with no parameters
    auto greet = []() { cout << "Hello, Lambda!" << endl; };

    // Call the lambda
    greet();  // Output: Hello, Lambda!

    return 0;
}

Explanation:

  • The lambda greet takes no parameters and simply prints a message to the console.

Output:

Hello, Lambda!

Example 4: Lambda with Return Type

If the return type of the lambda function is not obvious, you can explicitly specify it using the -> syntax.

#include <iostream>
using namespace std;

int main() {
    // Lambda with an explicit return type
    auto multiply = [](int a, int b) -> int { return a * b; };

    // Call the lambda
    cout << "Product: " << multiply(4, 5) << endl;  // Output: Product: 20

    return 0;
}

Explanation:

  • The lambda multiply takes two integers and returns their product.
  • The return type int is specified explicitly, although C++ could deduce it in this case.

Output:

Product: 20

Example 5: Lambda with Standard Algorithms

Lambdas are commonly used with standard library algorithms to perform tasks like sorting, filtering, or transforming data. Here's an example using std::sort with a lambda to sort a vector in descending order:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    vector<int> vec = {5, 1, 8, 3, 7};

    // Sort the vector in descending order using a lambda
    sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });

    // Print the sorted vector
    for (int num : vec) {
        cout << num << " ";
    }

    return 0;
}

Explanation:

  • The lambda [](int a, int b) { return a > b; } is used as the comparison function for std::sort.
  • This sorts the vector vec in descending order.

Output:

8 7 5 3 1

Advanced Usage of Lambdas

Lambdas in C++ can do much more than simple function-like tasks. Some advanced features include:

  1. Capturing this: You can capture the this pointer inside member functions to access member variables and functions of the object.

    class MyClass {
    public:
        int x = 5;
        void print() {
            auto lambda = [this]() { cout << x << endl; };
            lambda();  // Output: 5
        }
    };
    
  2. Returning lambdas: You can return lambda functions from other functions.
    auto getMultiplier(int factor) {
        return [factor](int x) { return x * factor; };
    }
    
    auto multiplyBy3 = getMultiplier(3);
    cout << multiplyBy3(5);  // Output: 15