mirror of
https://github.com/boostorg/lambda.git
synced 2026-01-22 05:12:51 +00:00
214 lines
12 KiB
HTML
214 lines
12 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>4. Using the library</title><meta name="generator" content="DocBook XSL Stylesheets V1.48"><link rel="home" href="index.html" title="
|
||
C++ BOOST
|
||
|
||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||
C++ BOOST
|
||
|
||
The Boost Lambda Library"><link rel="previous" href="ar01s03.html" title="3. Introduction"><link rel="next" href="ar01s05.html" title="5. Lambda expressions in details"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4. Using the library</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:using_library"></a>4. Using the library</h2></div></div><p>
|
||
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.
|
||
|
||
|
||
</p><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:introductory_examples"></a>4.1. Introductory Examples</h3></div></div><p>
|
||
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 <tt>list</tt>, to the value <tt>1</tt>:
|
||
|
||
|
||
<pre class="programlisting">
|
||
list<int> v(10);
|
||
for_each(v.begin(), v.end(), _1 = 1);</pre>
|
||
|
||
The expression <tt>_1 = 1</tt> creates a lambda functor which assigns the value <tt>1</tt> to every element in <tt>v</tt>.<sup>[<a name="id2739658" href="#ftn.id2739658">1</a>]</sup>
|
||
</p><p>
|
||
Next, we create a container of pointers and make them point to the elements in the first container <tt>v</tt>:
|
||
|
||
<pre class="programlisting">
|
||
list<int*> vp(10);
|
||
transform(v.begin(), v.end(), vp.begin(), &_1);</pre>
|
||
|
||
The expression <tt>&_1</tt> creates a function object for getting the address of each element in <tt>v</tt>.
|
||
The addresses get assigned to the corresponding elements in <tt>vp</tt>.
|
||
</p><p>
|
||
The next code fragment changes the values in <tt>v</tt>.
|
||
For each element, the function <tt>foo</tt> is called.
|
||
The original value of the element is passed as an argument to <tt>foo</tt>.
|
||
The result of <tt>foo</tt> is assigned back to the element:
|
||
|
||
|
||
<pre class="programlisting">
|
||
int foo(int);
|
||
for_each(v.begin(), v.end(), _1 = bind(foo, _1));</pre>
|
||
</p><p>
|
||
The next step is to sort the elements of <tt>vp</tt>:
|
||
|
||
<pre class="programlisting">sort(vp.begin(), vp.end(), *_1 > *_2);</pre>
|
||
|
||
In this call to <tt>sort</tt>, we are sorting the elements by their contents in descending order.
|
||
</p><p>
|
||
Finally, the following <tt>for_each</tt> call outputs the sorted content of <tt>vp</tt> separated by line breaks:
|
||
|
||
<pre class="programlisting">
|
||
for_each(vp.begin(), vp.end(), cout << *_1 << '\n');
|
||
</pre>
|
||
|
||
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
|
||
<pre class="programlisting">
|
||
for_each(vp.begin(), vp.end(), cout << '\n' << *_1);
|
||
</pre>
|
||
the subexpression <tt>cout << '\n'</tt> is evaluated immediately and the effect is to output a single line break, followed by the elements of <tt>vp</tt>.
|
||
The BLL provides functions <tt>constant</tt> and <tt>var</tt> to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions:
|
||
<pre class="programlisting">
|
||
for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);
|
||
</pre>
|
||
These functions are described more thoroughly in <a href="ar01s05.html#sect:delaying_constants_and_variables" title="5.5. Delaying constants and variables">Section 5.5</a>
|
||
|
||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:parameter_and_return_types"></a>4.2. Parameter and return types of lambda functors</h3></div></div><p>
|
||
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
|
||
<tt>_1 + _2</tt> creates a binary lambda functor.
|
||
It can be called with two objects of any types <tt>A</tt> and <tt>B</tt> for which <tt>operator+(A,B)</tt> is defined (and for which BLL knows the return type of the operator, see below).
|
||
</p><p>
|
||
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.
|
||
</p><p>
|
||
There are, however, cases when the return type cannot be deduced. For example, suppose you have defined:
|
||
|
||
<pre class="programlisting">C operator+(A, B);</pre>
|
||
|
||
The following lambda function invocation fails, since the return type cannot be deduced:
|
||
|
||
<pre class="programlisting">A a; B b; (_1 + _2)(a, b);</pre>
|
||
</p><p>
|
||
There are two alternative solutions to this.
|
||
The first is to extend the BLL type deduction system to cover your own types (see <a href="ar01s06.html#sect:extending_return_type_system" title="6. Extending return type deduction system">Section 6</a>).
|
||
The second is to use a special lambda expression (<tt>ret</tt>) which defines the return type in place (see <a href="ar01s05.html#sect:overriding_deduced_return_type" title="5.4. Overriding the deduced return type">Section 5.4</a>):
|
||
|
||
<pre class="programlisting">A a; B b; ret<C>(_1 + _2)(a, b);</pre>
|
||
</p><p>
|
||
For bind expressions, the return type can be defined as a template argument of the bind function as well:
|
||
<pre class="programlisting">bind<int>(foo, _1, _2);</pre>
|
||
|
||
|
||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:actual_arguments_to_lambda_functors"></a>4.3. About actual arguments to lambda functors</h3></div></div><p>A general restriction for the actual arguments is that they cannot be non-const rvalues.
|
||
For example:
|
||
|
||
<pre class="programlisting">
|
||
int i = 1; int j = 2;
|
||
(_1 + _2)(i, j); // ok
|
||
(_1 + _2)(1, 2); // error (!)
|
||
</pre>
|
||
|
||
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
|
||
<a href="ar01s05.html#sect:rvalues_as_actual_arguments" title="5.9.2. Rvalues as actual arguments to lambda functors">Section 5.9.2</a>.
|
||
|
||
|
||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:storing_bound_arguments"></a>4.4. Storing bound arguments in lambda functions</h3></div></div><p>
|
||
|
||
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:
|
||
|
||
<pre class="programlisting">
|
||
int i = 1;
|
||
(_1 + i)(i = 2);
|
||
</pre>
|
||
|
||
The value of the expression in the last line is 3, not 4.
|
||
|
||
In other words, the lambda expression <tt>_1 + i</tt> creates
|
||
a lambda function <tt>lambda x.x+1</tt> rather than
|
||
<tt>lambda x.x+i</tt>.
|
||
|
||
</p><p>
|
||
|
||
As said, this is the default behavior for which there are exceptions.
|
||
The exact rules are as follows:
|
||
|
||
<div class="itemizedlist"><ul type="disc"><li><p>
|
||
|
||
The programmer can control the storing mechanism with <tt>ref</tt>
|
||
and <tt>cref</tt> wrappers [<a href="bi01.html#cit:boost::ref" title="[ref]">ref</a>].
|
||
|
||
Wrapping an argument with <tt>ref</tt>, or <tt>cref</tt>,
|
||
instructs the library to store the argument as a reference,
|
||
or as a reference to const respectively.
|
||
|
||
For example, if we rewrite the previous example and wrap the variable
|
||
<tt>i</tt> with <tt>ref</tt>,
|
||
we are creating the lambda expression <tt>lambda x.x+i</tt>
|
||
and the value of the expression in the last line will be 4:
|
||
|
||
<pre class="programlisting">
|
||
i = 1;
|
||
(_1 + ref(i))(i = 2);
|
||
</pre>
|
||
|
||
Note that <tt>ref</tt> and <tt>cref</tt> are different
|
||
from <tt>var</tt> and <tt>constant</tt>.
|
||
|
||
While the latter ones create lambda functors, the former do not.
|
||
For example:
|
||
|
||
<pre class="programlisting">
|
||
int i;
|
||
var(i) = 1; // ok
|
||
ref(i) = 1; // not ok, ref(i) is not a lambda functor
|
||
</pre>
|
||
|
||
The functions <tt>ref</tt> and <tt>cref</tt> mostly
|
||
exist for historical reasons,
|
||
and <tt>ref</tt> can always
|
||
be replaced with <tt>var</tt>, and <tt>cref</tt> with
|
||
<tt>constant_ref</tt>.
|
||
See <a href="ar01s05.html#sect:delaying_constants_and_variables" title="5.5. Delaying constants and variables">Section 5.5</a> for details.
|
||
The <tt>ref</tt> and <tt>cref</tt> functions are
|
||
general purpose utility functions in Boost, and hence defined directly
|
||
in the <tt>boost</tt> namespace.
|
||
|
||
</p></li><li><p>
|
||
Array types cannot be copied, they are thus stored as const reference by default.
|
||
</p></li><li><p>
|
||
For some expressions it makes more sense to store the arguments as references.
|
||
|
||
For example, the obvious intention of the lambda expression
|
||
<tt>i += _1</tt> is that calls to the lambda functor affect the
|
||
value of the variable <tt>i</tt>,
|
||
rather than some temporary copy of it.
|
||
|
||
As another example, the streaming operators take their leftmost argument
|
||
as non-const references.
|
||
|
||
The exact rules are:
|
||
|
||
<div class="itemizedlist"><ul type="round"><li><p>The left argument of compound assignment operators (<tt>+=</tt>, <tt>*=</tt>, etc.) are stored as references to non-const.</p></li><li><p>If the left argument of <tt><<</tt> or <tt>>></tt> operator is derived from an instantiation of <tt>basic_ostream</tt> or respectively from <tt>basic_istream</tt>, the argument is stored as a reference to non-const.
|
||
For all other types, the argument is stored as a copy.
|
||
</p></li><li><p>
|
||
In pointer arithmetic expressions, non-const array types are stored as non-const references.
|
||
This is to prevent pointer arithmetic making non-const arrays const.
|
||
|
||
</p></li></ul></div>
|
||
|
||
</p></li></ul></div>
|
||
</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id2739658" href="#id2739658">1</a>] </sup>
|
||
Strictly taken, the C++ standard defines <tt>for_each</tt> as a <span class="emphasis"><i>non-modifying sequence operation</i></span>, and the function object passed to <tt>for_each</tt> should not modify its argument.
|
||
The requirements for the arguments of <tt>for_each</tt> are unnecessary strict, since as long as the iterators are <span class="emphasis"><i>mutable</i></span>, <tt>for_each</tt> accepts a function object that can have side-effects on their argument.
|
||
Nevertheless, it is straightforward to provide another function template with the functionality of<tt>std::for_each</tt> but more fine-grained requirements for its arguments.
|
||
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3. Introduction </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 5. Lambda expressions in details</td></tr></table></div></body></html>
|