Channels ▼
RSS

C/C++

Lambdas in C++11


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.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video