Have an amazing solution built in RAD Studio? Let us know. Looking for discounts? Visit our Special Offers page!
C++Code

The Advanced Guide To Lambda Expression In C++ Software

lambdaexpression

What is a Lambda Expression?

A Lambda Expression defines an anonymous function or a closure at the point where it is used. You can think of a lambda expression as an unnamed function (that’s why it’s called “anonymous”). Lambda expressions help make your C++ software code cleaner, more concise, and allow you to see behavior inline where it’s defined instead of referring to an external method, like a function.

Lambda Expressions are an expression that returns a function object. Lambda expressions are widely used in C++ as well as the C#, Groovy, Java, Python, Ruby languages too.

Where does the name Lambda Expression come from?

The Greek letter Lambda ( λ ) refers to an anonymous function – a function without a name so we use the word “lambda” instead.

A Lambda Expression is assignable to a variable whose data type is usually auto and defines a function object.

Syntax for a lambda expression consists of specific punctuation with = [ ] ( ) { … } series. 

The Advanced Guide To Lambda Expression In C++ Software. A diagram of a Lamda Expression

Lambda expressions are one example of modern C++ language features. The aim of this article is to provide information about lambda expressions, parts of the expressions, and how they can be used while writing code.

What is the syntax of the Lambda Expression?

The syntax for a lambda expression consists of specific punctuation with = [ ] ( ) { ... } series. 

The basic syntax of a Lambda Expression is;

The basic syntax of Lambda Expression in C++20 version is;

Here;

  • Datatype is its type like int, float, class, etc. and mostly auto term is used
  • Lambda Expression is a definition by the user
  • Capture Clause has variables that are visible in the body, capture can happen by value or reference and it can be empty
  • Parameter List can be empty or omitted
  • Return Type is a data type returned by the body, optional, normally deduced
  • Body contains the programming statements to execute and it can be empty

Now lets see each of them.

What other parts of Lambda Expression syntax are there?

The Lambda Expression’s Datatype

Datatype is the data type of the lambda expression which is its type like int, float etc. In modern C++, mostly auto term is used.

Lambda Expression 

It is an expression, a definition by the user. It is used like a class name or method name.

The Lambda Expression’s capture clause

Capture clauses are used to instruct the compiler to capture the variables visible in scope around where the lambda is declared, either by copy or by reference, to be available for use inside the lambda method body. Capture clauses can be used in different ways to specify the requirements of functions.

The capture clause is the first part of a lambda, in square brackets [].

Here are a few ways to declare capture clauses:

  1. [ ] : Empty Capture. It means that nothing should be captured. Lambda Expression can be written as auto L= [ ] ( ) { };
  2. [ = ] : Capture Value in Definition. It specifies that all variables used in the function’s definition should be captured by value. It makes capture by value the default capture type. Lambda Expression can be written as auto L= [ = ] ( ) { };
  3. [ & ] : Capture Value in Usage. It specifies that all variables used in the function’s definition should be captured by reference. It makes capture by reference the default capture type. Lambda Expression can be written as auto L= [ & ] ( ) { };
  4. [*this] : Capturing *this was introduced in C++11. Its purpose is to either capture the copy of the current object, or capture the object itself. Capturing [*this] by value was introduced in C++17. Capturing [*this] by value is important in a scenario where a lambda expression is asynchronously dispatched from a non-static member function. The pointer might not be valid when the function runs. For that reason, it is important to be able to capture *this by value. You can read more about the new feature here: Lambda Capture of *this by Value as [=,*this]
  5. Multiple Capture. Both [=] and [&] can be used together in one capture clause. For example, [=, &var] specifies that all variables should be captured by copy but variable “var” should be captured by reference.
    Some capture clause definitions result in errors due to redundancy. For example, a capture clause like [&, &var] is problematic since we already specified that all variables should be captured by reference and then re-specified that var should be captured by reference.    
  6. Capture by Copy. Similarly, you can capture all variables by reference and specify particular variables to capture by copy. For example, [&, var] specifies that all variables should be captured by reference but variable “var” should be captured by copy.  

