16.3 Lambda Expressions

As you’ll see in this chapter, many Standard Library algorithms can receive function pointers as parameters—recall from Section 12.8 that the name of a function is implicitly convertible into a pointer to that function’s code. Before you can pass a function pointer to an algorithm, the corresponding function must be declared.

C++11’s lambda expressions (or simply lambdas) enable you to define anonymous functions where they’re passed to a function. They’re defined locally inside functions and can use and manipulate the local variables of the enclosing function. Figure 16.1 demonstrates the Standard Library’s for_each algorithm, which invokes a function once for each element in a range. The example calls for_each twice, each with a simple lambda:

  • the first is used to display each element in an int array multiplied by 2.

  • the second is used to sum the elements of the int array.

Fig. 16.1 Lambda expressions.

Alternate View

 1   // Fig. 16.1: fig16_01.cpp
 2   // Lambda expressions.
 3   #include <iostream>
 4   #include <array>
 5   #include <algorithm>
 6   #include <iterator>
 7   using namespace std;
 8
 9   int main() {
10      const size_t SIZE{4}; // size of array values
11      array<int, SIZE> values{1, 2, 3, 4}; // initialize values
12      ostream_iterator<int> output{cout, " "};
13
14      cout << "values contains: ";
15      copy(values.cbegin(), values.cend(), output);
16      cout << "
Display each element multiplied by two: ";
17
18      // output each element multiplied by two
19      for_each(values.cbegin(), values.cend(),
20         [](auto i) {cout << i * 2 << " ";});
21
22      // add each element to sum
23      int sum = 0; // initialize sum to zero
24      for_each(values.cbegin(), values.cend(), [&sum](auto i) {sum += i;});
25
26      cout << "
Sum of value's elements is: " << sum << endl; // output sum
27   }

values contains: 1 2 3 4
Display each element multiplied by two: 2 4 6 8
Sum of value's elements is: 10

16.3.1 Algorithm for_each

Lines 19–20 and 24 use the for_each algorithm to call a function that performs a task once for each element of the array values. Like the algorithm copy (introduced in Section 15.3), for_each’s first two arguments represent the range of elements to process. This program processes from values.cbegin() (the position of the array’s first element) up to, but not including, values.cend() (the position one past the array’s last element), so all of the array’s elements are processed. The for_each algorithm’s two iterator arguments must be at least input iterators that point into the same container, so for_each can get values from that container.

The function specified by for_each’s third argument specifies the function to call with each element in the range. The function must have one parameter of the container’s element type. for_each passes the current element’s value as the function’s argument, then the function performs a task using that value. As you’ll see momentarily, this example’s for_each calls each receive as their third argument a lambda representing a function that receives one argument and performs a task with that argument’s value. If the function’s parameter is a non-const reference and the iterators passed to for_each refer to non-const data, the function can modify the element.

16.3.2 Lambda with an Empty Introducer

Line 11 declares and initializes the array of ints named values and line 15 displays its contents. Lines 19–20 call the for_each algorithm to multiply each element of values by 2 and display the result. The third argument (line 20) to for_each


[](auto i) {cout << i * 2 << " ";}

is a lambda expression that performs the multiplication and output.

Lambdas begin with the lambda introducer ([]), followed by a parameter list and function body. A lambda can use local variables from the function in which the lambda is defined. The introducer enables you to specify which, if any, local variables the lambda uses—this is known as capturing the variables. The empty lambda introducer ([]) in line 20 indicates that the lambda does not use any of main’s local variables.

The lambda in line 20 receives one parameter named i. Specifying the parameter’s type as auto enables the compiler to infer the parameter’s type, based on the context in which the lambda appears. In this case, the for_each algorithm calls line 20’s lambda once for each element of the array, passing the element’s value as the lambda’s argument. Since the array contains ints, the compiler infers parameter i’s type as int. Using auto to infer the parameter type is a new C++14 feature of so-called generic lambdas. In C++11 you were required to state each lambda parameter’s explicit type. In this example, the lambda in line 20 is similar to the standalone function


void timesTwo(int i) {
   cout << i * 2 << " ";
}

Had we defined this function, lines 19–20 could have called the for_each algorithm with timesTwo’s function name as the third argument, as in


for_each(values.cbegin(), values.cend(), timesTwo);

16.3.3 Lambda with a Nonempty Introducer—Capturing Local Variables

The second call to the for_each algorithm (line 24) totals array’s elements. The lambda introducer [&sum] in


[&sum](auto i) {sum += i;}

indicates that this lambda expression captures the local variable sum (line 23) by reference. The ampersand (&) indicates that the lambda captures sum by reference and can modify its value. Without the ampersand, sum would be captured by value and the lambda would not modify the local variable outside the lambda expression. The for_each algorithm passes each element of values to the lambda, which adds the value to the sum. Line 26 then displays the sum.

16.3.4 Lambda Return Types

The compiler can infer a lambda’s return type if the body contains a statement of the form


return expression;

Otherwise, the lambda’s return type is void, unless you explicitly specify a return type using C++11’s trailing return type syntax (-> type), as in


[](parameterList) -> type {lambdaBody}

The trailing return type is placed between the parameter list’s closing right parenthesis and the lambda’s body.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset