Home | Projects | Notes > C++ Programming > Stateless Lambda Expressions

Stateless Lambda Expressions

 

C++ Stateless Lambda Expressions

Stateless lambda expressions are lambdas that do not capture any external variables from their surrounding scope. An empty capture list means that the expression captures no information from its environment and only has access to the data passed through its function parameter list.

Simple Stateless Lambda Expressions (No capture lists)

L3: This lambda is invoked with the value 100 passed to its x parameter. Since it is stateless, it captures no information from its surrounding environment. This means it has no access to the x variable defined earlier and only operates on the value explicitly passed to its parameter when it is called.

L4: From the empty capture list, we know that this lambda is stateless, meaning it has no access to the array or its length defined earlier. The only way it can compute the sum of the integers in the array is if both the array and its length are passed as parameters. This is exactly what happens when the lambda is called in L12.

Using Values and References as Lambda Parameters

L1: int x - Value parameter

L2: int &x) - Reference parameter (i.e., alias to the actual parameter; no copy is made)

Using Pointers as Lambda Parameters

Using Arrays and Vectors as Lambda Reference Parameters

Using auto as Lambda Parameter Type Specifiers

This allows the lambda expression to accommodate different types of arguments, making it more flexible and enabling it to work like a generic function. (The auto keyword is the key!)

Note: auto is not an actual type. It's an instruction telling the compiler to deduce the actual type.

Using Lambda Expressions as Function Parameters

L3: Passing a lambda expression to a function as a function object using the standard library's <functional> header. The function foo takes the function object l as a function parameter. void type specifier represents the return type of the function object, and the int type specifier represents the function object's parameter type. (C++14)

L4: Passing a lambda expression to a function as a function pointer. The function foo takes as its parameter a pointer to the function l. (C++14)

L6: In C++20, we can eliminate the need to explicitly declare return and parameter types by using the auto keyword, allowing the compiler to deduce both the parameter types and the return type of the lambda expression.

Returning Lambda Expressions from Functions

Similar to how the lambda expressions are passed to functions, they can be returned as either function objects, function pointers or by using the auto keyword to instruct the compiler to deduce the return type.

L3: Returning a lambda expression as a function object.

L4: Returning a lambda expression as a function pointer. This is an old-style C syntax that has persisted for backward compatibility. In modern C++, it's uncommon to use this approach to return a lambda expression from a function. Instead, it's more typical—and more flexible—to return lambdas either as function objects or by using the auto keyword.

All 3 versions are used the same way:

Examples of why you might want to return a lambda from a function are best illustrated using stateful lambda expressions, which will be discussed in the next section.

Using Lambda Expressions as Function Parameters

L1: A common way of passing lambda expressions to functions since in most cases they're only ever passed once.

L3: If the lambda will be used more than once, it may be beneficial to assign it to a variable so that it can be passed to multiple functions and called independently without having to define the lambda each time.

Using Lambda Expressions as Predicates

A predicate in C++ is a function that takes one or more arguments and returns a boolean value. Naturally, a predicate lambda is a lambda expression that implements this behavior. This is where the true power of lambdas shines—enabling concise, inline logic for filtering, searching, and decision-making in algorithms.

L1: Takes as its parameters an integer vector and a predicate lambda that's passed as a function pointer. In this case, the predicate lambda is used to determine which elements of the integer vector to display.

Predicate lambdas are especially important when working with Standard Template Library (STL) functions and algorithms such as std::sort() or std::for_each(), which often take a predicate as a parameter to customize their behavior.