2
0
mirror of https://github.com/boostorg/lambda.git synced 2026-01-22 05:12:51 +00:00
Files
lambda/doc/ar01s04.html
Jaakko Järvi 10c4216ddc lambda docs to the main trunk
[SVN r13536]
2002-04-19 19:45:20 +00:00

214 lines
12 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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&lt;int&gt; 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&lt;int*&gt; vp(10);
transform(v.begin(), v.end(), vp.begin(), &amp;_1);</pre>
The expression <tt>&amp;_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 &gt; *_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 &lt;&lt; *_1 &lt;&lt; '\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 &lt;&lt; '\n' &lt;&lt; *_1);
</pre>
the subexpression <tt>cout &lt;&lt; '\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 &lt;&lt; constant('\n') &lt;&lt; *_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&lt;C&gt;(_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&lt;int&gt;(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>&lt;&lt;</tt> or <tt>&gt;&gt;</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>