1. Home
C++ Tutorial

Explore C++ Tutorials: Exploring the World of C++ Programming

Discover comprehensive C++ tutorials designed for beginners and advanced programmers alike. Enhance your coding skills with step-by-step guides and practical examples.

  • 77 Lessons
  • 15 Hours
right-top-arrow
11

C++ Lambda: The Complete Guide

Updated on 20/09/2024421 Views

C++ lambdas are like ants of the programming world: small, powerful, and perfect for specific tasks. C++ lambda lets us write clean, functional code without the overhead of traditional functions.

Let us learn about C++ lambda expression and how we can practically use it for working with complex code. We will cover the C++ lambda function and its various applications in detail.

What is a C++ Lambda Expression?

Lambda expressions, introduced in C++11, are anonymous functions defined inline within our code. They eliminate the need for separate function definitions, offering a concise and convenient way to create small, specialized functions.

Benefits of Lambda Expressions

Here are the benefits of C++ lambda:

  • Concise syntax: Lambdas allow us to define functions directly where they are used, reducing code verbosity and improving readability.
  • Improved readability: By keeping related logic close together, lambdas can enhance code comprehension, especially for short functions used within algorithms or as callbacks.
  • Functional programming capabilities: Lambdas play a crucial role in functional programming paradigms within C++. They enable the creation of functions that can be treated as values, promoting code composability and expressiveness.

Syntax of C++ Lambda Expression

The basic syntax of a lambda expression can be broken down into the following  four components:

  1. [capture]: The capture list (enclosed in square brackets) is an optional section that specifies variables from the surrounding scope that the lambda expression can access. These variables are captured by value or by reference depending on the declaration within the capture list.
  2. (parameters): Similar to regular functions, lambdas can take zero or more parameters enclosed in parentheses. These parameters are passed to the lambda body for processing.
  3. -> return_type: The optional return type declaration specifies the data type of the value returned by the lambda expression. If not explicitly declared, the return type defaults to void.
  4. { body }: The function body, enclosed in curly braces, contains the statements that define the lambda's functionality. This is where the actual code executed by the lambda resides.

Syntax example:

// Sort a vector of integers in descending order using a lambda expression

std::vector<int> numbers = {3, 1, 4, 5, 2};

std::sort(numbers.begin(), numbers.end(), 

  [](int a, int b) { return a > b; }  // Lambda expression as comparison function

);

In the above cpp lambda example, the lambda expression [](int a, int b) { return a > b; } acts as a comparison function for the std::sort algorithm. It takes two integer parameters a and b and returns true if a is greater than b. This allows the std::sort function to sort the numbers vector in descending order.

Note: The capture list is empty ([]) as the lambda doesn't need to access any external variables.

Capturing Variables

The capture list in a lambda expression plays a critical role in determining how variables from the surrounding scope are accessed within the lambda's body. Let us explore the two primary approaches: capturing by value and capturing by reference.

Note: We should use capture by value when we don't intend to modify the original variable and want to isolate the lambda's behavior. It also avoids potential issues with dangling references (references to variables that no longer exist). When it comes to capture by reference, we should use it when we need to modify the original variable from within the lambda. However, be cautious of dangling references if the original variable might go out of scope before the lambda is executed.

1. Capturing by Value (Copies)

When a variable is captured by value in the capture list, a copy of the variable's current value is created and stored within the lambda's local scope. Any modifications made to the captured variable inside the lambda's body will only affect the copy, not the original variable in the surrounding scope.

Scenario:

int x = 5;

[x] {  // Capture x by value

  x = 10;  // Modification affects the copy within the lambda

  std::cout << "Inside lambda: x = " << x << std::endl;

};

std::cout << "Outside lambda: x = " << x << std::endl;

Output:

Inside lambda: x = 10

Outside lambda: x = 5

In the above C++ lambda example, the variable x with the value 5 is captured by value. Inside the lambda, the assignment x = 10 modifies the copy of x within the lambda's scope, leaving the original x with the value 5 unchanged outside the lambda.

2. Capturing by Reference

Capturing a variable by reference in the capture list creates a reference to the original variable within the lambda's body. Any modifications made to the captured reference will directly affect the original variable in the surrounding scope.

Scenario:

int y = 5;

[&y] {  // Capture y by reference

  y = 10;  // Modification affects the original variable through the reference

  std::cout << "Inside lambda: y = " << y << std::endl;

};

