Lambda Expression Syntax

This topic describes the syntax of lambda expressions. It provides an example that demonstrates the structural elements of a lambda expression and how these elements relate to the example.

The following program uses lambda expressions with two STL algorithms: generate_n and for_each. The lambda expression that appears in the call to the generate_n function assigns an element of a vector object to the sum of the previous two elements. The lambda expression that appears in the call to the for_each function prints an element of the same vector object to the console.

// lambda_structure.cpp
// compile with: /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

// The number of elements in the vector.
const int elementCount = 9;

int main() 
{
   // Create a vector object with each element set to 1.
   vector<int> v(elementCount, 1);

   // These variables hold the previous two elements of the vector.
   int x = 1;
   int y = 1;

   // Assign each element in the vector to the sum of the 
   // previous two elements.
   generate_n(v.begin() + 2, elementCount - 2, [=]() mutable throw() -> int {
      
      // Generate current value.
      int n = x + y;

      // Update previous two values.
      x = y;
      y = n;

      return n;
   });

   // Print the contents of the vector.
   for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
   cout << endl;

   // Print the local variables x and y.
   // The values of x and y hold their initial values because 
   // they are captured by value.
   cout << x << " " << y << endl;
}

For more information about the generate_n function, see generate_n. For more information about the for_each function, see for_each.

The following sections describe the grammar of a lambda expression and how each element relates to the preceding example.

Lambda Expression Grammar

The following formal definition shows the grammar, in BNF format, of a lambda expression:

lambda-expression

   : lambda-introducer lambda-parameter-declarationopt compound-statement

lambda-introducer

   : [ lambda-captureopt ]

lambda-capture

   : capture-default

   | capture-list

   | capture-default , capture-list

capture-default

   : &

   | =

capture-list

   : capture

   | capture-list , capture

capture

   : identifier

   | & identifier

   | this

lambda-parameter-declaration

   : ( lambda-parameter-declaration-listopt ) mutable-specificationopt exception-specificationopt lambda-return-type-clauseopt

lambda-parameter-declaration-list

   : lambda-parameter

   | lambda-parameter , lambda-parameter-declaration-list

lambda-parameter

   : decl-specifier-seq declarator

lambda-return-type-clause

   : -> type-id

The following section describes how the grammar relates to the example in the introduction.

Properties of Lambda Expressions

The following illustration maps the grammar to the example.

Structural elements of a lambda expression

The callouts in the illustration are as follows:

  1. lambda-introducer (referred to as capture clause later in this topic)

  2. lambda-parameter-declaration-list (referred to as parameter list later in this topic)

  3. mutable-specification (referred to as mutable specification later in this topic)

  4. exception-specification (referred to as exception specification later in this topic)

  5. lambda-return-type-clause (referred to as return type later in this topic)

  6. compound-statement (referred to as lambda body later in this topic)

The following sections describe the grammar in more detail.

Capture Clause

A lambda expression can access any variable that has automatic storage duration and that can be accessed in the enclosing scope. The capture clause specifies whether the body of the lambda expression accesses variables in the enclosing scope by value or by reference: variables that have the ampersand (&) prefix are accessed by reference and variables that do not have the & prefix are accessed by value. The empty capture clause, [], indicates that the body of the lambda expression accesses no variables in the enclosing scope.

The default capture mode specifies whether capture variables that you do not explicitly specify are captured by value or by reference. You can specify the default capture mode (capture-default in the syntax) by specifying & or = as the first element of the capture clause. The & element specifies that the body of the lambda expression accesses all captured variables by reference unless you explicitly specify otherwise. The = element specifies that the body of the lambda expression accesses all captured variables by value unless you explicitly specify otherwise. For example, if the body of a lambda expression accesses the external variable total by reference and the external variable factor by value, then the following capture clauses are equivalent:

[&total, factor]
[&, factor]
[=, &total]

You can use lambda expressions in the body of a class method. Pass the this pointer to the capture clause to provide access to the methods and data members of the enclosing class. For an example of how to use lambda expression with class methods, see Example: Using a Lambda Expression in a Method in the topic Examples of Lambda Expressions.

