mirror of
https://github.com/boostorg/lambda.git
synced 2026-01-21 17:02:36 +00:00
2175 lines
115 KiB
HTML
2175 lines
115 KiB
HTML
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>
|
|
C++ BOOST
|
|
|
|
The Boost Lambda Library</title><meta name="generator" content="DocBook XSL Stylesheets V1.48"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="article"><div class="titlepage"><div><h1 class="title"><a name="id2732401"></a>
|
|
<span class="inlinemediaobject"><img src="../../../c++boost.gif" alt="C++ BOOST"></span>
|
|
|
|
The Boost Lambda Library</h1></div><div><p class="copyright">Copyright © 1999-2002 Jaakko Järvi, Gary Powell</p></div><div><div class="legalnotice"><p>
|
|
The Boost Lambda Library is free software; Permission to copy,
|
|
use, modify and distribute this software and its documentation is granted, provided this copyright
|
|
notice appears in all copies.
|
|
</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt>1. <a href="#introduction">In a nutshell</a></dt><dt>2. <a href="#sect:getting_started">Getting Started</a></dt><dd><dl><dt>2.1. <a href="#id2779428">Installing the library</a></dt><dt>2.2. <a href="#id2733541">Conventions used in this document</a></dt></dl></dd><dt>3. <a href="#id2733588">Introduction</a></dt><dd><dl><dt>3.1. <a href="#id2733595">Motivation</a></dt><dt>3.2. <a href="#id2733932">Introduction to lambda expressions</a></dt></dl></dd><dt>4. <a href="#sect:using_library">Using the library</a></dt><dd><dl><dt>4.1. <a href="#sect:introductory_examples">Introductory Examples</a></dt><dt>4.2. <a href="#sect:parameter_and_return_types">Parameter and return types of lambda functors</a></dt><dt>4.3. <a href="#sect:actual_arguments_to_lambda_functors">About actual arguments to lambda functors</a></dt><dt>4.4. <a href="#sect:storing_bound_arguments">Storing bound arguments in lambda functions</a></dt></dl></dd><dt>5. <a href="#sect:lambda_expressions_in_details">Lambda expressions in details</a></dt><dd><dl><dt>5.1. <a href="#sect:placeholders">Placeholders</a></dt><dt>5.2. <a href="#sect:operator_expressions">Operator expressions</a></dt><dt>5.3. <a href="#sect:bind_expressions">Bind expressions</a></dt><dt>5.4. <a href="#sect:overriding_deduced_return_type">Overriding the deduced return type</a></dt><dt>5.5. <a href="#sect:delaying_constants_and_variables">Delaying constants and variables</a></dt><dt>5.6. <a href="#sect:lambda_expressions_for_control_structures">Lambda expressions for control structures</a></dt><dt>5.7. <a href="#sect:exceptions">Exceptions</a></dt><dt>5.8. <a href="#sect:construction_and_destruction">Construction and destruction</a></dt><dt>5.9. <a href="#id2794800">Special lambda expressions</a></dt><dt>5.10. <a href="#id2795373">Casts, sizeof and typeid</a></dt><dt>5.11. <a href="#sect:nested_stl_algorithms">Nesting STL algorithm invocations</a></dt></dl></dd><dt>6. <a href="#sect:extending_return_type_system">Extending return type deduction system</a></dt><dt>7. <a href="#id2796882">Practical considerations</a></dt><dd><dl><dt>7.1. <a href="#id2796888">Performance</a></dt><dt>7.2. <a href="#id2797381">About compiling</a></dt><dt>7.3. <a href="#id2797442">Portability</a></dt></dl></dd><dt>8. <a href="#id2797826">Relation to other Boost libraries</a></dt><dd><dl><dt>8.1. <a href="#id2797834">Boost Function</a></dt><dt>8.2. <a href="#id2797938">Boost Bind</a></dt></dl></dd><dt>9. <a href="#id2798134">Contributors</a></dt><dt>A. <a href="#id2798156">Rationale for some of the design decisions</a></dt><dd><dl><dt>1. <a href="#sect:why_weak_arity">
|
|
Lambda functor arity
|
|
</a></dt></dl></dd><dt><a href="#id2798308">Bibliography</a></dt></dl></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="introduction"></a>1. In a nutshell</h2></div></div><p>
|
|
|
|
The Boost Lambda Library (BLL in the sequel) is a C++ template
|
|
library, which implements form of <span class="emphasis"><i>lambda abstractions</i></span> for C++.
|
|
The term originates from functional programming and lambda calculus, where a lambda abstraction defines an unnamed function.
|
|
The primary motivation for the BLL is to provide flexible and
|
|
convenient means to define unnamed function objects for STL algorithms.
|
|
In explaining what the library is about, a line of code says more than a thousand words; the
|
|
following line outputs the elements of some STL container
|
|
<tt>a</tt> separated by spaces:
|
|
|
|
<pre class="programlisting">for_each(a.begin(), a.end(), std::cout << _1 << ' ');</pre>
|
|
|
|
The expression <tt>std::cout << _1 << ' '</tt> defines a unary function object.
|
|
The variable <tt>_1</tt> is the parameter of this function, a <span class="emphasis"><i>placeholder</i></span> for the actual argument.
|
|
Within each iteration of <tt>for_each</tt>, the function is
|
|
called with an element of <tt>a</tt> as the actual argument.
|
|
This actual argument is substituted for the placeholder, and the ‘body’ of the function is evaluated.
|
|
</p><p>The essence of BLL is letting you define small unnamed function objects, such as the one above, directly on the call site of an STL algorithm.
|
|
</p></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:getting_started"></a>2. Getting Started</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2779428"></a>2.1. Installing the library</h3></div></div><p>
|
|
The library consists of include files only, hence there is no
|
|
installation procedure. The <tt>boost</tt> include directory
|
|
must be on the include path.
|
|
There are a number of include files that give different functionality:
|
|
|
|
|
|
<div class="itemizedlist"><ul type="disc"><li><p>
|
|
<tt>lambda/lambda.hpp</tt> defines lambda expressions for different C++
|
|
operators, see <a href="#sect:operator_expressions" title="5.2. Operator expressions">Section 5.2</a>.
|
|
</p></li><li><p>
|
|
<tt>lambda/bind.hpp</tt> defines <tt>bind</tt> functions for up to 9 arguments, see <a href="#sect:bind_expressions" title="5.3. Bind expressions">Section 5.3</a>.</p></li><li><p>
|
|
<tt>lambda/if.hpp</tt> defines lambda function equivalents for if statements and the conditional operator, see <a href="#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a> (includes <tt>lambda.hpp</tt>).
|
|
</p></li><li><p>
|
|
<tt>lambda/loops.hpp</tt> defines lambda function equivalent for looping constructs, see <a href="#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a>.
|
|
</p></li><li><p>
|
|
<tt>lambda/switch.hpp</tt> defines lambda function equivalent for the switch statement, see <a href="#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a>.
|
|
</p></li><li><p>
|
|
<tt>lambda/construct.hpp</tt> provides tools for writing lambda expressions with constructor, destructor, new and delete invocations, see <a href="#sect:construction_and_destruction" title="5.8. Construction and destruction">Section 5.8</a> (includes <tt>lambda.hpp</tt>).
|
|
</p></li><li><p>
|
|
<tt>lambda/casts.hpp</tt> provides lambda versions of different casts, as well as <tt>sizeof</tt> and <tt>typeid</tt>, see <a href="#sect:cast_expressions" title="5.10.1.
|
|
Cast expressions
|
|
">Section 5.10.1</a>.
|
|
</p></li><li><p>
|
|
<tt>lambda/exceptions.hpp</tt> gives tools for throwing and catching
|
|
exceptions within lambda functions, <a href="#sect:exceptions" title="5.7. Exceptions">Section 5.7</a> (includes
|
|
<tt>lambda.hpp</tt>).
|
|
</p></li><li><p>
|
|
<tt>lambda/algorithm.hpp</tt> and <tt>lambda/numeric.hpp</tt> (cf. standard <tt>algortihm</tt> and <tt>numeric</tt> headers) allow nested STL algorithm invocations, see <a href="#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>.
|
|
</p></li></ul></div>
|
|
|
|
Any other header files in the package are for internal use.
|
|
Additionally, the library depends on two other Boost Libraries, the
|
|
<span class="emphasis"><i>Tuple</i></span> [<a href="#cit:boost::tuple" title="[tuple]">tuple</a>] and the <span class="emphasis"><i>type_traits</i></span> [<a href="#cit:boost::type_traits" title="[type_traits]">type_traits</a>] libraries, and on the <tt>boost/ref.hpp</tt> header.
|
|
</p><p>
|
|
All definitions are placed in the namespace <tt>boost::lambda</tt> and its subnamespaces.
|
|
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2733541"></a>2.2. Conventions used in this document</h3></div></div><p>In most code examples, we omit the namespace prefixes for names in the <tt>std</tt> and <tt>boost::lambda</tt> namespaces.
|
|
Implicit using declarations
|
|
<pre class="programlisting">
|
|
using namespace std;
|
|
using namespace boost::lambda;
|
|
</pre>
|
|
are assumed to be in effect.
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2733588"></a>3. Introduction</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2733595"></a>3.1. Motivation</h3></div></div><p>The Standard Template Library (STL)
|
|
[<a href="#cit:stepanov:94" title="[STL94]">STL94</a>], now part of the C++ Standard Library [<a href="#cit:c++:98" title="[C++98]">C++98</a>], is a generic container and algorithm library.
|
|
Typically STL algorithms operate on container elements via <span class="emphasis"><i>function objects</i></span>. These function objects are passed as arguments to the algorithms.
|
|
</p><p>
|
|
Any C++ construct that can be called with the function call syntax
|
|
is a function object.
|
|
The STL contains predefined function objects for some common cases (such as <tt>plus</tt>, <tt>less</tt> and <tt>not1</tt>).
|
|
As an example, one possible implementation for the standard <tt>plus</tt> template is:
|
|
|
|
<pre class="programlisting">
|
|
template <class T> : public binary_function<T, T, T>
|
|
struct plus {
|
|
T operator()(const T& i, const T& j) const {
|
|
return i + j;
|
|
}
|
|
};
|
|
</pre>
|
|
|
|
The base class <tt>binary_function<T, T, T></tt> contains typedefs for the argument and return types of the function object, which are needed to make the function object <span class="emphasis"><i>adaptable</i></span>.
|
|
</p><p>
|
|
In addition to the basic function object classes, such as the one above,
|
|
the STL contains <span class="emphasis"><i>binder</i></span> templates for creating a unary function object from an adaptable binary function object by fixing one of the arguments to a constant value.
|
|
For example, instead of having to explicitly write a function object class like:
|
|
|
|
<pre class="programlisting">
|
|
class plus_1 {
|
|
int _i;
|
|
public:
|
|
plus_1(const int& i) : _i(i) {}
|
|
int operator()(const int& j) { return _i + j; }
|
|
};
|
|
</pre>
|
|
|
|
the equivalent functionality can be achieved with the <tt>plus</tt> template and one of the binder templates (<tt>bind1st</tt>).
|
|
E.g., the following two expressions create function objects with identical functionalities;
|
|
when invoked, both return the result of adding <tt>1</tt> to the argument of the function object:
|
|
|
|
<pre class="programlisting">
|
|
plus_1(1)
|
|
bind1st(plus<int>(), 1)
|
|
</pre>
|
|
|
|
The subexpression <tt>plus<int>()</tt> in the latter line is a binary function object which computes the sum of two integers, and <tt>bind1st</tt> invokes this function object partially binding the first argument to <tt>1</tt>.
|
|
As an example of using the above function object, the following code adds <tt>1</tt> to each element of some container <tt>a</tt> and outputs the results into the standard output stream <tt>cout</tt>.
|
|
|
|
<pre class="programlisting">
|
|
transform(a.begin(), a.end(), ostream_iterator<int>(cout),
|
|
bind1st(plus<int>(), 1));
|
|
</pre>
|
|
|
|
</p><p>
|
|
To make the binder templates more generally applicable, the STL contains <span class="emphasis"><i>adaptors</i></span> for making
|
|
pointers or references to functions, and pointers to member functions,
|
|
adaptable.
|
|
|
|
Finally, some STL implementations contain function composition operations as
|
|
extensions to the standard [<a href="#cit:sgi:02" title="[SGI02]">SGI02</a>].
|
|
</p><p>
|
|
All these tools aim at one goal: to make it possible to specify
|
|
<span class="emphasis"><i>unnamed functions</i></span> in a call of an STL algorithm,
|
|
in other words, to pass code fragments as an argument to a function.
|
|
|
|
However, this goal is attained only partially.
|
|
The simple example above shows that the definition of unnamed functions
|
|
with the standard tools is cumbersome.
|
|
|
|
Complex expressions involving functors, adaptors, binders and
|
|
function composition operations tend to be difficult to comprehend.
|
|
|
|
In addition to this, there are significant restrictions in applying
|
|
the standard tools. E.g. the standard binders allow only one argument
|
|
of a binary function to be bound; there are no binders for
|
|
3-ary, 4-ary etc. functions.
|
|
</p><p>
|
|
The Boost Lambda Library provides solutions for the problems described above:
|
|
|
|
<div class="itemizedlist"><ul type="disc"><li><p>
|
|
Unnamed functions can be created easily with an intuitive syntax.
|
|
|
|
The above example can be written as:
|
|
|
|
<pre class="programlisting">
|
|
transform(a.begin(), a.end(), ostream_iterator<int>(cout),
|
|
1 + _1);
|
|
</pre>
|
|
|
|
or even more intuitively:
|
|
|
|
<pre class="programlisting">
|
|
for_each(a.begin(), a.end(), cout << (1 + _1));
|
|
</pre>
|
|
</p></li><li><p>
|
|
Most of the restrictions in argument binding are removed,
|
|
arbitrary arguments of practically any C++ function can be bound.
|
|
</p></li><li><p>
|
|
Separate function composition operations are not needed,
|
|
as function composition is supported implicitly.
|
|
|
|
</p></li></ul></div>
|
|
|
|
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2733932"></a>3.2. Introduction to lambda expressions</h3></div></div><p>
|
|
Lambda expression are common in functional programming languages.
|
|
Their syntax varies between languages (and between different forms of lambda calculus), but the basic form of a lambda expressions is:
|
|
|
|
|
|
<pre class="programlisting">
|
|
lambda x<sub>1</sub> ... x<sub>n</sub>.e
|
|
</pre>
|
|
|
|
|
|
A lambda expression defines an unnamed function and consists of:
|
|
<div class="itemizedlist"><ul type="disc"><li><p>
|
|
the parameters of this function: <tt>x<sub>1</sub> ... x<sub>n</sub></tt>.
|
|
|
|
</p></li><li><p>the expression e which computes the value of the function in terms of the parameters <tt>x<sub>1</sub> ... x<sub>n</sub></tt>.
|
|
</p></li></ul></div>
|
|
|
|
A simple example of a lambda expression is
|
|
<pre class="programlisting">
|
|
lambda x y.x+y
|
|
</pre>
|
|
Applying the lambda function means substituting the formal parameters with the actual arguments:
|
|
<pre class="programlisting">
|
|
(lambda x y.x+y) 2 3 = 2 + 3 = 5
|
|
</pre>
|
|
|
|
|
|
</p><p>
|
|
In the C++ version of lambda expressions the <tt>lambda x<sub>1</sub> ... x<sub>n</sub></tt> part is missing and the formal parameters have predefined names.
|
|
In the current version of the library,
|
|
there are three such predefined formal parameters,
|
|
called <span class="emphasis"><i>placeholders</i></span>:
|
|
<tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
|
|
They refer to the first, second and third argument of the function defined
|
|
by the lambda expression.
|
|
|
|
For example, the C++ version of the definition
|
|
<pre class="programlisting">lambda x y.x+y</pre>
|
|
is
|
|
<pre class="programlisting">_1 + _2</pre>
|
|
</p><p>
|
|
Hence, there is no syntactic keyword for C++ lambda expressions.
|
|
The use of a placeholder as an operand implies that the operator invocation is a lambda expression.
|
|
However, this is true only for operator invocations.
|
|
Lambda expressions containing function calls, control structures, casts etc. require special syntactic constructs.
|
|
Most importantly, function calls need to be wrapped inside a <tt>bind</tt> function.
|
|
|
|
As an example, consider the lambda expression:
|
|
|
|
<pre class="programlisting">lambda x y.foo(x,y)</pre>
|
|
|
|
Rather than <tt>foo(_1, _2)</tt>, the C++ counterpart for this expression is:
|
|
|
|
<pre class="programlisting">bind(foo, _1, _2)</pre>
|
|
|
|
We refer to this type of C++ lambda expressions as <span class="emphasis"><i>bind expressions</i></span>.
|
|
</p><p>A lambda expression defines a C++ function object, hence function application syntax is like calling any other function object, for instance: <tt>(_1 + _2)(i, j)</tt>.
|
|
|
|
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:partial_function_application"></a>3.2.1. Partial function application</h4></div></div><p>
|
|
A bind expression is in effect a <span class="emphasis"><i>partial function application</i></span>.
|
|
In partial function application, some of the arguments of a function are bound to fixed values.
|
|
The result is another function, with possibly fewer arguments.
|
|
When called with the unbound arguments, this new function invokes the original function with the merged argument list of bound and unbound arguments.
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:terminology"></a>3.2.2. Terminology</h4></div></div><p>
|
|
A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, <span class="emphasis"><i>a functor</i></span>, when evaluated. We use the name <span class="emphasis"><i>lambda functor</i></span> to refer to such a function object.
|
|
Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor.
|
|
</p></div></div></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="id2729061" href="#ftn.id2729061">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">
|
|
vector<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="#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="#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="#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="#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="#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="#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><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:lambda_expressions_in_details"></a>5. Lambda expressions in details</h2></div></div><p>
|
|
This section describes different categories of lambda expressions in details.
|
|
We devote a separate section for each of the possible forms of a lambda expression.
|
|
|
|
|
|
</p><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:placeholders"></a>5.1. Placeholders</h3></div></div><p>
|
|
The BLL defines three placeholder types: <tt>placeholder1_type</tt>, <tt>placeholder2_type</tt> and <tt>placeholder3_type</tt>.
|
|
BLL has a predefined placeholder variable for each placeholder type: <tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
|
|
However, the user is not forced to use these placeholders.
|
|
It is easy to define placeholders with alternative names.
|
|
This is done by defining new variables of placeholder types.
|
|
For example:
|
|
|
|
<pre class="programlisting">boost::lambda::placeholder1_type X;
|
|
boost::lambda::placeholder2_type Y;
|
|
boost::lambda::placeholder3_type Z;
|
|
</pre>
|
|
|
|
With these variables defined, <tt>X += Y * Z</tt> is equivalent to <tt>_1 += _2 * _3</tt>.
|
|
</p><p>
|
|
The use of placeholders in the lambda expression determines whether the resulting function is nullary, unary, binary or 3-ary.
|
|
The highest placeholder index is decisive. For example:
|
|
|
|
<pre class="programlisting">
|
|
_1 + 5 // unary
|
|
_1 * _1 + _1 // unary
|
|
_1 + _2 // binary
|
|
bind(f, _1, _2, _3) // 3-ary
|
|
_3 + 10 // 3-ary
|
|
</pre>
|
|
|
|
Note that the last line creates a 3-ary function, which adds <tt>10</tt> to its <span class="emphasis"><i>third</i></span> argument.
|
|
The first two arguments are discarded.
|
|
Furthermore, lambda functors only have a minimum arity.
|
|
One can always provide more arguments (up the number of supported placeholders)
|
|
that is really needed.
|
|
The remaining arguments are just discarded.
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int i, j, k;
|
|
_1(i, j, k) // returns i, discards j and k
|
|
(_2 + _2)(i, j, k) // returns j+j, discards i and k
|
|
</pre>
|
|
|
|
See
|
|
<a href="#sect:why_weak_arity" title="1.
|
|
Lambda functor arity
|
|
">Section 1</a> for the design rationale behind this
|
|
functionality.
|
|
|
|
</p><p>
|
|
In addition to these three placeholder types, there is also a fourth placeholder type <tt>placeholderE_type</tt>.
|
|
The use of this placeholder is defined in <a href="#sect:exceptions" title="5.7. Exceptions">Section 5.7</a> describing exception handling in lambda expressions.
|
|
</p><p>When an actual argument is supplied for a placeholder, the parameter passing mode is always by reference.
|
|
This means that any side-effects to the placeholder are reflected to the actual argument.
|
|
For example:
|
|
|
|
|
|
<pre class="programlisting">
|
|
int i = 1;
|
|
(_1 += 2)(i); // i is now 3
|
|
(++_1, cout << _1)(i) // i is now 4, outputs 4
|
|
</pre>
|
|
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:operator_expressions"></a>5.2. Operator expressions</h3></div></div><p>
|
|
The basic rule is that any C++ operator invocation with at least one argument being a lambda expression is itself a lambda expression.
|
|
Almost all overloadable operators are supported.
|
|
For example, the following is a valid lambda expression:
|
|
|
|
<pre class="programlisting">cout << _1, _2[_3] = _1 && false</pre>
|
|
</p><p>
|
|
However, there are some restrictions that originate from the C++ operator overloading rules, and some special cases.
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2730141"></a>5.2.1. Operators that cannot be overloaded</h4></div></div><p>
|
|
Some operators cannot be overloaded at all (<tt>::</tt>, <tt>.</tt>, <tt>.*</tt>).
|
|
For some operators, the requirements on return types prevent them to be overloaded to create lambda functors.
|
|
These operators are <tt>->.</tt>, <tt>-></tt>, <tt>new</tt>, <tt>new[]</tt>, <tt>delete</tt>, <tt>delete[]</tt> and <tt>?:</tt> (the conditional operator).
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:assignment_and_subscript"></a>5.2.2. Assignment and subscript operators</h4></div></div><p>
|
|
These operators must be implemented as class members.
|
|
Consequently, the left operand must be a lambda expression. For example:
|
|
|
|
<pre class="programlisting">
|
|
int i;
|
|
_1 = i; // ok
|
|
i = _1; // not ok. i is not a lambda expression
|
|
</pre>
|
|
|
|
There is a simple solution around this limitation, described in <a href="#sect:delaying_constants_and_variables" title="5.5. Delaying constants and variables">Section 5.5</a>.
|
|
In short,
|
|
the left hand argument can be explicitly turned into a lambda functor by wrapping it with a special <tt>var</tt> function:
|
|
<pre class="programlisting">
|
|
var(i) = _1; // ok
|
|
</pre>
|
|
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:logical_operators"></a>5.2.3. Logical operators</h4></div></div><p>
|
|
Logical operators obey the short-circuiting evaluation rules. For example, in the following code, <tt>i</tt> is never incremented:
|
|
<pre class="programlisting">
|
|
bool flag = true; int i = 0;
|
|
(_1 || ++_2)(flag, i);
|
|
</pre>
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:comma_operator"></a>5.2.4. Comma operator</h4></div></div><p>
|
|
Comma operator is the ‘statement separator’ in lambda expressions.
|
|
Since comma is also the separator between arguments in a function call, extra parenthesis are sometimes needed:
|
|
|
|
<pre class="programlisting">
|
|
for_each(a.begin(), a.end(), (++_1, cout << _1));
|
|
</pre>
|
|
|
|
Without the extra parenthesis around <tt>++_1, cout << _1</tt>, the code would be interpreted as an attempt to call <tt>for_each</tt> with four arguments.
|
|
</p><p>
|
|
The lambda functor created by the comma operator adheres to the C++ rule of always evaluating the left operand before the right one.
|
|
In the above example, each element of <tt>a</tt> is first incremented, then written to the stream.
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_call_operator"></a>5.2.5. Function call operator</h4></div></div><p>
|
|
The function call operators have the effect of evaluating the lambda
|
|
functor.
|
|
Calls with too few arguments lead to a compile time error.
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:member_pointer_operator"></a>5.2.6. Member pointer operator</h4></div></div><p>
|
|
The member pointer operator <tt>operator->*</tt> can be overloaded freely.
|
|
Hence, for user defined types, member pointer operator is no special case.
|
|
The built-in meaning, however, is a somewhat more complicated case.
|
|
The built-in member pointer operator is applied if the left argument is a pointer to an object of some class <tt>A</tt>, and the right hand argument is a pointer to a member of <tt>A</tt>, or a pointer to a member of a class from which <tt>A</tt> derives.
|
|
We must separate two cases:
|
|
|
|
<div class="itemizedlist"><ul type="disc"><li><p>The right hand argument is a pointer to a data member.
|
|
In this case the lambda functor simply performs the argument substitution and calls the built-in member pointer operator, which returns a reference to the member pointed to.
|
|
For example:
|
|
<pre class="programlisting">
|
|
struct A { int d; };
|
|
A* a = new A();
|
|
...
|
|
(a ->* &A::d); // returns a reference to a->d
|
|
(_1 ->* &A::d)(a); // likewise
|
|
</pre>
|
|
</p></li><li><p>
|
|
The right hand argument is a pointer to a member function.
|
|
For a built-in call like this, the result is kind of a delayed member function call.
|
|
Such an expression must be followed by a function argument list, with which the delayed member function call is performed.
|
|
For example:
|
|
<pre class="programlisting">
|
|
struct B { int foo(int); };
|
|
B* b = new B();
|
|
...
|
|
(b ->* &B::foo) // returns a delayed call to b->foo
|
|
// a function argument list must follow
|
|
(b ->* &B::foo)(1) // ok, calls b->foo(1)
|
|
|
|
(_1 ->* &B::foo)(b); // returns a delayed call to b->foo,
|
|
// no effect as such
|
|
(_1 ->* &B::foo)(b)(1); // calls b->foo(1)
|
|
</pre>
|
|
</p></li></ul></div>
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:bind_expressions"></a>5.3. Bind expressions</h3></div></div><p>
|
|
Bind expressions can have two forms:
|
|
|
|
|
|
<pre class="programlisting">
|
|
bind(<i><tt>target-function</tt></i>, <i><tt>bind-argument-list</tt></i>)
|
|
bind(<i><tt>target-member-function</tt></i>, <i><tt>object-argument</tt></i>, <i><tt>bind-argument-list</tt></i>)
|
|
</pre>
|
|
|
|
A bind expression delays the call of a function.
|
|
If this <span class="emphasis"><i>target function</i></span> is <span class="emphasis"><i>n</i></span>-ary, then the <tt><span class="emphasis"><i>bind-argument-list</i></span></tt> must contain <span class="emphasis"><i>n</i></span> arguments as well.
|
|
In the current version of the BLL, 0 <= n <= 9 must hold.
|
|
For member functions, the number of arguments must be at most 8, as the object argument takes one argument position.
|
|
|
|
Basically, the
|
|
<span class="emphasis"><i><tt>bind-argument-list</tt></i></span> must be a valid argument list for the target function, except that any argument can be replaced with a placeholder, or more generally, with a lambda expression.
|
|
Note that also the target function can be a lambda expression.
|
|
|
|
The result of a bind expression is either a nullary, unary, binary or 3-ary function object depending on the use of placeholders in the <span class="emphasis"><i><tt>bind-argument-list</tt></i></span> (see <a href="#sect:placeholders" title="5.1. Placeholders">Section 5.1</a>).
|
|
</p><p>
|
|
The return type of the lambda functor created by the bind expression can be given as an explicitly specified template parameter, as in the following example:
|
|
<pre class="programlisting">
|
|
bind<<span class="emphasis"><i>RET</i></span>>(<span class="emphasis"><i>target-function</i></span>, <span class="emphasis"><i>bind-argument-list</i></span>)
|
|
</pre>
|
|
This is only necessary if the return type of the target function cannot be deduced.
|
|
</p><p>
|
|
The following sections describe the different types of bind expressions.
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_pointers_as_targets"></a>5.3.1. Function pointers or references as targets</h4></div></div><p>The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example:
|
|
<pre class="programlisting">
|
|
X foo(A, B, C); A a; B b; C c;
|
|
bind(foo, _1, _2, c)(a, b);
|
|
bind(&foo, _1, _2, c)(a, b);
|
|
bind(_1, a, b, c)(foo);
|
|
</pre>
|
|
|
|
The return type deduction always succeeds with this type of bind expressions.
|
|
</p><p>
|
|
Note, that in C++ it is possible to take the address of an overloaded function only if the address is assigned to, or used as an initializer of, a variable, the type of which solves the amibiguity, or if an explicit cast expression is used.
|
|
This means that overloaded functions cannot be used in bind expressions directly, e.g.:
|
|
<pre class="programlisting">
|
|
void foo(int);
|
|
void foo(float);
|
|
int i;
|
|
...
|
|
bind(&foo, _1)(i); // error
|
|
...
|
|
void (*pf1)(int) = &foo;
|
|
bind(pf1, _1)(i); // ok
|
|
bind(static_cast<void(*)(int)>(&foo), _1)(i); // ok
|
|
</pre>
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="member_functions_as_targets"></a>5.3.2. Member functions as targets</h4></div></div><p>
|
|
The syntax for using pointers to member function in bind expression is:
|
|
<pre class="programlisting">
|
|
bind(<i><tt>target-member-function</tt></i>, <i><tt>object-argument</tt></i>, <i><tt>bind-argument-list</tt></i>)
|
|
</pre>
|
|
|
|
The object argument can be a reference or pointer to the object, the BLL supports both cases with a uniform interface:
|
|
|
|
<pre class="programlisting">
|
|
bool A::foo(int) const;
|
|
A a;
|
|
vector<int> ints;
|
|
...
|
|
find_if(ints.begin(), ints.end(), bind(&A::foo, a, _1));
|
|
find_if(ints.begin(), ints.end(), bind(&A::foo, &a, _1));
|
|
</pre>
|
|
|
|
Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference:
|
|
|
|
<pre class="programlisting">
|
|
bool A::foo(int);
|
|
list<A> refs;
|
|
list<A*> pointers;
|
|
...
|
|
find_if(refs.begin(), refs.end(), bind(&A::foo, _1, 1));
|
|
find_if(pointers.begin(), pointers.end(), bind(&A::foo, _1, 1));
|
|
</pre>
|
|
|
|
</p><p>
|
|
Even though the interfaces are the same, there are important semantic differences between using a pointer or a reference as the object argument.
|
|
The differences stem from the way <tt>bind</tt>-functions take their parameters, and how the bound parameters are stored within the lambda functor.
|
|
The object argument has the same parameter passing and storing mechanism as any other bind argument slot (see <a href="#sect:storing_bound_arguments" title="4.4. Storing bound arguments in lambda functions">Section 4.4</a>); it is passed as a const reference and stored as a const copy in the lambda functor.
|
|
This creates some asymmetry between the lambda functor and the original member function, and between seemingly similar lambda functors. For example:
|
|
<pre class="programlisting">
|
|
class A {
|
|
int i; mutable int j;
|
|
public:
|
|
|
|
A(int ii, int jj) : i(ii), j(jj) {};
|
|
void set_i(int x) { i = x; };
|
|
void set_j(int x) const { j = x; };
|
|
};
|
|
</pre>
|
|
|
|
When a pointer is used, the behavior is what the programmer might expect:
|
|
|
|
<pre class="programlisting">
|
|
A a(0,0); int k = 1;
|
|
bind(&A::set_i, &a, _1)(k); // a.i == 1
|
|
bind(&A::set_j, &a, _1)(k); // a.j == 1
|
|
</pre>
|
|
|
|
Even though a const copy of the object argument is stored, the original object <tt>a</tt> is still modified.
|
|
This is since the object argument is a pointer, and the pointer is copied, not the object it points to.
|
|
When we use a reference, the behaviour is different:
|
|
|
|
<pre class="programlisting">
|
|
A a(0,0); int k = 1;
|
|
bind(&A::set_i, a, _1)(k); // error; a const copy of a is stored.
|
|
// Cannot call a non-const function set_i
|
|
bind(&A::set_j, a, _1)(k); // a.j == 0, as a copy of a is modified
|
|
</pre>
|
|
</p><p>
|
|
To prevent the copying from taking place, one can use the <tt>ref</tt> or <tt>cref</tt> wrappers (<tt>var</tt> and <tt>constant_ref</tt> would do as well):
|
|
<pre class="programlisting">
|
|
bind(&A::set_i, ref(a), _1)(k); // a.j == 1
|
|
bind(&A::set_j, cref(a), _1)(k); // a.j == 1
|
|
</pre>
|
|
</p><p>Note that the preceding discussion is relevant only for bound arguments.
|
|
If the object argument is unbound, the parameter passing mode is always by reference.
|
|
Hence, the argument <tt>a</tt> is not copied in the calls to the two lambda functors below:
|
|
<pre class="programlisting">
|
|
A a(0,0);
|
|
bind(&A::set_i, _1, 1)(a); // a.i == 1
|
|
bind(&A::set_j, _1, 1)(a); // a.j == 1
|
|
</pre>
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:members_variables_as_targets"></a>5.3.3. Member variables as targets</h4></div></div><p>
|
|
A pointer to a member variable is not really a function, but
|
|
the first argument to the <tt>bind</tt> function can nevertheless
|
|
be a pointer to a member variable.
|
|
Invoking such a bind expression returns a reference to the data member.
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
struct A { int data; };
|
|
A a;
|
|
bind(&A::data, _1)(a) = 1; // a.data == 1
|
|
</pre>
|
|
|
|
The cv-qualifiers of the object whose member is accessed are respected.
|
|
For example, the following tries to write into a const location:
|
|
<pre class="programlisting">
|
|
const A ca = a;
|
|
bind(&A::data, _1)(ca) = 1; // error
|
|
</pre>
|
|
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_objects_as_targets"></a>5.3.4. Function objects as targets</h4></div></div><p>
|
|
|
|
Function objects, that is, class objects which have the function call
|
|
operator defined, can be used as target functions.
|
|
|
|
In general, BLL cannot deduce the return type of an arbitrary function object.
|
|
|
|
However, there is a method for giving BLL this capability for a certain
|
|
function object class.
|
|
|
|
</p><div class="simplesect"><div class="titlepage"><div><h5 class="title"><a name="id2792562"></a>The sig template</h5></div></div><p>
|
|
To make BLL aware of the return type(s) of a function object one needs to
|
|
provide a member template struct
|
|
<tt>sig<Args></tt> with a typedef
|
|
<tt>type</tt> that specifies the return type.
|
|
|
|
Here is a simple example:
|
|
<pre class="programlisting">
|
|
struct A {
|
|
template <class Args> struct sig { typedef B type; }
|
|
B operator()(X, Y, Z);
|
|
};
|
|
</pre>
|
|
|
|
The template argument <tt>Args</tt> is a
|
|
<tt>tuple</tt> (or more precisely a <tt>cons</tt> list)
|
|
type [<a href="#cit:boost::tuple" title="[tuple]">tuple</a>], where the first element
|
|
is the function
|
|
object type itself, and the remaining elements are the types of
|
|
the arguments, with which the function object is being called.
|
|
|
|
This may seem overly complex compared to the Standard Library
|
|
convention for defining the return type of a function
|
|
object with the <tt>return_type</tt> typedef.
|
|
Howver, there are two significant restrictions with using just a simple
|
|
typedef to express the return type:
|
|
<div class="orderedlist"><ol type="1"><li><p>
|
|
If the function object defines several function call operators, there is no way to specify different result types for them.
|
|
</p></li><li><p>
|
|
If the function call operator is a template, the result type may
|
|
depend on the template parameters.
|
|
Hence, the typedef ought to be a template too, which the C++ language
|
|
does not support.
|
|
</p></li></ol></div>
|
|
|
|
The following code shows an example, where the return type depends on the type
|
|
of one of the arguments, and how that dependency can be expressed with the
|
|
<tt>sig</tt> template:
|
|
|
|
<pre class="programlisting">
|
|
struct A {
|
|
|
|
// the return type equals the third argument type:
|
|
template<class T1, T2, T3>
|
|
T3 operator()(const T1& t1, const T2& t2, const T3& t3);
|
|
|
|
template <class Args>
|
|
class sig {
|
|
// get the third argument type (4th element)
|
|
typedef typename
|
|
boost::tuples::element<3, Args>::type T3;
|
|
public:
|
|
typedef typename
|
|
boost::remove_cv<T3>::type type;
|
|
}
|
|
};
|
|
</pre>
|
|
|
|
|
|
The elements of the <tt>Args</tt> tuple are always
|
|
non-reference types.
|
|
|
|
Moreover, the element types can have a const or volatile qualifier
|
|
(jointly referred to as <span class="emphasis"><i>cv-qualifiers</i></span>), or both.
|
|
This is since the cv-qualifiers in the arguments can affect the return type.
|
|
The reason for including the potentially cv-qualified function object
|
|
type itself into the <tt>Args</tt> tuple, is that the function
|
|
object class can contain both const and non-const (or volatile, even
|
|
const volatile) function call operators, and they can each have a different
|
|
return type.
|
|
</p><p>
|
|
The <tt>sig</tt> template can be seen as a
|
|
<span class="emphasis"><i>meta-function</i></span> that maps the argument type tuple to
|
|
the result type of the call made with arguments of the types in the tuple.
|
|
|
|
As the example above demonstrates, the template can end up being somewhat
|
|
complex.
|
|
Typical tasks to be performed are the extraction of the relevant types
|
|
from the tuple, removing cv-qualifiers etc.
|
|
See the Boost type_traits [<a href="#cit:boost::type_traits" title="[type_traits]">type_traits</a>] and
|
|
Tuple [<a href="#cit:boost::type_traits" title="[type_traits]">type_traits</a>] libraries
|
|
for tools that can aid in these tasks.
|
|
The <tt>sig</tt> templates are a refined version of a similar
|
|
mechanism first introduced in the FC++ library
|
|
[<a href="#cit:fc++" title="[fc++]">fc++</a>].
|
|
</p></div><p>
|
|
Earlier versions of the library supported the Standard Library convention
|
|
as the default, and required special actions to make the library recognize
|
|
the <tt>sig</tt> template.
|
|
Now the BLL has that reversed.
|
|
|
|
If one needs to use a functor that adheres to the Standard Library
|
|
convention in a bind expression, we provide the <tt>std_functor</tt>
|
|
wrapper, that gives the function object a <tt>sig</tt>
|
|
template based on the <tt>result_type</tt> typedef.
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int i = 1;
|
|
bind(plus<int>(), _1, 1)(i); // error, no sig template
|
|
bind(std_functor(plus<int>()), _1, 1)(i); // ok
|
|
</pre>
|
|
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:overriding_deduced_return_type"></a>5.4. Overriding the deduced return type</h3></div></div><p>
|
|
The return type deduction system may not be able to deduce the return types of some user defined operators or bind expressions with class objects.
|
|
|
|
A special lambda expression type is provided for stating the return type explicitly and overriding the deduction system.
|
|
To state that the return type of the lambda functor defined by the lambda expression <tt>e</tt> is <tt>T</tt>, you can write:
|
|
|
|
<pre class="programlisting">ret<T>(e);</pre>
|
|
|
|
The effect is that the return type deduction is not performed for the lambda expression <tt>e</tt> at all, but instead, <tt>T</tt> is used as the return type.
|
|
Obviously <tt>T</tt> cannot be an arbitrary type, the true result of the lambda functor must be implicitly convertible to <tt>T</tt>.
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
A a; B b;
|
|
C operator+(A, B);
|
|
int operator*(A, B);
|
|
...
|
|
ret<D>(_1 + _2)(a, b); // error (C cannot be converted to D)
|
|
ret<C>(_1 + _2)(a, b); // ok
|
|
ret<float>(_1 * _2)(a, b); // ok (int can be converted to float)
|
|
...
|
|
struct X {
|
|
Y operator(int)();
|
|
};
|
|
...
|
|
X x; int i;
|
|
bind(x, _1)(i); // error, return type cannot be deduced
|
|
ret<Y>(bind(x, _1))(i); // ok
|
|
</pre>
|
|
For bind expressions, there is a short-hand notation that can be used instead of <tt>ret</tt>.
|
|
The last line could alternatively be written as:
|
|
|
|
<pre class="programlisting">bind<Z>(x, _1)(i);</pre>
|
|
This feature is modeled after the Boost Bind library [<a href="#cit:boost::bind" title="[bind]">bind</a>].
|
|
|
|
</p><p>Note that within nested lambda expressions,
|
|
the <tt>ret</tt> must be used at each subexpression where
|
|
the deduction would otherwise fail.
|
|
For example:
|
|
<pre class="programlisting">
|
|
A a; B b;
|
|
C operator+(A, B); D operator-(C);
|
|
...
|
|
ret<D>( - (_1 + _2))(a, b); // error
|
|
ret<D>( - ret<C>(_1 + _2))(a, b); // ok
|
|
</pre>
|
|
</p><p>If you find yourself using <tt>ret</tt> repeatedly with the same types, it is worth while extending the return type deduction (see <a href="#sect:extending_return_type_system" title="6. Extending return type deduction system">Section 6</a>).
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:nullary_functors_and_ret"></a>5.4.1. Nullary lambda functors and ret</h4></div></div><p>
|
|
As stated above, the effect of <tt>ret</tt> is to prevent the return type deduction to be performed.
|
|
However, there is an exception.
|
|
Due to the way the C++ template instantiation works, the compiler is always forced to instantiate the return type deduction templates for zero-argument lambda functors.
|
|
This introduces a slight problem with <tt>ret</tt>, best described with an example:
|
|
|
|
<pre class="programlisting">
|
|
struct F { int operator()(int i) const; };
|
|
F f;
|
|
...
|
|
bind(f, _1); // fails, cannot deduce the return type
|
|
ret<int>(bind(f, _1)); // ok
|
|
...
|
|
bind(f, 1); // fails, cannot deduce the return type
|
|
ret<int>(bind(f, 1)); // fails as well!
|
|
</pre>
|
|
The BLL cannot deduce the return types of the above bind calls, as <tt>F</tt> does not define the typedef <tt>result_type</tt>.
|
|
One would expect <tt>ret</tt> to fix this, but for the nullary lambda functor that results from a bind expression (last line above) this does not work.
|
|
The return type deduction templates are instantiated, even though it would not be necessary and the result is a compilation error.
|
|
</p><p>The solution to this is not to use the <tt>ret</tt> function, but rather define the return type as an explicitly specified template parameter in the <tt>bind</tt> call:
|
|
<pre class="programlisting">
|
|
bind<int>(f, 1); // ok
|
|
</pre>
|
|
|
|
The lambda functors created with
|
|
<tt>ret<<i><tt>T</tt></i>>(bind(<i><tt>arg-list</tt></i>))</tt> and
|
|
<tt>bind<<i><tt>T</tt></i>>(<i><tt>arg-list</tt></i>)</tt> have the exact same functionality —
|
|
apart from the fact that for some nullary lambda functors the former does not work while the latter does.
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:delaying_constants_and_variables"></a>5.5. Delaying constants and variables</h3></div></div><p>
|
|
The unary functions <tt>constant</tt>,
|
|
<tt>constant_ref</tt> and <tt>var</tt> turn their argument into a lambda functor, that implements an identity mapping.
|
|
The former two are for constants, the latter for variables.
|
|
The use of these <span class="emphasis"><i>delayed</i></span> constants and variables is sometimes necessary due to the lack of explicit syntax for lambda expressions.
|
|
For example:
|
|
<pre class="programlisting">
|
|
for_each(a.begin(), a.end(), cout << _1 << ' ');
|
|
for_each(a.begin(), a.end(), cout << ' ' << _1);
|
|
</pre>
|
|
The first line outputs the elements of <tt>a</tt> separated by spaces, while the second line outputs a space followed by the elements of <tt>a</tt> without any separators.
|
|
The reason for this is that neither of the operands of
|
|
<tt>cout << ' '</tt> is a lambda expression, hence <tt>cout << ' '</tt> is evaluated immediately.
|
|
|
|
To delay the evaluation of <tt>cout << ' '</tt>, one of the operands must be explicitly marked as a lambda expression.
|
|
This is accomplished with the <tt>constant</tt> function:
|
|
<pre class="programlisting">
|
|
for_each(a.begin(), a.end(), cout << constant(' ') << _1);
|
|
</pre>
|
|
|
|
The call <tt>constant(' ')</tt> creates a nullary lambda functor which stores the character constant <tt>' '</tt>
|
|
and returns a reference to it when invoked.
|
|
The function <tt>constant_ref</tt> is similar, except that it
|
|
stores a constant reference to its argument.
|
|
|
|
The <tt>constant</tt> and <tt>consant_ref</tt> are only
|
|
needed when the operator call has side effects, like in the above example.
|
|
</p><p>
|
|
Sometimes we need to delay the evaluation of a variable.
|
|
Suppose we wanted to output the elements of a container in a numbered list:
|
|
|
|
<pre class="programlisting">
|
|
int index = 0;
|
|
for_each(a.begin(), a.end(), cout << ++index << ':' << _1 << '\n');
|
|
for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1 << '\n');
|
|
</pre>
|
|
|
|
The first <tt>for_each</tt> invocation does not do what we want; <tt>index</tt> is incremented only once, and its value is written into the output stream only once.
|
|
By using <tt>var</tt> to make <tt>index</tt> a lambda expression, we get the desired effect.
|
|
|
|
</p><p>
|
|
In sum, <tt>var(x)</tt> creates a nullary lambda functor,
|
|
which stores a reference to the variable <tt>x</tt>.
|
|
When the lambda functor is invoked, a reference to <tt>x</tt> is returned.
|
|
</p><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2793408"></a>Naming delayed constants and variables</h4></div></div><p>
|
|
It is possible to predefine and name a delayed variable or constant outside a lambda expression.
|
|
The templates <tt>var_type</tt>, <tt>constant_type</tt>
|
|
and <tt>constant_ref_type</tt> serve for this purpose.
|
|
They are used as:
|
|
<pre class="programlisting">
|
|
var_type<T>::type delayed_i(var(i));
|
|
constant_type<T>::type delayed_c(constant(c));
|
|
</pre>
|
|
The first line defines the variable <tt>delayed_i</tt> which is a delayed version of the variable <tt>i</tt> of type <tt>T</tt>.
|
|
Analogously, the second line defines the constant <tt>delayed_c</tt> as a delayed version of the constant <tt>c</tt>.
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int i = 0; int j;
|
|
for_each(a.begin(), a.end(), (var(j) = _1, _1 = var(i), var(i) = var(j)));
|
|
</pre>
|
|
is equivalent to:
|
|
<pre class="programlisting">
|
|
int i = 0; int j;
|
|
var_type<int>::type vi(var(i)), vj(var(j));
|
|
for_each(a.begin(), a.end(), (vj = _1, _1 = vi, vi = vj));
|
|
</pre>
|
|
</p><p>
|
|
Here is an example of naming a delayed constant:
|
|
<pre class="programlisting">
|
|
constant_type<char>::type space(constant(' '));
|
|
for_each(a.begin(),a.end(), cout << space << _1);
|
|
</pre>
|
|
</p></div><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2793532"></a>About assignment and subscript operators</h4></div></div><p>
|
|
As described in <a href="#sect:assignment_and_subscript" title="5.2.2. Assignment and subscript operators">Section 5.2.2</a>, assignment and subscripting operators are always defined as member functions.
|
|
This means, that for expressions of the form
|
|
<tt>x = y</tt> or <tt>x[y]</tt> to be interpreted as lambda expressions, the left-hand operand <tt>x</tt> must be a lambda expression.
|
|
Consequently, it is sometimes necessary to use <tt>var</tt> for this purpose.
|
|
We repeat the example from <a href="#sect:assignment_and_subscript" title="5.2.2. Assignment and subscript operators">Section 5.2.2</a>:
|
|
|
|
<pre class="programlisting">
|
|
int i;
|
|
i = _1; // error
|
|
var(i) = _1; // ok
|
|
</pre>
|
|
</p><p>
|
|
|
|
Note that the compound assignment operators <tt>+=</tt>, <tt>-=</tt> etc. can be defined as non-member functions, and thus they are interpreted as lambda expressions even if only the right-hand operand is a lambda expression.
|
|
Nevertheless, it is perfectly ok to delay the left operand explicitly.
|
|
For example, <tt>i += _1</tt> is equivalent to <tt>var(i) += _1</tt>.
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:lambda_expressions_for_control_structures"></a>5.6. Lambda expressions for control structures</h3></div></div><p>
|
|
BLL defines several functions to create lambda functors that represent control structures.
|
|
They all take lambda functors as parameters and return <tt>void</tt>.
|
|
To start with an example, the following code outputs all even elements of some container <tt>a</tt>:
|
|
|
|
<pre class="programlisting">
|
|
for_each(a.begin(), a.end(),
|
|
if_then(_1 % 2 == 0, cout << _1));
|
|
</pre>
|
|
</p><p>
|
|
The BLL supports the following function templates for control structures:
|
|
|
|
<pre class="programlisting">
|
|
if_then(condition, then_part)
|
|
if_then_else(condition, then_part, else_part)
|
|
if_then_else_return(condition, then_part, else_part)
|
|
while_loop(condition, body)
|
|
while_loop(condition) // no body case
|
|
do_while_loop(condition, body)
|
|
do_while_loop(condition) // no body case
|
|
for_loop(init, condition, increment, body)
|
|
for_loop(init, condition, increment) // no body case
|
|
switch_statement(...)
|
|
</pre>
|
|
|
|
The return types of all control construct lambda functor is
|
|
<tt>void</tt>, except for <tt>if_then_else_return</tt>,
|
|
which wraps a call to the conditional operator
|
|
<pre class="programlisting">
|
|
condition ? then_part : else_part
|
|
</pre>
|
|
The return type rules for this operator are somewhat complex.
|
|
Basically, if the branches have the same type, this type is the return type.
|
|
If the type of the branches differ, one branch, say of type
|
|
<tt>A</tt>, must be convertible to the other branch,
|
|
say of type <tt>B</tt>.
|
|
In this situation, the result type is <tt>B</tt>.
|
|
Further, if the common type is an lvalue, the return type will be an lvalue
|
|
too.
|
|
</p><p>
|
|
Delayed variables tend to be commonplace in control structure lambda expressions.
|
|
For instance, here we use the <tt>var</tt> function to turn the arguments of <tt>for_loop</tt> into lambda expressions.
|
|
The effect of the code is to add 1 to each element of a two-dimensional array:
|
|
|
|
<pre class="programlisting">
|
|
int a[5][10]; int i;
|
|
for_each(a, a+5,
|
|
for_loop(var(i)=0, var(i)<10, ++var(i),
|
|
_1[var(i)] += 1));
|
|
</pre>
|
|
|
|
|
|
</p><p>
|
|
The BLL supports an alternative syntax for control expressions, suggested
|
|
by Joel de Guzmann.
|
|
By overloading the <tt>operator[]</tt> we can
|
|
get a closer resemblance with the built-in control structures:
|
|
|
|
<pre class="programlisting">
|
|
if_(condition)[then_part]
|
|
if_(condition)[then_part].else_[else_part]
|
|
while_(condition)[body]
|
|
do_[body].while_(condition)
|
|
for_(init, condition, increment)[body]
|
|
</pre>
|
|
|
|
For example, using this syntax the <tt>if_then</tt> example above
|
|
can be written as:
|
|
<pre class="programlisting">
|
|
for_each(a.begin(), a.end(),
|
|
if(_1 % 2 == 0)[ cout << _1 ])
|
|
</pre>
|
|
|
|
As more experience is gained, we may end up deprecating one or the other
|
|
of these syntaces.
|
|
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:switch_statement"></a>5.6.1. Switch statement</h4></div></div></div><p>
|
|
The lambda expressions for <tt>switch</tt> control structures are more complex since the number of cases may vary.
|
|
The general form of a switch lambda expression is:
|
|
|
|
<pre class="programlisting">
|
|
switch_statement(<i><tt>condition</tt></i>,
|
|
case_statement<<i><tt>label</tt></i>>(<i><tt>lambda expression</tt></i>),
|
|
case_statement<<i><tt>label</tt></i>>(<i><tt>lambda expression</tt></i>),
|
|
...
|
|
default_statement(<i><tt>lambda expression</tt></i>)
|
|
)
|
|
</pre>
|
|
|
|
The <tt><i><tt>condition</tt></i></tt> argument must be a lambda expression that creates a lambda functor with an integral return type.
|
|
The different cases are created with the <tt>case_statement</tt> functions, and the optional default case with the <tt>default_statement</tt> function.
|
|
The case labels are given as explicitly specified template arguments to <tt>case_statement</tt> functions and
|
|
<tt>break</tt> statements are implicitly part of each case.
|
|
For example, <tt>case_statement<1>(a)</tt>, where <tt>a</tt> is some lambda functor, generates the code:
|
|
|
|
<pre class="programlisting">
|
|
case 1:
|
|
<i><tt>evaluate lambda functor</tt></i> a;
|
|
break;
|
|
</pre>
|
|
The <tt>switch_statement</tt> function is specialized for up to 9 case statements.
|
|
|
|
</p><p>
|
|
As a concrete example, the following code iterates over some container <tt>v</tt> and ouptuts “zero” for each <tt>0</tt>, “one” for each <tt>1</tt>, and “other: <i><tt>n</tt></i>” for any other value <i><tt>n</tt></i>.
|
|
Note that another lambda expression is sequenced after the <tt>switch_statement</tt> to output a line break after each element:
|
|
|
|
<pre class="programlisting">
|
|
std::for_each(v.begin(), v.end(),
|
|
(
|
|
switch_statement(
|
|
_1,
|
|
case_statement<0>(std::cout << constant("zero")),
|
|
case_statement<1>(std::cout << constant("one")),
|
|
default_statement(cout << constant("other: ") << _1)
|
|
),
|
|
cout << constant("\n")
|
|
)
|
|
);
|
|
</pre>
|
|
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:exceptions"></a>5.7. Exceptions</h3></div></div><p>
|
|
The BLL provides lambda functors that throw and catch exceptions.
|
|
Lambda functors for throwing exceptions are created with the unary function <tt>throw_exception</tt>.
|
|
The argument to this function is the exception to be thrown, or a lambda functor which creates the exception to be thrown.
|
|
A lambda functor for rethrowing exceptions is created with the nullary <tt>rethrow</tt> function.
|
|
</p><p>
|
|
Lambda expressions for handling exceptions are somewhat more complex.
|
|
The general form of a lambda expression for try catch blocks is as follows:
|
|
|
|
<pre class="programlisting">
|
|
try_catch(
|
|
<i><tt>lambda expression</tt></i>,
|
|
catch_exception<<i><tt>type</tt></i>>(<i><tt>lambda expression</tt></i>),
|
|
catch_exception<<i><tt>type</tt></i>>(<i><tt>lambda expression</tt></i>),
|
|
...
|
|
catch_all(<i><tt>lambda expression</tt></i>)
|
|
)
|
|
</pre>
|
|
|
|
The first lambda expression is the try block.
|
|
Each <tt>catch_exception</tt> defines a catch block where the
|
|
explicitly specified template argument defines the type of the exception
|
|
to catch.
|
|
|
|
The lambda expression within the <tt>catch_exception</tt> defines
|
|
the actions to take if the exception is caught.
|
|
|
|
Note that the resulting exception handlers catch the exceptions as
|
|
references, i.e., <tt>catch_exception<T>(...)</tt>
|
|
results in the catch block:
|
|
|
|
<pre class="programlisting">
|
|
catch(T& e) { ... }
|
|
</pre>
|
|
|
|
The last catch block can alternatively be a call to
|
|
<tt>catch_exception<<i><tt>type</tt></i>></tt>
|
|
or to
|
|
<tt>catch_all</tt>, which is the lambda expression equivalent to
|
|
<tt>catch(...)</tt>.
|
|
|
|
</p><p>
|
|
|
|
The <a href="#ex:exceptions" title="Example 1. Throwing and handling exceptions in lambda expressions.">Example 1</a> demonstrates the use of the BLL
|
|
exception handling tools.
|
|
The first handler catches exceptions of type <tt>foo_exception</tt>.
|
|
Note the use of <tt>_1</tt> placeholder in the body of the handler.
|
|
</p><p>
|
|
The second handler shows how to throw exceptions, and demonstrates the
|
|
use of the <span class="emphasis"><i>exception placeholder</i></span> <tt>_e</tt>.
|
|
|
|
It is a special placeholder, which refers to the caught exception object
|
|
within the handler body.
|
|
|
|
Here we are handling an exception of type <tt>std::exception</tt>,
|
|
which carries a string explaining the cause of the exception.
|
|
|
|
This explanation can be queried with the zero-argument member
|
|
function <tt>what</tt>.
|
|
|
|
The expression
|
|
<tt>bind(&std::exception::what, _e)</tt> creates the lambda
|
|
function for making that call.
|
|
|
|
Note that <tt>_e</tt> cannot be used outside of an exception handler lambda expression.
|
|
|
|
|
|
The last line of the second handler constructs a new exception object and
|
|
throws that with <tt>throw exception</tt>.
|
|
|
|
Constructing and destructing objects within lambda expressions is
|
|
explained in <a href="#sect:construction_and_destruction" title="5.8. Construction and destruction">Section 5.8</a>
|
|
</p><p>
|
|
Finally, the third handler (<tt>catch_all</tt>) demonstrates
|
|
rethrowing exceptions.
|
|
</p><div class="example"><p><a name="ex:exceptions"></a><b>Example 1. Throwing and handling exceptions in lambda expressions.</b></p><pre class="programlisting">
|
|
for_each(
|
|
a.begin(), a.end(),
|
|
try_catch(
|
|
bind(foo, _1), // foo may throw
|
|
catch_exception<foo_exception>(
|
|
cout << constant("Caught foo_exception: ")
|
|
<< "foo was called with argument = " << _1
|
|
),
|
|
catch_exception<std::exception>(
|
|
cout << constant("Caught std::exception: ")
|
|
<< bind(&std::exception::what, _e),
|
|
throw_exception(bind(constructor<bar_exception>(), _1)))
|
|
),
|
|
catch_all(
|
|
(cout << constant("Unknown"), rethrow())
|
|
)
|
|
)
|
|
);
|
|
</pre></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:construction_and_destruction"></a>5.8. Construction and destruction</h3></div></div><p>
|
|
Operators <tt>new</tt> and <tt>delete</tt> can be
|
|
overloaded, but their return types are fixed.
|
|
|
|
Particularly, the return types cannot be lambda functors,
|
|
which prevents them to be overloaded for lambda expressions.
|
|
|
|
It is not possible to take the address of a constructor,
|
|
hence constructors cannot be used as target functions in bind expressions.
|
|
|
|
The same is true for destructors.
|
|
|
|
As a way around these constraints, BLL defines wrapper classes for
|
|
<tt>new</tt> and <tt>delete</tt> calls,
|
|
as well as for constructors and destructors.
|
|
|
|
Instances of these classes are function objects, that can be used as
|
|
target functions of bind expressions.
|
|
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int* a[10];
|
|
for_each(a, a+10, _1 = bind(new_ptr<int>()));
|
|
for_each(a, a+10, bind(delete_ptr(), _1));
|
|
</pre>
|
|
|
|
The <tt>new_ptr<int>()</tt> expression creates
|
|
a function object that calls <tt>new int()</tt> when invoked,
|
|
and wrapping that inside <tt>bind</tt> makes it a lambda functor.
|
|
|
|
In the same way, the expression <tt>delete_ptr()</tt> creates
|
|
a function object that invokes <tt>delete</tt> on its argument.
|
|
|
|
Note that <tt>new_ptr<<i><tt>T</tt></i>>()</tt>
|
|
can take arguments as well.
|
|
|
|
They are passed directly to the constructor invocation and thus allow
|
|
calls to constructors which take arguments.
|
|
|
|
</p><p>
|
|
|
|
As an example of constructor calls in lambda expressions,
|
|
the following code reads integers from two containers <tt>x</tt>
|
|
and <tt>y</tt>,
|
|
constructs pairs out of them and inserts them into a third container:
|
|
|
|
<pre class="programlisting">
|
|
vector<pair<int, int> > v;
|
|
transform(x.begin(), x.end(), y.begin(), back_inserter(v),
|
|
bind(constructor<pair<int, int> >(), _1, _2));
|
|
</pre>
|
|
|
|
<a href="#table:constructor_destructor_fos" title="Table 1. Construction and destruction related function objects.">Table 1</a> lists all the function
|
|
objects related to creating and destroying objects,
|
|
showing the expression to create and call the function object,
|
|
and the effect of evaluating that expression.
|
|
|
|
</p><div class="table"><p><a name="table:constructor_destructor_fos"></a><b>Table 1. Construction and destruction related function objects.</b></p><table summary="Construction and destruction related function objects." border="1"><colgroup><col><col></colgroup><thead><tr><th>Function object call</th><th>Wrapped expression</th></tr></thead><tbody><tr><td><tt>constructor<T>()(<i><tt>arg_list</tt></i>)</tt></td><td>T(<i><tt>arg_list</tt></i>)</td></tr><tr><td><tt>destructor()(a)</tt></td><td><tt>a.~A()</tt>, where <tt>a</tt> is of type <tt>A</tt></td></tr><tr><td><tt>destructor()(pa)</tt></td><td><tt>pa.->A()</tt>, where <tt>pa</tt> is of type <tt>A*</tt></td></tr><tr><td><tt>new_ptr<T>()(<i><tt>arg_list</tt></i>)</tt></td><td><tt>new T(<i><tt>arg_list</tt></i>)</tt></td></tr><tr><td><tt>new_array<T>()(sz)</tt></td><td><tt>new T[sz]</tt></td></tr><tr><td><tt>delete_ptr()(p)</tt></td><td><tt>delete p</tt></td></tr><tr><td><tt>delete_array()(p)</tt></td><td><tt>delete p[]</tt></td></tr></tbody></table></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2794800"></a>5.9. Special lambda expressions</h3></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2794807"></a>5.9.1. Preventing argument substitution</h4></div></div><p>
|
|
When a lambda functor is called, the default behavior is to substitute
|
|
the actual arguments for the placeholders within all subexpressions.
|
|
|
|
This section describes the tools to prevent the substitution and
|
|
evaluation of a subexpression, and explains when these tools should be used.
|
|
</p><p>
|
|
The arguments to a bind expression can be arbitrary lambda expressions,
|
|
e.g., other bind expressions.
|
|
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int foo(int); int bar(int);
|
|
...
|
|
int i;
|
|
bind(foo, bind(bar, _1)(i);
|
|
</pre>
|
|
|
|
The last line makes the call <tt>foo(bar(i));</tt>
|
|
|
|
Note that the first argument in a bind expression, the target function,
|
|
is no exception, and can thus be a bind expression too.
|
|
|
|
The innermost lambda functor just has to return something that can be used
|
|
as a target function: another lambda functor, function pointer,
|
|
pointer to member function etc.
|
|
|
|
For example, in the following code the innermost lambda functor makes
|
|
a selection between two functions, and returns a pointer to one of them:
|
|
|
|
<pre class="programlisting">
|
|
int add(int a, int b) { return a+b; }
|
|
int mul(int a, int b) { return a*b; }
|
|
|
|
int(*)(int, int) add_or_mul(bool x) {
|
|
return x ? add : mul;
|
|
}
|
|
|
|
bool condition; int i; int j;
|
|
...
|
|
bind(bind(&add_or_mul, _1), _2, _3)(condition, i, j);
|
|
</pre>
|
|
|
|
</p><div class="section"><div class="titlepage"><div><h5 class="title"><a name="sect:unlambda"></a>5.9.1.1. Unlambda</h5></div></div><p>A nested bind expression may occur inadvertently,
|
|
if the target function is a variable with a type that depends on a
|
|
template parameter.
|
|
|
|
Typically the target function could be a formal parameter of a
|
|
function template.
|
|
|
|
In such a case, the programmer may not know whether the target function is a lambda functor or not.
|
|
</p><p>Consider the following function template:
|
|
|
|
<pre class="programlisting">
|
|
template<class F>
|
|
int nested(const F& f) {
|
|
int x;
|
|
...
|
|
bind(f, _1)(x);
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
Somewhere inside the function the formal parameter
|
|
<tt>f</tt> is used as a target function in a bind expression.
|
|
|
|
In order for this <tt>bind</tt> call to be valid,
|
|
<tt>f</tt> must be a unary function.
|
|
|
|
Suppose the following two calls to <tt>nested</tt> are made:
|
|
|
|
<pre class="programlisting">
|
|
int foo(int);
|
|
int bar(int, int);
|
|
nested(&foo);
|
|
nested(bind(bar, 1, _1));
|
|
</pre>
|
|
|
|
Both are unary functions, or function objects, with appropriate argument
|
|
and return types, but the latter will not compile.
|
|
|
|
In the latter call, the bind expression inside <tt>nested</tt>
|
|
will become:
|
|
|
|
<pre class="programlisting">
|
|
bind(bind(bar, 1, _1), _1)
|
|
</pre>
|
|
|
|
When this is invoked with <tt>x</tt>,
|
|
after substituitions we end up trying to call
|
|
|
|
<pre class="programlisting">
|
|
bar(1, x)(x)
|
|
</pre>
|
|
|
|
which is an error.
|
|
|
|
The call to <tt>bar</tt> returns int,
|
|
not a unary function or function object.
|
|
</p><p>
|
|
In the example above, the intent of the bind expression in the
|
|
<tt>nested</tt> function is to treat <tt>f</tt>
|
|
as an ordinary function object, instead of a lambda functor.
|
|
|
|
The BLL provides the function template <tt>unlambda</tt> to
|
|
express this: a lambda functor wrapped inside <tt>unlambda</tt>
|
|
is not a lambda functor anymore, and does not take part into the
|
|
argument substitution process.
|
|
|
|
Note that for all other argument types <tt>unlambda</tt> is
|
|
an identity operation, except for making non-const objects const.
|
|
</p><p>
|
|
Using <tt>unlambda</tt>, the <tt>nested</tt>
|
|
function is written as:
|
|
|
|
<pre class="programlisting">
|
|
template<class F>
|
|
int nested(const F& f) {
|
|
int x;
|
|
...
|
|
bind(unlambda(f), _1)(x);
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
</p></div><div class="section"><div class="titlepage"><div><h5 class="title"><a name="id2795067"></a>5.9.1.2. Protect</h5></div></div><p>
|
|
The <tt>protect</tt> function is related to unlambda.
|
|
|
|
It is also used to prevent the argument substitution taking place,
|
|
but whereas <tt>unlambda</tt> turns a lambda functor into
|
|
an ordinary function object for good, <tt>protect</tt> does
|
|
this temporarily, for just one evaluation round.
|
|
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int x = 1, y = 10;
|
|
(_1 + protect(_1 + 2))(x)(y);
|
|
</pre>
|
|
|
|
The first call substitutes <tt>x</tt> for the leftmost
|
|
<tt>_1</tt>, and results in another lambda functor
|
|
<tt>x + (_1 + 2)</tt>, which after the call with
|
|
<tt>y</tt> becomes <tt>x + (y + 2)</tt>,
|
|
and thus finally 13.
|
|
</p><p>
|
|
Primary motivation for including <tt>protect</tt> into the library,
|
|
was to allow nested STL algorithm invocations
|
|
(<a href="#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>).
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:rvalues_as_actual_arguments"></a>5.9.2. Rvalues as actual arguments to lambda functors</h4></div></div><p>
|
|
Actual arguments to the lambda functors cannot be non-const rvalues.
|
|
This is due to a deliberate design decision: either we have this restriction,
|
|
or there can be no side-effects to the actual arguments.
|
|
|
|
There are ways around this limitation.
|
|
|
|
We repeat the example from section
|
|
<a href="#sect:actual_arguments_to_lambda_functors" title="4.3. About actual arguments to lambda functors">Section 4.3</a> and list the
|
|
different solutions:
|
|
|
|
<pre class="programlisting">
|
|
int i = 1; int j = 2;
|
|
(_1 + _2)(i, j); // ok
|
|
(_1 + _2)(1, 2); // error (!)
|
|
</pre>
|
|
|
|
<div class="orderedlist"><ol type="1"><li><p>
|
|
If the rvalue is of a class type, the return type of the function that
|
|
creates the rvalue should be defined as const.
|
|
Due to an unfortunate language restriction this does not work for
|
|
built-in types, as built-in rvalues cannot be const qualified.
|
|
</p></li><li><p>
|
|
If the lambda function call is accessible, the <tt>make_const</tt>
|
|
function can be used to <span class="emphasis"><i>constify</i></span> the rvalue. E.g.:
|
|
|
|
<pre class="programlisting">
|
|
(_1 + _2)(make_const(1), make_const(2)); // ok
|
|
</pre>
|
|
|
|
Commonly the lambda function call site is inside a standard algorithm
|
|
function template, preventing this solution to be used.
|
|
|
|
</p></li><li><p>
|
|
If neither of the above is possible, the lambda expression can be wrapped
|
|
in a <tt>const_parameters</tt> function.
|
|
It creates another type of lambda functor, which takes its arguments as
|
|
const references. For example:
|
|
|
|
<pre class="programlisting">
|
|
const_parameters(_1 + _2)(1, 2); // ok
|
|
</pre>
|
|
|
|
Note that <tt>const_parameters</tt> makes all arguments const.
|
|
Hence, in the case were one of the arguments is a non-const rvalue,
|
|
and another argument needs to be passed as a non-const reference,
|
|
this approach cannot be used.
|
|
</p></li><li><p>If none of the above is possible, there is still one solution,
|
|
which unfortunately can break const correctness.
|
|
|
|
The solution is yet another lambda functor wrapper, which we have named
|
|
<tt>break_const</tt> to alert the user of the potential dangers
|
|
of this function.
|
|
|
|
The <tt>break_const</tt> function creates a lambda functor that
|
|
takes its arguments as const, and casts away constness prior to the call
|
|
to the original wrapped lambda functor.
|
|
|
|
For example:
|
|
<pre class="programlisting">
|
|
int i;
|
|
...
|
|
(_1 += _2)(i, 2); // error, 2 is a non-const rvalue
|
|
const_parameters(_1 += _2)(i, 2); // error, i becomes const
|
|
break_const(_1 += _2)(i, 2); // ok, but dangerous
|
|
</pre>
|
|
|
|
Note, that the results of <tt> break_const</tt> or
|
|
<tt>const_parameters</tt> are not lambda functors,
|
|
so they cannot be used as subexpressions of lambda expressions. For instance:
|
|
|
|
<pre class="programlisting">
|
|
break_const(_1 + _2) + _3; // fails.
|
|
const_parameters(_1 + _2) + _3; // fails.
|
|
</pre>
|
|
|
|
However, this kind of code should never be necessary,
|
|
since calls to sub lambda functors are made inside the BLL,
|
|
and are not affected by the non-const rvalue problem.
|
|
</p></li></ol></div>
|
|
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2795373"></a>5.10. Casts, sizeof and typeid</h3></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:cast_expressions"></a>5.10.1.
|
|
Cast expressions
|
|
</h4></div></div><p>
|
|
The BLL defines its counterparts for the four cast expressions
|
|
<tt>static_cast</tt>, <tt>dynamic_cast</tt>,
|
|
<tt>const_cast</tt> and <tt>reinterpret_cast</tt>.
|
|
|
|
The BLL versions of the cast expressions have the prefix
|
|
<tt>ll_</tt>.
|
|
|
|
The type to cast to is given as an explicitly specified template argument,
|
|
and the sole argument is the expression from which to perform the cast.
|
|
|
|
If the argument is a lambda functor, the lambda functor is evaluated first.
|
|
|
|
For example, the following code uses <tt>ll_dynamic_cast</tt>
|
|
to count the number of <tt>derived</tt> instances in the container
|
|
<tt>a</tt>:
|
|
|
|
<pre class="programlisting">
|
|
class base {};
|
|
class derived : public base {};
|
|
|
|
vector<base*> a;
|
|
...
|
|
int count = 0;
|
|
for_each(a.begin(), a.end(),
|
|
if_then(ll_dynamic_cast<derived*>(_1), ++var(count)));
|
|
</pre>
|
|
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2795475"></a>5.10.2. Sizeof and typeid</h4></div></div><p>
|
|
The BLL counterparts for these expressions are named
|
|
<tt>ll_sizeof</tt> and <tt>ll_typeid</tt>.
|
|
|
|
Both take one argument, which can be a lambda expression.
|
|
The lambda functor created wraps the <tt>sizeof</tt> or
|
|
<tt>typeid</tt> call, and when the lambda functor is called
|
|
the wrapped operation is performed.
|
|
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
vector<base*> a;
|
|
...
|
|
for_each(a.begin(), a.end(),
|
|
cout << bind(&type_info::name, ll_typeid(*_1)));
|
|
</pre>
|
|
|
|
Here <tt>ll_typeid</tt> creates a lambda functor for
|
|
calling <tt>typeid</tt> for each element.
|
|
|
|
The result of a <tt>typeid</tt> call is an instance of
|
|
the <tt>type_info</tt> class, and the bind expression creates
|
|
a lambda functor for calling the <tt>name</tt> member
|
|
function of that class.
|
|
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:nested_stl_algorithms"></a>5.11. Nesting STL algorithm invocations</h3></div></div><p>
|
|
The BLL defines common STL algorithms as function object classes,
|
|
instances of which can be used as target functions in bind expressions.
|
|
For example, the following code iterates over the elements of a
|
|
two-dimensional array, and computes their sum.
|
|
|
|
<pre class="programlisting">
|
|
int a[100][200];
|
|
int sum = 0;
|
|
|
|
std::for_each(a, a + 100,
|
|
bind(ll::for_each(), _1, _1 + 200, protect(sum += _1)));
|
|
</pre>
|
|
|
|
The BLL versions of the STL algorithms are classes, which define the function call operator (or several overloaded ones) to call the corresponding function templates in the <tt>std</tt> namespace.
|
|
All these structs are placed in the subnamespace <tt>boost::lambda:ll</tt>.
|
|
|
|
</p><p>
|
|
Note that there is no easy way to express an overloaded member function
|
|
call in a lambda expression.
|
|
|
|
This limits the usefulness of nested STL algorithms, as for instance
|
|
the <tt>begin</tt> function has more than one overloaded
|
|
definitions in container templates.
|
|
|
|
In general, something analogous to the pseudo-code below cannot be written:
|
|
|
|
<pre class="programlisting">
|
|
std::for_each(a.begin(), a.end(),
|
|
bind(ll::for_each(), _1.begin(), _1.end(), protect(sum += _1)));
|
|
</pre>
|
|
|
|
Some aid for common special cases can be provided though.
|
|
|
|
The BLL defines two helper function object classes,
|
|
<tt>call_begin</tt> and <tt>call_end</tt>,
|
|
which wrap a call to the <tt>begin</tt> and, respectively,
|
|
<tt>end</tt> functions of a container, and return the
|
|
<tt>const_iterator</tt> type of the container.
|
|
|
|
With these helper templates, the above code becomes:
|
|
<pre class="programlisting">
|
|
std::for_each(a.begin(), a.end(),
|
|
bind(ll::for_each(),
|
|
bind(call_begin(), _1), bind(call_end(), _1),
|
|
protect(sum += _1)));
|
|
</pre>
|
|
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:extending_return_type_system"></a>6. Extending return type deduction system</h2></div></div><p>
|
|
|
|
|
|
In this section, we explain how to extend the return type deduction system
|
|
to cover user defined operators.
|
|
|
|
In many cases this is not necessary,
|
|
as the BLL defines default return types for operators.
|
|
|
|
For example, the default return type for all comparison operators is
|
|
<tt>bool</tt>, and as long as the user defined comparison operators
|
|
have a bool return type, there is no need to write new specializations
|
|
for the return type deduction classes.
|
|
|
|
Sometimes this cannot be avoided, though.
|
|
|
|
</p><p>
|
|
The overloadable user defined operators are either unary or binary.
|
|
|
|
For each arity, there are two traits templates that define the
|
|
return types of the different operators.
|
|
|
|
Hence, the return type system can be extended by providing more
|
|
specializations for these templates.
|
|
|
|
The templates for unary functors are
|
|
|
|
<tt>
|
|
plain_return_type_1<Action, A>
|
|
</tt>
|
|
|
|
and
|
|
|
|
<tt>
|
|
return_type_1<Action, A>
|
|
</tt>, and
|
|
|
|
<tt>
|
|
plain_return_type_2<Action, A, B>
|
|
</tt>
|
|
|
|
and
|
|
|
|
<tt>
|
|
return_type_2<Action, A, B>
|
|
</tt>
|
|
|
|
respectively for binary functors.
|
|
|
|
</p><p>
|
|
The first parameter (<tt>Action</tt>) to all these templates
|
|
is the <span class="emphasis"><i>action</i></span> class, which specifies the operator.
|
|
|
|
Operators with similar return type rules are grouped together into
|
|
<span class="emphasis"><i>action groups</i></span>,
|
|
and only the action class and action group together define the operator
|
|
unambiguously.
|
|
|
|
As an example, the action type
|
|
<tt>arithmetic_action<plus_action></tt> stands for
|
|
<tt>operator+</tt>.
|
|
|
|
The complete listing of different action types is shown in
|
|
<a href="#table:actions" title="Table 2. Action types">Table 2</a>.
|
|
</p><p>
|
|
The latter parameters, <tt>A</tt> in the unary case,
|
|
or <tt>A</tt> and <tt>B</tt> in the binary case,
|
|
stand for the argument types of the operator call.
|
|
|
|
The two sets of templates,
|
|
<tt>plain_return_type_<i><tt>n</tt></i></tt> and
|
|
<tt>return_type_<i><tt>n</tt></i></tt>
|
|
(<i><tt>n</tt></i> is 1 or 2) differ in the way how parameter types
|
|
are presented to them.
|
|
|
|
For the former templates, the parameter types are always provided as
|
|
non-reference types, and do not have const or volatile qualifiers.
|
|
|
|
This makes specializing easy, as commonly one specialization for each
|
|
user defined operator, or operator group, is enough.
|
|
|
|
On the other hand, if a particular operator is overloaded for different
|
|
cv-qualifications of the same argument types,
|
|
and the return types of these overloaded versions differ, a more fine-grained control is needed.
|
|
|
|
Hence, for the latter templates, the parameter types preserve the
|
|
cv-qualifiers, and are non-reference types as well.
|
|
|
|
The downside is, that for an overloaded set of operators of the
|
|
kind described above, one may end up needing up to
|
|
16 <tt>return_type_2</tt> specializations.
|
|
</p><p>
|
|
Suppose the user has overloaded the following operators for some user defined
|
|
types <tt>X</tt>, <tt>Y</tt> and <tt>Z</tt>:
|
|
|
|
<pre class="programlisting">
|
|
Z operator+(const X&, const Y&);
|
|
Z operator-(const X&, const Y&);
|
|
</pre>
|
|
|
|
Now, one can add a specialization stating, that if the left hand argument
|
|
is of type <tt>X</tt>, and the right hand one of type
|
|
<tt>Y</tt>, the return type of all such binary arithmetic
|
|
operators is <tt>Z</tt>:
|
|
|
|
<pre class="programlisting">
|
|
namespace boost {
|
|
namespace lambda {
|
|
|
|
template<class Act>
|
|
struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
|
|
typedef Z type;
|
|
};
|
|
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
Having this specialization defined, BLL is capable of correctly
|
|
deducing the return type of the above two operators.
|
|
|
|
Note, that the specializations must be in the same namespace,
|
|
<tt>::boost::lambda</tt>, with the primary template.
|
|
|
|
For brevity, we do not show the namespace definitions in the examples below.
|
|
</p><p>
|
|
It is possible to specialize on the level of an individual operator as well,
|
|
in addition to providing a specialization for a group of operators.
|
|
Say, we add a new arithmetic operator for argument types <tt>X</tt>
|
|
and <tt>Y</tt>:
|
|
|
|
<pre class="programlisting">
|
|
X operator*(const X&, const Y&);
|
|
</pre>
|
|
|
|
Our first rule for all arithmetic operators specifies that the return
|
|
type of this operator is <tt>Z</tt>,
|
|
which obviously is not the case.
|
|
Hence, we provide a new rule for the multiplication operator:
|
|
|
|
<pre class="programlisting">
|
|
template<>
|
|
struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
|
|
typedef X type;
|
|
};
|
|
</pre>
|
|
</p><p>
|
|
The specializations can define arbitrary mappings from the argument types
|
|
to the return type.
|
|
|
|
Suppose we have some mathematical vector type, templated on the element type:
|
|
|
|
<pre class="programlisting">
|
|
template <class T> class my_vector;
|
|
</pre>
|
|
|
|
Suppose the addition operator is defined between any two
|
|
<tt>my_vector</tt> instantiations,
|
|
as long as the addition operator is defined between their element types.
|
|
|
|
Furthermore, the element type of the resulting <tt>my_vector</tt>
|
|
is the same as the result type of the addition between the element types.
|
|
|
|
E.g., adding <tt>my_vector<int></tt> and
|
|
<tt>my_vector<double></tt> results in
|
|
<tt>my_vector<double></tt>.
|
|
|
|
The BLL has traits classes to perform the implicit built-in and standard
|
|
type conversions between integral, floating point, and complex classes.
|
|
|
|
Using BLL tools, the addition operator described above can be defined as:
|
|
|
|
<pre class="programlisting">
|
|
template<class A, class B>
|
|
my_vector<typename return_type_2<arithmetic_action<plus_action>, A, B>::type>
|
|
operator+(const my_vector<A>& a, const my_vector<B>& b)
|
|
{
|
|
typedef typename
|
|
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
|
|
return my_vector<res_type>();
|
|
}
|
|
</pre>
|
|
</p><p>
|
|
To allow BLL to deduce the type of <tt>my_vector</tt>
|
|
additions correctly, we can define:
|
|
|
|
<pre class="programlisting">
|
|
template<class A, class B>
|
|
class plain_return_type_2<arithmetic_action<plus_action>,
|
|
my_vector<A>, my_vector<B> > {
|
|
typedef typename
|
|
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
|
|
public:
|
|
typedef my_vector<res_type> type;
|
|
};
|
|
</pre>
|
|
Note, that we are reusing the existing specializations for the
|
|
BLL <tt>return_type_2</tt> template,
|
|
which require that the argument types are references.
|
|
</p><div class="table"><p><a name="table:actions"></a><b>Table 2. Action types</b></p><table summary="Action types" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt>+</tt></td><td><tt>arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>arithmetic_action<minus_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>arithmetic_action<multiply_action></tt></td></tr><tr><td><tt>/</tt></td><td><tt>arithmetic_action<divide_action></tt></td></tr><tr><td><tt>%</tt></td><td><tt>arithmetic_action<remainder_action></tt></td></tr><tr><td><tt>+</tt></td><td><tt>unary_arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>unary_arithmetic_action<minus_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>bitwise_action<and_action></tt></td></tr><tr><td><tt>|</tt></td><td><tt>bitwise_action<or_action></tt></td></tr><tr><td><tt>~</tt></td><td><tt>bitwise_action<not_action></tt></td></tr><tr><td><tt>^</tt></td><td><tt>bitwise_action<xor_action></tt></td></tr><tr><td><tt><<</tt></td><td><tt>bitwise_action<leftshift_action_no_stream></tt></td></tr><tr><td><tt>>></tt></td><td><tt>bitwise_action<rightshift_action_no_stream></tt></td></tr><tr><td><tt>&&</tt></td><td><tt>logical_action<and_action></tt></td></tr><tr><td><tt>||</tt></td><td><tt>logical_action<or_action></tt></td></tr><tr><td><tt>!</tt></td><td><tt>logical_action<not_action></tt></td></tr><tr><td><tt><</tt></td><td><tt>relational_action<less_action></tt></td></tr><tr><td><tt>></tt></td><td><tt>relational_action<greater_action></tt></td></tr><tr><td><tt><=</tt></td><td><tt>relational_action<lessorequal_action></tt></td></tr><tr><td><tt>>=</tt></td><td><tt>relational_action<greaterorequal_action></tt></td></tr><tr><td><tt>==</tt></td><td><tt>relational_action<equal_action></tt></td></tr><tr><td><tt>!=</tt></td><td><tt>relational_action<notequal_action></tt></td></tr><tr><td><tt>+=</tt></td><td><tt>arithmetic_assignment_action<plus_action></tt></td></tr><tr><td><tt>-=</tt></td><td><tt>arithmetic_assignment_action<minus_action></tt></td></tr><tr><td><tt>*=</tt></td><td><tt>arithmetic_assignment_action<multiply_action></tt></td></tr><tr><td><tt>/=</tt></td><td><tt>arithmetic_assignment_action<divide_action></tt></td></tr><tr><td><tt>%=</tt></td><td><tt>arithmetic_assignment_action<remainder_action></tt></td></tr><tr><td><tt>&=</tt></td><td><tt>bitwise_assignment_action<and_action></tt></td></tr><tr><td><tt>=|</tt></td><td><tt>bitwise_assignment_action<or_action></tt></td></tr><tr><td><tt>^=</tt></td><td><tt>bitwise_assignment_action<xor_action></tt></td></tr><tr><td><tt><<=</tt></td><td><tt>bitwise_assignment_action<leftshift_action></tt></td></tr><tr><td><tt>>>=</tt></td><td><tt>bitwise_assignment_action<rightshift_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>pre_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>pre_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>post_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>post_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>other_action<address_of_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>other_action<contents_of_action></tt></td></tr><tr><td><tt>,</tt></td><td><tt>other_action<comma_action></tt></td></tr></tbody></table></div></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2796882"></a>7. Practical considerations</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2796888"></a>7.1. Performance</h3></div></div><p>In theory, all overhead of using STL algorithms and lambda functors
|
|
compared to hand written loops can be optimized away, just as the overhead
|
|
from standard STL function objects and binders can.
|
|
|
|
Depending on the compiler, this can also be true in practice.
|
|
We ran two tests with the GCC 3.0.4 compiler on 1.5 GHz Intel Pentium 4.
|
|
The optimization flag -03 was used.
|
|
</p><p>
|
|
In the first test we compared lambda functors against explicitly written
|
|
function objects.
|
|
We used both of these styles to define unary functions which multiply the
|
|
argument repeatedly by itself.
|
|
We started with the identity function, going up to
|
|
x<sup>5</sup>.
|
|
The expressions were called inside a <tt>std::transform</tt> loop,
|
|
reading the argument from one <tt>std::vector<int></tt>
|
|
and placing the result into another.
|
|
The length of the vectors was 100 elements.
|
|
The running times are listed in
|
|
<a href="#table:increasing_arithmetic_test" title="Table 3. Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
|
|
The running times are expressed in arbitrary units.">Table 3</a>.
|
|
|
|
We can observe that there is no significant difference between the
|
|
two approaches.
|
|
</p><p>
|
|
In the second test we again used <tt>std::transform</tt> to
|
|
perform an operation to each element in a 100-element long vector.
|
|
This time the element type of the vectors was <tt>double</tt>
|
|
and we started with very simple arithmetic expressions and moved to
|
|
more complex ones.
|
|
The running times are listed in <a href="#table:ll_vs_stl_test" title="Table 4. Test 2. CPU time of arithmetic expressions written as lambda
|
|
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
|
|
Using BLL terminology,
|
|
a and b are bound arguments in the expressions, and x is open.
|
|
All variables were of types double.
|
|
The running times are expressed in arbitrary units.">Table 4</a>.
|
|
|
|
Here, we also included classic STL style unnamed functions into tests.
|
|
We do not show these expressions, as they get rather complex.
|
|
For example, the
|
|
last expression in <a href="#table:ll_vs_stl_test" title="Table 4. Test 2. CPU time of arithmetic expressions written as lambda
|
|
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
|
|
Using BLL terminology,
|
|
a and b are bound arguments in the expressions, and x is open.
|
|
All variables were of types double.
|
|
The running times are expressed in arbitrary units.">Table 4</a> written with
|
|
classic STL tools contains 7 calls to <tt>compose2</tt>,
|
|
8 calls to <tt>bind1st</tt>
|
|
and altogether 14 constructor invocations for creating
|
|
<tt>multiplies</tt>, <tt>minus</tt>
|
|
and <tt>plus</tt> objects.
|
|
|
|
In this test the BLL expressions are a little slower (roughly 10% on average,
|
|
less than 14% in all cases)
|
|
than the corresponding hand-written function objects.
|
|
The performance hit is a bit greater with classic STL expressions,
|
|
up to 27% for the simplest expressios.
|
|
</p><p>
|
|
The tests suggest that the BLL does not introduce a loss of performance
|
|
compared to STL function objects.
|
|
With a reasonable optimizing compiler, one should expect the performance characteristics be comparable to using classic STL.
|
|
Moreover, with simple expressions the performance can be expected to be close
|
|
to that of explicitly written function objects.
|
|
|
|
|
|
|
|
Note however, that evaluating a lambda functor consist of a sequence of calls to small functions that are declared inline.
|
|
If the compiler fails to actually expand these functions inline,
|
|
the performance can suffer.
|
|
The running time can more than double if this happens.
|
|
Although the above tests do not include such an expression, we have experiensed
|
|
this for some seemingly simple expressions.
|
|
|
|
|
|
<div class="table"><p><a name="table:increasing_arithmetic_test"></a><b>Table 3. Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
|
|
The running times are expressed in arbitrary units.</b></p><table summary="Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
|
|
The running times are expressed in arbitrary units." border="1"><colgroup><col><col><col></colgroup><thead><tr><th>expression</th><th>lambda expression</th><th>hand-coded function object</th></tr></thead><tbody><tr><td>x</td><td>240</td><td>230</td></tr><tr><td>x*x</td><td>340</td><td>350</td></tr><tr><td>x*x*x</td><td>770</td><td>760</td></tr><tr><td>x*x*x*x</td><td>1180</td><td>1210</td></tr><tr><td>x*x*x*x*x</td><td>1950</td><td>1910</td></tr></tbody></table></div>
|
|
</p><p>
|
|
<div class="table"><p><a name="table:ll_vs_stl_test"></a><b>Table 4. Test 2. CPU time of arithmetic expressions written as lambda
|
|
expressions, as classic STL unnamed functions (using <tt>compose2</tt>, <tt>bind1st</tt> etc.) and as traditional hand-coded function object classes.
|
|
Using BLL terminology,
|
|
<tt>a</tt> and <tt>b</tt> are bound arguments in the expressions, and <tt>x</tt> is open.
|
|
All variables were of types <tt>double</tt>.
|
|
The running times are expressed in arbitrary units.</b></p><table summary="Test 2. CPU time of arithmetic expressions written as lambda
|
|
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
|
|
Using BLL terminology,
|
|
a and b are bound arguments in the expressions, and x is open.
|
|
All variables were of types double.
|
|
The running times are expressed in arbitrary units." border="1"><colgroup><col><col><col><col></colgroup><thead><tr><th>expression</th><th>lambda expression</th><th>classic STL expression</th><th>hand-coded function object</th></tr></thead><tbody><tr><td>ax</td><td>330</td><td>370</td><td>290</td></tr><tr><td>-ax</td><td>350</td><td>370</td><td>310</td></tr><tr><td>ax-(a+x)</td><td>470</td><td>500</td><td>420</td></tr><tr><td>(ax-(a+x))(a+x)</td><td>620</td><td>670</td><td>600</td></tr><tr><td>((ax) - (a+x))(bx - (b+x))(ax - (b+x))(bx - (a+x))</td><td>1660</td><td>1660</td><td>1460</td></tr></tbody></table></div>
|
|
</p><p>Some additional performance testing with an earlier version of the
|
|
library is described
|
|
[<a href="#cit:jarvi:00" title="[Jär00]">Jär00</a>].
|
|
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2797381"></a>7.2. About compiling</h3></div></div><p>The BLL uses templates rather heavily, performing numerous recursive instantiations of the same templates.
|
|
This has (at least) three implications:
|
|
<div class="itemizedlist"><ul type="disc"><li><p>
|
|
While it is possible to write incredibly complex lambda expressions, it probably isn't a good idea.
|
|
Compiling such expressions may end up requiring a lot of memory
|
|
at compile time, and being slow to compile.
|
|
</p></li><li><p>
|
|
The types of lambda functors that result from even the simplest lambda expressions are cryptic.
|
|
Usually the programmer doesn't need to deal with the lambda functor the types at all, but in the case of an error in a lambda expression, the compiler usually outputs the types of the lambda functors involved.
|
|
This can make the error messages very long and difficult to interpret, particularly if the compiler outputs the whole chain of template instantiations.
|
|
</p></li><li><p>
|
|
The C++ Standard suggests a template nesting level of 17 to help detect infinite recursion.
|
|
Complex lambda templates can easily exceed this limit.
|
|
Most compilers allow a greater number of nested templates, but commonly require the limit explicitly increased with a command line argument.
|
|
</p></li></ul></div></p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2797442"></a>7.3. Portability</h3></div></div><p>
|
|
The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL:
|
|
|
|
<div class="itemizedlist"><ul type="disc"><li>GCC 3.0.4
|
|
</li><li>KCC 4.0f with EDG 2.43.1
|
|
</li><li>GCC 2.96 (fails with one test case, the <tt>exception_test.cpp</tt> results in an internal compiler error.
|
|
)
|
|
|
|
</li></ul></div>
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2797481"></a>7.3.1. Test coverage</h4></div></div><p>The following list describes the test files included and the features that each file covers:
|
|
|
|
<div class="itemizedlist"><ul type="disc"><li><p>
|
|
<tt>bind_tests_simple.cpp</tt> : Bind expressions of different arities and types of target functions: function pointers, function objects and member functions.
|
|
Function composition with bind expressions.</p></li><li><p><tt>bind_tests_simple_function_references.cpp</tt> :
|
|
Repeats all tests from <tt>bind_tests_simple.cpp</tt> where the target function is a function pointer, but uses function references instead.
|
|
</p></li><li><p><tt>bind_tests_advanced.cpp</tt> : Contains tests for nested bind expressions, <tt>unlambda</tt>, <tt>protect</tt>, <tt>const_parameters</tt> and <tt>break_const</tt>.
|
|
Tests passing lambda functors as actual arguments to other lambda functors, currying, and using the <tt>sig</tt> template to specify the return type of a function object.
|
|
</p></li><li><p>
|
|
<tt>operator_tests_simple.cpp</tt> :
|
|
Tests using all operators that are overloaded for lambda expressions, that is, unary and binary arithmetic,
|
|
bitwise,
|
|
comparison,
|
|
logical,
|
|
increment and decrement,
|
|
compound,
|
|
assignment,
|
|
subscrict,
|
|
address of,
|
|
dereference, and comma operators.
|
|
The streaming nature of shift operators is tested, as well as pointer arithmetic with plus and minus operators.
|
|
</p></li><li><p><tt>member_pointer_test.cpp</tt> : The pointer to member operator is complex enough to warrant a separate test file.
|
|
</p></li><li><p>
|
|
<tt>control_structures.cpp</tt> :
|
|
Tests for the looping and if constructs.
|
|
</p></li><li><p>
|
|
<tt>switch_construct.cpp</tt> :
|
|
Includes tests for all supported arities of the switch statement, both with and without the default case.
|
|
</p></li><li><p>
|
|
<tt>exception_test.cpp</tt> :
|
|
Includes tests for throwing exceptions and for try/catch constructs with varying number of catch blocks.
|
|
</p></li><li><p>
|
|
<tt>constructor_tests.cpp</tt> :
|
|
Contains tests for <tt>constructor</tt>, <tt>destructor</tt>, <tt>new_ptr</tt>, <tt>delete_ptr</tt>, <tt>new_array</tt> and <tt>delete_array</tt>.
|
|
</p></li><li><p>
|
|
<tt>cast_test.cpp</tt> : Tests for the four cast expressions, as well as <tt>typeid</tt> and <tt>sizeof</tt>.
|
|
</p></li><li><p>
|
|
<tt>extending_return_type_traits.cpp</tt> : Tests extending the return type deduction system for user defined types.
|
|
Contains several user defined operators and the corresponding specializations for the return type deduction templates.
|
|
</p></li><li><p>
|
|
<tt>is_instance_of_test.cpp</tt> : Includes tests for an internally used traits template, which can detect whether a given type is an instance of a certain template or not.
|
|
</p></li><li><p>
|
|
<tt>bll_and_function.cpp</tt> :
|
|
Contains tests for using <tt>boost::function</tt> together with lambda functors.
|
|
</p></li></ul></div>
|
|
|
|
</p></div></div></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2797826"></a>8. Relation to other Boost libraries</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2797834"></a>8.1. Boost Function</h3></div></div><p>Sometimes it is convenient to store lambda functors in variables.
|
|
However, the types of even the simplest lambda functors are long and unwieldy, and it is in general unfeasible to declare variables with lambda functor types.
|
|
<span class="emphasis"><i>The Boost Function library</i></span> [<a href="#cit:boost::function" title="[function]">function</a>] defines wrappers for arbitrary function objects, for example
|
|
lambda functors; and these wrappers have types that are easy to type out.
|
|
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
boost::function<int(int, int)> f = _1 + _2;
|
|
boost::function<int&(int&)> g = (_1 += 10);
|
|
int i = 1, j = 2;
|
|
f(i); // returns 3
|
|
g(i); // sets i to = 11;
|
|
</pre>
|
|
|
|
The return and parameter types of the wrapped function object must be written explicilty as the template argument to the wrapper template <tt>boost::function</tt>; even when lambda functors, which otherwise have generic parameters, are wrapped.
|
|
Wrapping a function object with <tt>boost::function</tt> introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used.
|
|
|
|
Note that storing lambda functors inside <tt>boost::function</tt>
|
|
introduces a danger.
|
|
Certain types of lambda functors may store references to the bound
|
|
arguments, instead as taking copies of the arguments of the lambda expression.
|
|
When temporary lambda functor objects are used
|
|
in STL algorithm invocations this is always safe, as the lambda functor gets
|
|
destructed immediately after the STL algortihm invocation is completed.
|
|
|
|
However, a lambda functor wrapped inside <tt>boost::function</tt>
|
|
may continue to exist longer, creating the possibility of dangling references.
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
int* sum = new int();
|
|
*sum = 0;
|
|
boost::function<int&(int)> counter = *sum += _1;
|
|
counter(5); // ok, *sum = 5;
|
|
delete sum;
|
|
counter(3); // error, *sum does not exist anymore
|
|
</pre>
|
|
|
|
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2797938"></a>8.2. Boost Bind</h3></div></div><p>
|
|
<span class="emphasis"><i>The Boost Bind</i></span> [<a href="#cit:boost::bind" title="[bind]">bind</a>] library has partially overlapping functionality with the BLL.
|
|
Basically, the Boost Bind library (BB in the sequel) implements the bind expression part of BLL.
|
|
There are, however, some semantical differerences.
|
|
</p><p>
|
|
The BLL and BB evolved separately, and have different implementations.
|
|
This means that the bind expressions from the BB cannot be used within
|
|
bind expressions, or within other type of lambda expressions, of the BLL.
|
|
The same holds for using BLL bind expressions in the BB.
|
|
The libraries can coexist, however, as
|
|
the names of the BB library are in <tt>boost</tt> namespace,
|
|
whereas the BLL names are in <tt>boost::lambda</tt> namespace.
|
|
</p><p>
|
|
The BLL requires a compiler that is reasonably conformant to the
|
|
C++ standard, whereas the BB library is more portable, and works with
|
|
a larger set of compilers.
|
|
</p><p>
|
|
The following two sections describe what are the semantic differences
|
|
between the bind expressions in BB and BLL.
|
|
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2798002"></a>8.2.1. First argument of bind expression</h4></div></div>
|
|
|
|
In BB the first argument of the bind expression, the target function,
|
|
is treated differently from the other arguments,
|
|
as no argument substitution takes place within that argument.
|
|
In BLL the first argument is not a special case in this respect.
|
|
|
|
For example:
|
|
|
|
<pre class="programlisting">
|
|
template<class F>
|
|
int foo(const F& f) {
|
|
int x;
|
|
..
|
|
bind(f, _1)(x);
|
|
...
|
|
}
|
|
</pre><pre class="programlisting">
|
|
int bar(int, int);
|
|
nested(bind(bar, 1, _1));
|
|
</pre>
|
|
|
|
The bind expression inside <tt>foo</tt> becomes:
|
|
<pre class="programlisting">
|
|
bind(bind(bar, 1, _1), _1)(x)
|
|
</pre>
|
|
|
|
The BLL interpretes this as:
|
|
<pre class="programlisting">
|
|
bar(1, x)(x)
|
|
</pre>
|
|
whereas the BB library as
|
|
<pre class="programlisting">
|
|
bar(1, x)
|
|
</pre>
|
|
|
|
To get this functionality in BLL, the bind expression inside the <tt>foo</tt> function can be written as:
|
|
<pre class="programlisting">
|
|
bind(unlambda(f), _1)(x);
|
|
</pre>
|
|
as explained in <a href="#sect:unlambda" title="5.9.1.1. Unlambda">Section 5.9.1.1</a>.
|
|
|
|
</div><p>
|
|
The BB library supports up to nine placeholders, while the BLL
|
|
defines only three placeholders.
|
|
The rationale for not providing more, is that the highest arity of the
|
|
function objects accepted by any STL algorithm is two.
|
|
The placeholder count is easy to increase in the BB library.
|
|
In BLL it is possible, but more laborous.
|
|
The BLL currently passes the actual arguments to the lambda functors
|
|
internally just as they are and does not wrap them inside a tuple object.
|
|
The reason for this is that some widely used compilers are not capable
|
|
of optimizing the intermediate tuple objects away.
|
|
The creation of the intermediate tuples would cause a significant
|
|
performance hit, particularly for the simplest (and thus the most common)
|
|
lambda functors.
|
|
We are working on a hybrid approach, which will allow more placeholders
|
|
but not compromise the performance of simple lambda functors.
|
|
</p></div></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2798134"></a>9. Contributors</h2></div></div>
|
|
|
|
The main body of the library was written by Jaakko Järvi and Gary Powell.
|
|
We've got outside help, suggestions and ideas from Jeremy Siek, Peter Higley, Peter Dimov, Valentin Bonnard, William Kempf.
|
|
We would particularly like to mention Joel de Guzmann and his work with
|
|
Phoenix which has influenced BLL significantly, making it considerably simpler
|
|
to extend the library with new features.
|
|
|
|
</div><div class="appendix"><h2 class="title" style="clear: both"><a name="id2798156"></a>A. Rationale for some of the design decisions</h2><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:why_weak_arity"></a>1.
|
|
Lambda functor arity
|
|
</h3></div></div><p>
|
|
The highest placeholder index in a lambda expression determines the arity of the resulting function object.
|
|
However, this is just the minimal arity, as the function object can take arbitrarily many arguments; those not needed are discarded.
|
|
Consider the two bind expressions and their invocations below:
|
|
|
|
<pre class="programlisting">
|
|
bind(g, _3, _3, _3)(x, y, z);
|
|
bind(g, _1, _1, _1)(x, y, z);
|
|
</pre>
|
|
|
|
This first line discards arguments <tt>x</tt> and
|
|
<tt>y</tt>, and makes the call:
|
|
<pre class="programlisting">
|
|
g(z, z, z)
|
|
</pre>
|
|
whereas the second line discards arguments <tt>y</tt> and
|
|
<tt>z</tt>, and calls:
|
|
<pre class="programlisting">
|
|
g(x, x, x)
|
|
</pre>
|
|
In earlier versions of the library, the latter line resulted in a compile
|
|
time error.
|
|
|
|
This is basically a tradeoff between safety and flexibility, and the issue
|
|
was extensively discussed during the Boost review period of the library.
|
|
The main points for the <span class="emphasis"><i>strict arity</i></span> checking
|
|
was that it might
|
|
catch a programming error at an earlier time and that a lambda expression that
|
|
explicitly discards its arguments is easy to write:
|
|
<pre class="programlisting">
|
|
(_3, bind(g, _1, _1, _1))(x, y, z);
|
|
</pre>
|
|
This lambda expression takes three arguments.
|
|
The left-hand argument of the comma operator does nothing, and as comma
|
|
returns the result of evaluating the right-hand argument we end up with
|
|
the call
|
|
<tt>g(x, x, x)</tt>
|
|
even with the strict arity.
|
|
</p><p>
|
|
The main points against the strict arity checking were that the need to
|
|
discard arguments is commonplace, and should therefore be straightforward,
|
|
and that strict arity checking does not really buy that much more safety,
|
|
particularly as it is not symmetric.
|
|
For example, if the programmer wanted to write the expression
|
|
<tt>_1 + _2</tt> but mistakenly wrote <tt>_1 + 2</tt>,
|
|
with strict arity checking, the complier would spot the error.
|
|
However, if the erroneous expression was <tt>1 + _2</tt> instead,
|
|
the error would go unnoticed.
|
|
Furthermore, weak arity checking simplifies the implementation a bit.
|
|
Following the recommendation of the Boost review, strict arity checking
|
|
was dropped.
|
|
</p></div></div><div id="id2798308" class="bibliography"><div class="titlepage"><div><h2 class="title"><a name="id2798308"></a>Bibliography</h2></div></div><div class="biblioentry"><a name="cit:stepanov:94"></a><p>[STL94] <span class="authorgroup">A. A. Stepanov and M. Lee. </span><span class="title"><I>The Standard Template Library</I>. </span><span class="orgname">Hewlett-Packard Laboratories. </span><span class="pubdate">1994. </span><span class="bibliomisc">
|
|
<a href="http://www.hpl.hp.com/techreports" target="_top">www.hpl.hp.com/techreports</a>
|
|
. </span></p></div><div class="biblioentry"><a name="cit:sgi:02"></a><p>[SGI02] <span class="title"><I>The SGI Standard Template Library</I>. </span><span class="pubdate">2002. </span><span class="bibliomisc"><a href="http://www.sgi.com/tech/stl/" target="_top">www.sgi.com/tech/stl/</a>. </span></p></div><div class="biblioentry"><a name="cit:c++:98"></a><p>[C++98] <span class="title"><I>International Standard, Programming Languages – C++</I>. </span><span class="subtitle">ISO/IEC:14882. </span><span class="pubdate">1998. </span></p></div><div class="biblioentry"><a name="cit:jarvi:99"></a><p>[Jär99] <span class="articleinfo">
|
|
<span class="author">Jaakko Järvi. </span>
|
|
<span class="title"><I>C++ Function Object Binders Made Easy</I>. </span>
|
|
. </span><span class="title"><I>Lecture Notes in Computer Science</I>. </span><span class="volumenum">1977. </span><span class="publishername">Springer. </span><span class="pubdate">2000. </span></p></div><div class="biblioentry"><a name="cit:jarvi:00"></a><p>[Jär00] <span class="author">Jaakko Järvi. </span><span class="author">Gary Powell. </span><span class="title"><I>The Lambda Library : Lambda Abstraction in C++</I>. </span><span class="orgname">Turku Centre for Computer Science. </span><span class="bibliomisc">Technical Report . </span><span class="issuenum">378. </span><span class="pubdate">2000. </span><span class="bibliomisc"><a href="http://www.tucs.fi/Publications/techreports/TR378.php" target="_top">www.tucs.fi/publications</a>. </span></p></div><div class="biblioentry"><a name="cit:jarvi:01"></a><p>[Jär01] <span class="author">Jaakko Järvi. </span><span class="author">Gary Powell. </span><span class="title"><I>The Lambda Library : Lambda Abstraction in C++</I>. </span><span class="confgroup"><span class="conftitle">Second Workshop on C++ Template Programming. </span><span class="address">Tampa Bay, OOPSLA'01. </span>. </span><span class="pubdate">2001. </span><span class="bibliomisc"><a href="http://www.oonumerics.org/tmpw01/" target="_top">www.oonumerics.org/tmpw01/</a>. </span></p></div><div class="biblioentry"><a name="cit:boost::tuple"></a><p>[tuple] <span class="title"><I>The Boost Tuple Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html" target="_top">www.boost.org/libs/tuple/doc/tuple_users_guide.html</a>
|
|
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::type_traits"></a><p>[type_traits] <span class="title"><I>The Boost type_traits</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/type_traits/index.htm" target="_top">www.boost.org/libs/type_traits/</a>
|
|
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::ref"></a><p>[ref] <span class="title"><I>Boost ref</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/ref.html" target="_top">www.boost.org/libs/bind/ref.html</a>
|
|
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::bind"></a><p>[bind] <span class="title"><I>Boost Bind Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/bind.html" target="_top">www.boost.org/libs/bind/bind.html</a>
|
|
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::function"></a><p>[function] <span class="title"><I>Boost Function Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/function/" target="_top">www.boost.org/libs/function/</a>
|
|
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:fc++"></a><p>[fc++] <span class="title"><I>The FC++ library: Functional Programming in C++</I>. </span><span class="author">Yannis Smaragdakis. </span><span class="author">Brian McNamara. </span><span class="bibliomisc"><a href="http://www.cc.gatech.edu/~yannis/fc++/" target="_top">www.cc.gatech.edu/~yannis/fc++/</a>
|
|
. </span><span class="pubdate">2002. </span></p></div></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id2729061" href="#id2729061">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></body></html>
|