std::cout << "Outside lambda: y = " << y << std::endl;

Output:

Inside lambda: y = 10

Outside lambda: y = 10

Here, the variable y is captured by reference using &y. Inside the lambda, modifying y through the reference directly changes the original y in the surrounding scope, reflected in the output.

C++ Lambda Working Example: Sorting With a Lambda

This cpp lambda example sorts a vector of strings in ascending order based on their length:

Sorting with lambda

Code:

#include <vector>

#include <algorithm>

#include <string>

int main() {

  std::vector<std::string> names = {"Alice", "Bob", "Charlie", "David"};

  // Sort using a lambda expression as comparison function

  std::sort(names.begin(), names.end(), 

    [](const std::string& a, const std::string& b) { return a.length() < b.length(); }

  );

  for (const std::string& name : names) {

    std::cout << name << " ";

  }

  std::cout << std::endl;

  return 0;

}

The lambda expression [](const std::string& a, const std::string& b) { return a.length() < b.length(); } compares the lengths of two strings (a and b). The std::sort function uses this lambda to sort the names vector in ascending order based on string length.

If you wish to learn how to code in C++, you can check out upGrad’s software engineering courses.

C++ Lambda Parameters

Just like regular functions, lambdas can take zero or more parameters to customize their behavior. The lambda syntax allows us to define parameters within the parentheses following the capture list (if present). These parameters act as arguments that we can pass values to when executing the lambda.

  • Example: Adding Two Numbers

// Lambda with two parameters

auto add = [](int x, int y) { return x + y; };

int result = add(5, 3); // Pass arguments during execution

std::cout << "Sum of 5 and 3: " << result << std::endl;

In the above C++ lambda example, the lambda add takes two integer parameters x and y. Inside the lambda body, these parameters are used to calculate the sum, which is then returned. When calling the lambda with add(5, 3), the values 5 and 3 are passed as arguments, and the result is stored in the result variable.

Multiple Parameters

Lambdas can handle multiple parameters, allowing us to create more versatile functions. The order of parameter passing must match the order of parameter declaration in the lambda for proper execution.

Example:

// Lambda with three parameters for area calculation

auto calculateArea = [](int length, int width, bool isSquare = true) {

  if (isSquare) {

    return length * length;

  } else {

    return length * width;

  }

};

int rectangleArea = calculateArea(10, 5);

int squareArea = calculateArea(5); // Uses default argument for isSquare

std::cout << "Rectangle area: " << rectangleArea << std::endl;

std::cout << "Square area: " << squareArea << std::endl;

This example showcases a lambda calculateArea that takes three parameters: length, width, and an optional isSquare (defaulting to true). The lambda calculates the area based on whether it's a square (using only length) or a rectangle (using both length and width).

Lambda Function Body

The cpp lambda function body, enclosed in curly braces {}, is where the magic happens. It defines the code that the lambda executes when called. This section explores how lambdas handle the body and how captured variables interact within it.

Simple Statements vs. Code Blocks

Lambdas offer flexibility in defining their body. We can have:

  1. Single expression: For simple operations, the lambda body can be a single expression. This expression's result becomes the return value of the lambda.

C++ lambda function example:

// Lambda squaring a number

auto square = [](int x) { return x * x; };

int result = square(4); // Single expression body

std::cout << "Square of 4: " << result << std::endl;

  1. Code block: For more complex logic, the lambda body can be a code block enclosed in curly braces {}. This allows for multi-line statements, conditional logic, and loops.

C++ lambda function example:

// Lambda checking if a number is even

auto isEven = [](int num) {

  if (num % 2 == 0) {

    return true;

  } else {

    return false;

  }

};

if (isEven(10)) {

  std::cout << "10 is even." << std::endl;

} else {

  std::cout << "10 is odd." << std::endl;

}

Accessing Captured Variables

Captured variables, declared in the capture list, are accessible within the lambda body. However, their behavior depends on how they were captured. By understanding the capture method (by value or by reference), we can ensure the intended behavior of our C++ lambda functions.

  1. Captured by value: When a variable is captured by value, a copy of its value is stored within the lambda's scope. Any modifications made to the captured variable inside the lambda only affect the copy, not the original variable in the surrounding scope.

C++ lambda function example:

int x = 5;

[x] {  // Capture x by value

  x = 10;  // Modification affects the copy within the lambda

  std::cout << "Inside lambda: x = " << x << std::endl;

};