Parameter List

The parameter list for a lambda expression resembles the parameter list for a function, with the following exceptions:

  • The parameter list cannot have default arguments.

  • The parameter list cannot have a variable-length argument list.

  • The parameter list cannot have unnamed parameters.

A lambda expression can take another lambda expression as its argument. For more information, see Higher-Order Lambda Expressions in the topic Examples of Lambda Expressions.

The parameter list for a lambda expression is optional. You can omit the parameter list if you do not pass arguments to the lambda expression and you do not provide the mutable-specification, exception-specification, and lambda-return-type-clause elements. The following example shows a lambda expression that omits the parameter list:

// lambda_parameter_list.cpp
int main()
{
   int x = 4;
   int y = 5;
   int z = [=] { return x + y; }();
}

Mutable Specification

The mutable specification part enables the body of a lambda expression to modify variables that are captured by value. The preceding example uses the mutable keyword so that the body of the lambda expression can modify its copies of the external variables x and y, which the lambda expression captures by value. Because the lambda expression captures the variables x and y by value, their values remain 1 after the call to generate_n.

Exception Specification

You can use the throw() exception specification to indicate that the lambda expression does not throw any exceptions. As with regular functions, the Visual C++ compiler generates warning C4297 if a lambda expression declares the throw() exception specification and the lambda body throws an exception, as shown in the following example:

// throw_lambda_expression.cpp
int main() // C4297 expected
{
   []() throw() { throw 5; }();
}

For more information about exception specifications, see Exception Specifications.

Return Type

The return type part of a lambda expression resembles the return type part of an ordinary method or function. However, the return type follows the parameter list and you must include -> before the return type.

You can omit the return type part of a lambda expression if the lambda body contains a single return statement or the lambda expression does not return a value. If the lambda body consists of a single return statement, the compiler deduces the return type from the type of the return expression. Otherwise the compiler deduces the return type to be void.

A lambda expression can produce another lambda expression as its return value. For more information, see Higher-Order Lambda Expressions in the topic Examples of Lambda Expressions.

Lambda Body

The lambda body part of a lambda expression can contain anything that the body of an ordinary method or function can contain. The body of both an ordinary function and a lambda expression can access the following types of variables:

  • Parameters

  • Locally-declared variables

  • Class data members (when declared inside a class)

  • Any variable that has static storage duration (for example, global variables)

In addition, a lambda expression can access variables that it captures from the enclosing scope. A variable is explicitly captured if it appears in the capture clause of the lambda expression. Otherwise, the variable is implicitly captured. The body of the lambda expression uses the default capture mode to access variables that are implicitly captured.

The lambda_parameter_list.cpp example implicitly captures the local variables x and y by value. The following example contains a lambda expression that explicitly captures the variable n by value and implicitly captures the variable m by reference:

// captures_lambda_expression.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

int main()
{
   int m = 0, n = 0;
   [&, n] (int a) mutable { m = ++n + a; }(4);
   cout << m << endl << n << endl;
}

This example prints the following to the console:

5
0

Because the variable n is captured by value, its value remains 0 after the call to the lambda expression.

Although a lambda expression can only capture variables that have automatic storage duration, you can use variables that have static storage duration in the body of a lambda expression. The following example uses the generate function and a lambda expression to assign a value to each element in a vector object. The lambda expression modifies the static variable to generate the value of the next element.

// lambda_static_variable.cpp
// compile with: /c /EHsc
#include <vector>
#include <algorithm>
using namespace std;

void fillVector(vector<int>& v)
{
   // A local static variable.
   static int nextValue = 1;

   // The lambda expression that appears in the following call to
   // the generate function modifies and uses the local static 
   // variable nextValue.
   generate(v.begin(), v.end(), [] { return nextValue++; });
}

For more information about the generate function, see generate.

See Also

Reference

Lambda Expressions in C++

Examples of Lambda Expressions

generate

generate_n

for_each

Exception Specifications

Compiler Warning (level 1) C4297