Lambda Expression parameters

The parameter list of a lambda is just like the parameter list of any other method: a set of parameters inside braces (). Input parameters in a lambda expression can be listed while defining lambda expressions but are not required.  

The Lambda Expression’s return Type

Often the return type does not need to be specified because it can be deduced by the compiler. If you have a single return statement, the compiler can easily deduce the return type. For more complex lambdas you may need or choose to specify it explicitly.

The Lambda Expression’s Body

The body of a lambda expression simply contains the code, the same as a normal function. It is defined between { and } characters.

What are the different ways of writing lambda expressions?

We have added a couple of snippets of lambda expressions using Embarcadero’s C++Builder.

1. [ Captures ] ( Params ) -> ReturnType { Body };

In this method, we are using a capture clause, specifying some parameters, as well as the return type.

The Advanced Guide To Lambda Expression In C++ Software. A diagram of Lambda Expression syntax.

Sample code:

What this code means is that all variables should be available copied by value and the return type of the function is int. The statements enclosed within the curly braces represent the body of the function: note that the method both uses a variable outside the lambda (value, captured by copy, so available as a const value) and a normal parameter (a)

For this lambda the compiler could deduce what the return type is, but we’ve specified it anyway as int.

2. [ Captures ] ( Params ) { Body };

In this method, we are using a capture clause, and specifying some parameters. The return type should be deduced.

The Advanced Guide To Lambda Expression In C++ Software. More explanation of how Lambda Expression syntax works.

Sample code:

What this means is that all variables should be available by reference (meaning they can be written back to) and the return type of the function should be deduced. The statements enclosed within the curly braces represent the body of the function.

Normally, captured variables are const value variables. They are copies and cannot be modified. Here, since value is captured by reference, you can modify the value of “value” from within the lambda.

3. [ Captures ] { Body }; 

In this method, we are using a capture clause, and have excluded parameters. The return type should be deduced.

The Advanced Guide To Lambda Expression In C++ Software. A diagram of the capture syntax of a C++ Lambda Expression

Sample code:

Lambda expressions can also be written by only specifying the capture clause and defining the body of the function. When the return type is not specified, it will be deduced.

What changes to Lambda Expressions were made in C++17?

Updates to several features were made in C++17. Some of the changes made to lambda expressions in C++17 include:

  • Introduction of Constexpr Lambda Expressions: Lambda expressions can now be declared as constexpr. The constexpr keyword can be used to specify that an expression should be executed at compile time. Note that the lambda expression will need to follow certain rules if it is declared as constexpr. If an expression is declared as constexpr, the expression’s body should not contain code that is not constexpr. For example, memory should not be allocated dynamically.
  • Capture of [*this] in lambda expressions: Capture of [*this] by value in lambda expressions was introduced in C++17. Prior to C++17, this functionality was not allowed and so one would need to capture it by creating a copy (which is prone to errors).

In conclusion, lambda expressions provide a neat and concise alternative to writing functions. They can be declared in different ways based on users’ requirements by making use of capture clauses and parameters (which are optional). Additionally, return types can be deduced and lambda expressions can be declared as constexpr.

What are some examples of Lambda Expressions?

Now let’s see more syntax examples. We will define a lambda expression to combine datatypes;

This can be used on any datatypes as given below;

In modern C++ software, we can use UnicodeString in C++ Builder VCL or FMX projects. This code will support worldwide languages. Here below we used the Memo component as an output;

Is there a full example of C++ software Lambda Expression?

This is a full example about the lambda expression, it has 3 different ways of usage. It is also good to understand auto

Lambda Expressions have some advantages and disadvantages, now lets see them.

What are the pros of using a C++ Lambda Expression?

