Long-awaited lambda expressions finally came to C++ in the recent C++11 standard. Lambda expressions, also known as closures, lambda functions, function literals, or just lambdas, have their own unique syntax. Developers who moved away from C++ years ago and now are coming back to to the language may be a bit confused by the syntax for the new lambda expressions. In this article, I explain what lambdas are, illustrate how the syntax works, and provide examples of usage of C++11 lambda expressions.
Popular C++ Compilers with Support for Lambda Expressions
The following list shows versions of C++ compilers that support lambda expressions. To use this feature on these products, just make sure that you specify the configuration in each IDE's project settings or command-line compiler option than enables support for the C++11 (formerly C++0x) features.
- GCC: 4.5. You must specify the
-std=c++11
option. - Intel C++ Compiler: 11. Specify the
/Qstd=c++0x
option. - Microsoft Visual C++ 2010 (included in Visual Studio 2010).
Basic Syntax and Elements for Lambda Expressions
A lambda expression is a syntactic shortcut for a functor, so you can use lambda expressions to replace functors. The following line shows the basic syntax and elements for C++11 lambda expressions:
[ captures ] (parameters) -> returnTypesDeclaration { lambdaStatements; }
[ captures ]
: The capture clause, also known as the lambda introducer, specifies which outside variables are available for the lambda function and whether they should be captured by value (copying) or by reference. You will always be able to identify the start of a lambda expression with the presence of the capture clause. An empty capture clause [] means capture nothing, in which case the lambda expression body doesn't access variables in the enclosing scope. I'll dive deeper into capture defaults later.( parameters )
: This is the optional parameters list, also known as the lambda declarator. You can omit the parameters list if you want a function that takes zero arguments.-> returnTypeDeclaration
: This is the return type. Most of the time, compilers can deduce the return type of the lambda expression when you have zero or one return statement. However, if it makes it easier to understand the code, you can specify the return type. There are some differences among compilers regarding the automatic detection of return types when you have more than one return statement because the standard doesn't guarantee the automatic detection of return types. Notice that the specification of the return types is based on the optional return value syntax introduced with C++11, which puts the return value after the function.{ lambdaStatements; }
: This is the lambda body. The statements within the lambda body can access the captured variables and the parameters.
The following lines show a very simple example of the definition of a lambda expression named lambda
that doesn't capture any variable, takes zero arguments, and doesn't have a return statement. Thus, the compiler deduces that the return type is void
and it isn't necessary to specify it. The lambda body just writes the text "Code within a lambda expression"
to the console. Notice that the empty capture clause ([]
) starts the lambda definition. Next, the code calls the previously defined lambda expression without arguments. While this example is trivial, it allows me to introduce some important examples about syntax before moving to useful usage scenarios.
#include <iostream> using namespace std; int main() { auto lambda = []() { cout << "Code within a lambda expression" << endl; }; lambda(); }
As previously explained, some components of the lambda definition are optional, so the following three lines show three equivalent ways of defining the same lambda.
The first line doesn't include the parentheses for the parameters list because the lambda doesn't require arguments:
auto lambda = [] { cout << Code within a lambda expression" << endl; };
The second line includes the parentheses for the parameters list with the void
keyword:
auto lambda = [](void) { cout << Code within a lambda expression" << endl; };
The third line adds void
as the return type to the second line in order to highlight that the lambda doesn't include any return statement:
auto lambda = [](void) -> void { cout << "Code within a lambda expression" << endl; };
The following lines show another very simple example of the definition of a lambda expression named sum
that doesn't capture any variable but takes two int
arguments and returns an int
whose value is the sum of these arguments. Thus, the compiler deduces that the return type is int
and it isn't necessary to specify it. As in the previous example, the empty capture clause ([]
) starts the lambda definition. Then, the code calls the lambda expression two times with different arguments:
#include <iostream> using namespace std; int main() { auto sum = [](int x, int y) { return x + y; }; cout << sum(5, 2) << endl; cout << sum(10, 5) << endl; }
The following line shows an equivalent way of defining the same lambda but in this case specifying the return type.
auto sum = [](int x, int y) -> int { return x + y; };
The following code shows one possible usage of std::count_if
, included in the Standard Templates Library (STL), to count the number of elements in an int
vector that are greater than 5. In this case, the code defines an is_greater_than_5
function that returns a bool
value indicating whether the int
argument is greater than 5. The call to count_if
specifies is_greater_than_5
as the user-defined predicate function object that defines the condition to be satisfied if an element is to be counted. It is possible to simplify the code by using a lambda expression to specify the user-defined predicate function object.
#include <iostream> #include <algorithm> #include <vector> using namespace std; bool is_greater_than_5(int value) { return (value > 5); } int main() { vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 }; auto greater_than_5_count = count_if(numbers.begin(), numbers.end(), is_greater_than_5); cout << "The number of elements greater than 5 is: " << greater_than_5_count << "." << endl; } </p>
The predicate takes single int
argument and returns a bool
value. The good news is that you can use a lambda expression that takes an int
argument and returns a bool
value as the predicate. The following lines shows a new version of the previous code that uses a lambda expression and removes the need of an additional function.
#include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 }; auto great_than_5_count = count_if(numbers.begin(), numbers.end(), [](int x) { return (x > 5); }); cout << "The number of elements greater than 5 is: " << greater_than_5_count << "." << endl; }
An excellent example of how lambda expressions can simplify code is their use with the std::for_each
template function. For example, if you want to use std::for_each
to print the numbers in a numbers vector without the help of a lambda expression, you must either define a function or a function object type. The following code shows an example of the use of for_each
with a function named printnumber
that prints the int
value received as an argument.
#include <iostream> #include <algorithm> #include <vector> using namespace std; void printnumber(int y) { cout << y << endl; } int main() { vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 }; for_each(numbers.begin(), numbers.end(), printnumber); }
The following code shows an example of using for_each
with a function object type named printnumberobject
.
#include <iostream> #include <algorithm> #include <vector> using namespace std; struct printnumberclass { void operator() (int y) { cout << y << endl; } } printnumberobject; int main() { vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 }; for_each(numbers.begin(), numbers.end(), printnumberobject); }
In both cases, you need to read code outside of for_each
to understand what will happen with each number. Of course, both printnumber
and printnumberobject
provide you a very clear idea of what is going to happen with each int
number. However, a more complex example would introduce additional boilerplate code. The following code uses a lambda expression as the third argument of for_each
. Notice that the code is easier to read and the boilerplate is reduced because you don't need to create either a function or a function object type. You just write the code that has to run for each iteration within the lambda expression body. If you have worked with different STL algorithms without lambdas, you will notice immediately how lambdas can reduce boilerplate.
#include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { vector<int> numbers { 1, 2, 3, 4, 5, 10, 15, 20, 25, 35, 45, 50 }; for_each(numbers.begin(), numbers.end(), [] (int y) { cout << y << endl; }); }
Capturing Variables with Lambda Expressions
So far, I've shown simple examples of how to use lambda expressions declared with an empty capture clause ([]
). You can capture variables outside of the lambda expression either by value (copying) or by reference and make them available inside of the lambda body.