Creating a Lambda Expression
The lambda library enables you to rewrite the previous for_each()
call like this:
_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, then s 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;
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
. As expected, this for_each()
10 20 30
Now suppose you want to insert a space before each element. You modify the for_each()
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:
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;
cout << ++idx << ':' << _1 << '\n');
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()
cout << ++var(index) << ':' << _1 << '\n');
Now you get the desired output: