The purpose of this section is to introduce the basic functionality of the library. There are quite a lot of exceptions and special cases, but discussion of them is postponed until later sections.
In this section we give basic examples of using BLL lambda expressions in STL algorithm invocations.
We start with some simple expressions and work up.
First, we initialize the elements of a container, say, a list<int> v(10); for_each(v.begin(), v.end(), _1 = 1);
The expression
Next, we create a container of pointers and make them point to the elements in the first container vector<int*> vp(10); transform(v.begin(), v.end(), vp.begin(), &_1);
The expression
The next code fragment changes the values in int foo(int); for_each(v.begin(), v.end(), _1 = bind(foo, _1));
The next step is to sort the elements of sort(vp.begin(), vp.end(), *_1 > *_2);
In this call to
Finally, the following for_each(vp.begin(), vp.end(), cout << *_1 << '\n'); Note that a normal (non-lambda) expression as subexpression of a lambda expression is evaluated immediately. This may cause surprises. For instance, if the previous example is rewritten as for_each(vp.begin(), vp.end(), cout << '\n' << *_1);
the subexpression for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1); These functions are described more thoroughly in the section called “Delaying constants and variables”
During the invocation of a lambda functor, the actual arguments are substituted for the placeholders.
The placeholders do not dictate the type of these actual arguments.
The basic rule is that a lambda function can be called with arguments of any types, as long as the lambda expression with substitutions performed is a valid C++ expression.
As an example, the expression
C++ lacks a mechanism to query a type of an expression. However, this precise mechanism is crucial for the implementation of C++ lambda expressions. Consequently, BLL includes a somewhat complex type deduction system which uses a set of traits classes for deducing the resulting type of lambda functions. It handles expressions where the operands are of built-in types and many of the expressions with operands of standard library types. Many of the user defined types are covered as well, particularly if the user defined operators obey normal conventions in defining the return types. There are, however, cases when the return type cannot be deduced. For example, suppose you have defined: C operator+(A, B); The following lambda function invocation fails, since the return type cannot be deduced: A a; B b; (_1 + _2)(a, b);
There are two alternative solutions to this.
The first is to extend the BLL type deduction system to cover your own types (see the section called “Extending return type deduction system”).
The second is to use a special lambda expression ( A a; B b; ret<C>(_1 + _2)(a, b);
For bind expressions, the return type can be defined as a template argument of the bind function as well: bind<int>(foo, _1, _2);
A general restriction for the actual arguments is that they cannot be non-const rvalues. For example: int i = 1; int j = 2; (_1 + _2)(i, j); // ok (_1 + _2)(1, 2); // error (!) This restriction is not as bad as it may look. Since the lambda functors are most often called inside STL-algorithms, the arguments originate from dereferencing iterators and the dereferencing operators seldom return rvalues. And for the cases where they do, there are workarounds discussed in the section called “Rvalues as actual arguments to lambda functors”. By default, temporary const copies of the bound arguments are stored in the lambda functor. This means that the value of a bound argument is fixed at the time of the creation of the lambda function and remains constant during the lifetime of the lambda function object. For example: int i = 1; (_1 = 2, _1 + i)(i);
The comma operator is overloaded to combine lambda expressions into a sequence;
the resulting unary lambda functor first assigns 2 to its argument,
then adds the value of As said, this is the default behavior for which there are exceptions. The exact rules are as follows:
[1]
Strictly taken, the C++ standard defines |