Lambda Expressions

Lambda expressions are anonymous functions introduced in C++11 that allow for the creation of inline functions without the need for a separate function declaration. They provide a concise syntax for defining functions at the point of use, making code more expressive and readable.

Why Lambda Expressions Matter

Lambda expressions offer a powerful way to write more compact and maintainable code by encapsulating functionality directly where it’s needed. They are widely used in modern C++ programming for various tasks such as sorting, filtering, and event handling.

Basic Syntax of Lambda Expressions

Lambda expressions offer a powerful way to write more compact and maintainable code by encapsulating functionality directly where it’s needed. They are widely used in modern C++ programming for various tasks such as sorting, filtering, and event handling.

Capture Clause (Optional)

  • Enclosed in square brackets [].
  • Specifies how variables from the surrounding scope are accessed within the lambda.
  • Empty brackets [] indicate no variable capture.
  • [capture-list]: Variables to capture by value.
  • [&capture-list]: Variables to capture by reference.
  • [=, &capture-list]: Captures all surrounding variables by value and specific variables by reference.

Parameter List (Optional)

  • Enclosed in parentheses ().
  • Lists the parameters the lambda accepts, similar to a regular function.
  • Example: [](int x, double y) takes two parameters, an integer x and a double y.

Mutable Keyword (Optional)

  • Allows modification of captured variables by value within the lambda body.
  • Use with caution to avoid unintended side effects.

Optional Return Type Specification

  • -> return_type: Explicitly specifies the return type.
  • Often inferred by the compiler, but can be helpful for clarity in complex cases.

Lambda Body

  • Enclosed in curly braces {}.
  • Contains the code to be executed when the lambda is called.
  • Can access captured variables and function arguments.

Example: Basic Lambda

				
					#include <iostream>

int main() {
    int x = 5;
    int y = 10;

    // Lambda capturing x by value (copy)
    auto add = [x](int a) {
        return x + a;
    };

    int result = add(y); // result = 15 (5 + 10)
    std::cout << "Result: " << result << std::endl;

    return 0;
}

				
			
				
					// output //
Result: 15
				
			

Explanation:

  • The lambda captures x by value, creating a copy within the lambda’s scope.
  • When called with add(y), the value of y (10) is added to the captured copy of x (5), giving 15.

Capture by Reference

				
					#include <iostream>

int main() {
    int x = 5;

    // Lambda capturing x by reference
    auto increment = [&x]() {
        x++;
    };

    increment(); // Modifies the original x
    std::cout << "x after increment: " << x << std::endl;

    return 0;
}

				
			
				
					// output // 
x after increment: 6
				
			

Explanation:

  • The lambda captures x by reference ([&x]), allowing modification of the original variable in the outer scope.
  • Calling increment() increments the original x to 6.

Capturing All Variables

				
					#include <iostream>

int main() {
    int x = 5;
    int y = 10;

    // Lambda capturing all surrounding variables by value
    auto sum = [=]() {
        return x + y;
    };

    int result = sum(); // result = 15
    std::cout << "Result: " << result << std::endl;

    return 0;
}

				
			
				
					// output // 
Result: 15
				
			

Explanation:

  • [=] captures all surrounding variables (in this case, x and y) by value within the lambda.

Mutable Keyword

				
					#include <iostream>

int main() {
    int x = 5;

    // Lambda capturing x by value (trying to modify it)
    auto increment = [x]() mutable { // mutable keyword allows modification
        x++; // This would normally cause an error if mutable is not used
    };

    increment();
    std::cout << "x after increment: " << x << std::endl;

    return 0;
}

				
			
				
					// output // 
x after increment: 5

				
			

Explanation:

In the provided code, a lambda expression named increment is defined to capture the variable x by value. The mutable keyword is used to indicate that the lambda function can modify its captured variables, even if they were captured by value.

However, despite using the mutable keyword, the lambda function inside increment attempts to modify the captured variable x by incrementing it. This modification would normally be allowed due to the use of mutable.

However, since the lambda function captures x by value, any modifications made to x inside the lambda are local to the lambda’s scope and do not affect the original variable x declared in the main() function. Therefore, the output remains 5, as the original value of x remains unchanged despite the attempted modification inside the lambda function.

Lambda Expressions with Function Pointers

Lambdas excel at working with function pointers, providing a concise way to define anonymous functions on the fly.

				
					#include <iostream>
#include <functional> // for std::function

int add(int x, int y) {
    return x + y;
}

int main() {
    // Function pointer to an add function
    int (*fptr)(int, int) = add;

    // Lambda equivalent to the add function
    std::function<int(int, int)> lambda = [](int x, int y) { return x + y; };

    int result1 = fptr(5, 10); // result1 = 15 (using function pointer)
    int result2 = lambda(3, 8); // result2 = 11 (using lambda)

    std::cout << "Result1 (fptr): " << result1 << std::endl;
    std::cout << "Result2 (lambda): " << result2 << std::endl;

    return 0;
}

				
			
				
					// output //
Result1 (fptr): 15
Result2 (lambda): 11
				
			

Explanation:

  • The code defines a regular add function and a function pointer fptr to it.
  • A lambda is created that captures no variables and takes two integer arguments, similar to add.
  • Both fptr and the lambda are used to perform addition, achieving the same result.

Lambda Expressions with Function Pointers

Lambda expressions are particularly useful with the Standard Template Library (STL) algorithms like std::sort, std::find, and std::for_each. They allow you to define custom sorting criteria, search conditions, or actions to be performed on elements within the algorithm.

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

struct Person {
    std::string name;
    int age;
};

int main() {
    std::vector<Person> people = {
        {"Alice", 30}, {"Bob", 25}, {"Charlie", 35}
    };

    // Sort people by age in descending order
    std::sort(people.begin(), people.end(), [](const Person& p1, const Person& p2) {
        return p1.age > p2.age;
    });

    for (const Person& person : people) {
        std::cout << person.name << " (" << person.age << ")" << std::endl;
    }

    return 0;
}

				
			
				
					// output //
Charlie (35)
Alice (30)
Bob (25)
				
			

Explanation:

  • Person struct is defined to represent names and ages.
  • The std::sort algorithm is used to sort the people vector.
  • A lambda expression is provided as the third argument, defining the sorting criteria.
  • The lambda takes two Person objects as arguments and compares their ages using the greater than operator (>) to achieve descending order.

Lambda Expressions with Captors and Closures

Lambdas can capture variables from their surrounding scope, creating closures. These captured variables persist even after the lambda’s defining scope has ended, as long as the lambda object itself is alive. This allows for interesting use cases where the lambda’s behavior is influenced by the captured state.

				
					#include <iostream>

int main() {
    int startingValue = 5;

    // Lambda capturing startingValue by value
    auto increment = [startingValue]() {
        startingValue++; // Modifies the captured copy of startingValue
        return startingValue;
    };

    int result1 = increment(); // result1 = 6
    int result2 = increment(); // result2 = 7 (captured value persists)

    std::cout << "Result1: " << result1 << std::endl;
    std::cout << "Result2: " << result2 << std::endl;

    return 0;
}

				
			
				
					// output //
Result1: 6
Result2: 7
				
			

Explanation:

  • The startingValue is captured by value ([startingValue]) within the lambda.
  • Calling increment multiple times modifies the captured copy of startingValue, demonstrating closure behavior.

Lambda expressions in C++ provide a concise and powerful way to define inline functions, improving code readability and expressiveness. By capturing variables from the enclosing scope and supporting advanced features like mutable specifier and return type deduction, lambda expressions enable developers to write more flexible and efficient code.Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India