Creating a Lambda Expression
The lambda library enables you to rewrite the previous
for_each() call like this:
for_each(s.begin(),
s.end(),
_1 = '*');
The interesting part is the third argument:
_1 = '*'
This expression creates a lambda functor which writes
* to every character in
s. The syntax seems unusual, so let's see how it works under the hood.
The identifier _1 (an underscore followed by the number one, not a lowercase "L") is called a placeholder. It's the crux of the lambda functor. Within each iteration of for_each(), the functor is called with a different element of s as its actual argument. This actual argument is substituted for the placeholder _1, and the body of the lambda functor is evaluated. Thus, within the first iteration _1 is translated to s[0], then s[1] and so on.
Delaying the Evaluation of Constants and Variables
The following line outputs the elements of a vector. Each element is followed by a space:
vector <int> vi;
vi.push_back(10);
vi.push_back(20);
vi.push_back(30);
for_each(vi.begin(),
vi.end(),
cout << _1 << ' ');
Remember to understand what a lambda functor such as:
std::cout << _1 << ' '
does on each iteration, simply replace the placeholder with an actual argument e.g.,
vi[0]. As expected, this
for_each() call outputs:
10 20 30
Now suppose you want to insert a space before each element. You modify the
for_each() call slightly:
for_each(vi.begin(),
vi.end(),
cout << ' ' <<_1);
This however doesn't work as expected. It outputs a single space followed by the elements of
vi
with no separators. The problem is that none of the operands of:
cout << ' '
is a lambda expression. Therefore, this expression is evaluated immediately, causing a single space to be displayed. In such cases, you need to use the
constant() function for delaying the evaluation of constants:
for_each(vi.begin(),
vi.end(),
cout << constant(' ') << _1);
This time, you get the desired output:
10 20 30
The expression
constant(' ') produces a nullary lambda functor that stores the character constant
' ' and returns a reference to it when called.
A similar problem arises when you use variables in a lambda expression:
int idx = 0;
for_each(vi.begin(),
vi.end(),
cout << ++idx << ':' << _1 << '\n');
Here,
idx is incremented and displayed only once while the rest of the elements are displayed sequentially. To get the desired results, wrap
idx with the function
var():
for_each(vi.begin(),
vi.end(),
cout << ++var(index) << ':' << _1 << '\n');
Now you get the desired output:
1:10
2:20
3:30