std::cout << "Outside lambda: x = " << x << std::endl;

  1. Captured by reference: When a variable is captured by reference using &, the lambda obtains a reference to the original variable in the surrounding scope. Modifications made through this reference directly affect the original variable.

C++ lambda function example:

int y = 5;

[&y] {  // Capture y by reference

  y = 10;  // Modification affects the original variable through the reference

  std::cout << "Inside lambda: y = " << y << std::endl;

};

std::cout << "Outside lambda: y = " << y << std::endl;

More C++ Lambda Examples and Practical Applications

Let us look at two more practical applications of C++ lambda to understand lambda better.

Event Handling with a Lambda

This example demonstrates using a lambda as a callback function for a button click event:

Event handling with a lambda

Code:

#include <iostream>

void onButtonClick() {

  std::cout << "Button clicked!" << std::endl;

}

int main() {

  // Simulate a button click event

  onButtonClick();  // Can be replaced with actual button click logic

  // Define a lambda as a callback

  auto handleClick = []() {

    std::cout << "Button clicked using lambda!" << std::endl;

  };

  // Simulate another button click and call the lambda callback

  handleClick();

  return 0;

}

The onButtonClick function simulates a button click event. The handleClick lambda is defined inline and assigned to a variable. When called, it executes the code within its body, printing a message indicating a button click using a lambda.

Iterating with for_each and a Lambda

This C++ lambda example iterates over a list of numbers and calculates their squares using a lambda:

Iterating with for_each and a lambda

Code:

#include <iostream>

#include <vector>

#include <algorithm>

int main() {

  std::vector<int> numbers = {1, 2, 3, 4, 5};

  // Iterate and print squares using for_each and a lambda

  std::for_each(numbers.begin(), numbers.end(), 

    [](int num) { std::cout << num * num << " "; }

  );

  std::cout << std::endl;

  return 0;

}

The std::for_each algorithm iterates over the numbers vector. For each element (num), the lambda expression [](int num) { std::cout << num * num << " "; } is executed, calculating and printing the square of the current number.

Final Tips

By mastering C++ lambdas, you will be equipped to write more expressive, efficient, and readable code. Explore the various applications we discussed, from sorting algorithms to custom operations. Remember, lambdas are a powerful tool, but we must use them wisely.

You are now ready to go forth and conquer complex code with the power of lambdas in your C++ arsenal. If you wish to learn programming languages such as C++, you can check out upGrad’s computer science programs such as the Master’s in Computer Science Program.

Frequently Asked Questions

  1. What is a C++ lambda?

A C++ lambda is a short anonymous function for concise code.

  1. When should I use lambda in C++?

Use lambdas for small functions needed within algorithms or callbacks.

  1. Can you run C++ in lambda?

You cannot run a full C++ program in a lambda, but they can be lightweight.

  1. Are lambdas expensive C++?

Lambdas are generally not expensive in C++.

  1. Where do we use lambda?

They are commonly used in algorithms, event handling, and custom operations. 

  1. Which version of C++ has lambda?

Lambdas were introduced in C++11.

  1. Is lambda inline C++?

Yes, lambdas are inline functions.

  1. What data type is a lambda C++?

A lambda's data type depends on its context and return type.

  1. What is the difference between function and lambda in C++?

Lambdas offer a concise way to define functions compared to regular functions.

  1. Is lambda faster than function?

Lambdas are not inherently faster than functions, but can reduce boilerplate code.

Rohan Vats

Rohan Vats

Software Engineering Manager @ upGrad. Passionate about building large scale web apps with delightful experiences. In pursuit of transforming eng…Read More

Need Guidance? We're Here to Help!
form image
+91
*
By clicking, I accept theT&Cand
Privacy Policy
image
Join 10M+ Learners & Transform Your Career
Learn on a personalised AI-powered platform that offers best-in-class content, live sessions & mentorship from leading industry experts.
right-top-arrowleft-top-arrow

upGrad Learner Support

Talk to our experts. We’re available 24/7.

text

Indian Nationals

1800 210 2020

text

Foreign Nationals

+918045604032

Disclaimer

upGrad does not grant credit; credits are granted, accepted or transferred at the sole discretion of the relevant educational institution offering the diploma or degree. We advise you to enquire further regarding the suitability of this program for your academic, professional requirements and job prospects before enr...