Lambda expressions are lightweight, nameless functions that can be defined just-in-place where they are used. Lambdas expression feature is not a specific-purpose feature like functional programming etc. Lambda expressions allow you to specify function arguments as lambdas beside C-like functions and functors. Unless you need a function available in more than one place, you’ll feel more comfortable using lambdas as arguments of STL components. Because of their features, Lambda Expressions have some advantages;

  • Lambdas are cheap in memory and CPU usage. The cost of a lambda expression is never greater than the cost of an equivalent class or function.
  • They are some like identical to using a class. Their assembly output is identical to using a class
  • Lambdas allocate on the stack, not heap, this may an advantage in some cases
  • We don’t need to capture static variables when using Lambdas
  • We can return a lambda. We can use std::function or similar
  • In Lambda Expression, captured variables are immutable by default
  • Copying a lambda expression, will copy its state
  • Capturing this in Lambda Expression is not a special case
  • Lambda Expressions are also cheap, If you do capture a variable. The cost is the same as constructing an object and calling a function directly on it, with no virtual look-ups.

What are the cons of using a Lambda Expression in C++ software?

Since the lambda expressions has been introduced in C++11 standards (2011) – as it that allow you to write an inline, anonymous functor to replace the struct f – still it is not popular in C++ usage among the developers. I try to list some of the reasons, and its disadvantages below,

  • Developers find Lambda expressions are complex to use
  • Hard to remember its syntax. Developers think its syntax is confusing, its notations too.
  • Hard to understand what is behind the lambda definition (in a struct way or in assembler programming)
  • New developers may get difficulties to adopt to their new code lines including those lambda definitions
  • Developers may mistake ‘=’ and ‘&’ capture symbols. In some cases, detecting this problem may take a lot of time. These kind of problems can be found by variable changes in steps of debugging only. ( Note that & symbol in capture points the address of variable, means value of variable in usage; = symbol in capture points the exact value of variable in definition)
  • Global and local usage of lambda definitions with capture types may have errors in wrong usages
  • Lambdas allocate on the stack, not heap, this may be disadvantage in some cases
  • If a developer doesn’t capture any variables, Lambda Expressions are literally like a function call, which means they are ‘cheaper’ (efficient) in this type.
  • There is a common misconception about captures that some developers may think [=] and [&] capture all surrounding variables. Actually this is wrong ! They only capture every variable that is used in the function definition, and no more. Developers should explicitly name each captured variable however.
  • If a Lambda Expression will generate a class, it will be as expensive (in terms of efficiency) as creating an equivalent class that holds the same number of variables as you capture. If you capture the more variables (particularly by value), the larger your generated functor class, and the more expensive your use of a lambda will be. In addition, if you capture by reference generally, this will be no more than a few pointers.

Find out more about Lambda Expressions in the Embarcadero DocWiki.

cbuilder_11_512x5121x-7286189-8695819

C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.

There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise versions of C++ Builder and there is a trial version you can download from here.


What's Coming in Delphi, C++Builder, and RAD Studio 11.2 Alexandria

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.
Start Free Trial   Upgrade Today

   Free Delphi Community Edition   Free C++Builder Community Edition

About author

Dr. Yilmaz Yoru has 33+ years of coding with more than 30+ programming languages, mostly C++ on Windows, Android, Mac-OS, iOS, Linux, and other operating systems. He was born in 1974, Eskisehir-Turkey. He graduated from the Department of Mechanical Engineering of Eskisehir Osmangazi University in 1997. One year later, he started to work in the same university as an assistant. He received his MSc and Ph.D. degrees from the same department of the same university. Since 2012, he is the founder and CEO of Esenja LLC Company. Some of his interests are Programming, Thermodynamics, Fluid Mechanics, and Artificial Intelligence. He also likes the graphical 2D & 3D design and high-end innovations. He has married, and he is a father of a son.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

IN THE ARTICLES