diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-06-25 22:59:01 +0000 |
|---|---|---|
| committer | <> | 2013-09-27 11:49:28 +0000 |
| commit | 8c4528713d907ee2cfd3bfcbbad272c749867f84 (patch) | |
| tree | c09e2ce80f47b90c85cc720f5139089ad9c8cfff /libs/lambda | |
| download | boost-tarball-baserock/morph.tar.gz | |
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_54_0.tar.bz2.boost_1_54_0baserock/morph
Diffstat (limited to 'libs/lambda')
30 files changed, 11208 insertions, 0 deletions
diff --git a/libs/lambda/doc/Jamfile.v2 b/libs/lambda/doc/Jamfile.v2 new file mode 100644 index 000000000..1723bb732 --- /dev/null +++ b/libs/lambda/doc/Jamfile.v2 @@ -0,0 +1,12 @@ +project boost/doc ; +import boostbook : boostbook ; + +# Are these really the correct images?? +path-constant images : ../../spirit/phoenix/doc/html ; + +boostbook lambda-doc : lambda.xml +: + <xsl:param>boost.root=../../../.. + <format>pdf:<xsl:param>img.src.path=$(images)/ +; + diff --git a/libs/lambda/doc/detail/README b/libs/lambda/doc/detail/README new file mode 100644 index 000000000..51d75a9de --- /dev/null +++ b/libs/lambda/doc/detail/README @@ -0,0 +1,7 @@ +- lambda_doc.xml is a DocBook xml file from which the lambda docs are +generated +- lambda_doc_chunks.xsl loads the stylesheets that generate a separate +html-file for each section +- lambda_doc.xsl loads stylesheets that generate one big html-file +(you need to edit the paths in these files to make them work) + diff --git a/libs/lambda/doc/detail/lambda_doc.xml b/libs/lambda/doc/detail/lambda_doc.xml new file mode 100644 index 000000000..42522cb38 --- /dev/null +++ b/libs/lambda/doc/detail/lambda_doc.xml @@ -0,0 +1,3456 @@ +<?xml version="1.0" encoding="ISO-Latin-1"?> +<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" + "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<library name="Lambda" dirname="lambda" id="lambda" + last-revision="$Date: 2008-03-22 14:45:55 -0700 (Sat, 22 Mar 2008) $" + xmlns:xi="http://www.w3.org/2001/XInclude"> +<libraryinfo> + <author> + <firstname>Jaakko</firstname> + <surname>Järvi</surname> + <email>jarvi at cs tamu edu</email> + </author> + + <copyright> + <year>1999</year> + <year>2000</year> + <year>2001</year> + <year>2002</year> + <year>2003</year> + <year>2004</year> + <holder>Jaakko Järvi</holder> + <holder>Gary Powell</holder> + </copyright> + + <legalnotice> + <para>Use, modification and distribution is subject to the Boost + Software License, Version 1.0. (See accompanying file + <filename>LICENSE_1_0.txt</filename> or copy at <ulink + url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)</para> + </legalnotice> + + <librarypurpose>Define small unnamed function objects at the actual call site, and more</librarypurpose> + <librarycategory name="category:higher-order"/> +</libraryinfo> + + <!-- --> + + <section id="introduction"> + + <title>In a nutshell</title> + + <para> + + The Boost Lambda Library (BLL in the sequel) is a C++ template + library, which implements form of <emphasis>lambda abstractions</emphasis> 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 + <literal>a</literal> separated by spaces: + + <programlisting><![CDATA[for_each(a.begin(), a.end(), std::cout << _1 << ' ');]]></programlisting> + + The expression <literal><![CDATA[std::cout << _1 << ' ']]></literal> defines a unary function object. + The variable <literal>_1</literal> is the parameter of this function, a <emphasis>placeholder</emphasis> for the actual argument. + Within each iteration of <literal>for_each</literal>, the function is + called with an element of <literal>a</literal> as the actual argument. + This actual argument is substituted for the placeholder, and the <quote>body</quote> of the function is evaluated. + </para> + + <para>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. + </para> + </section> + + <section id="sect:getting_started"> + <title>Getting Started</title> + + <section> + <title>Installing the library</title> + + + <para> + The library consists of include files only, hence there is no + installation procedure. The <literal>boost</literal> include directory + must be on the include path. + There are a number of include files that give different functionality: + + <!-- TODO: tarkista vielä riippuvuudet--> + <itemizedlist> + + <listitem><para> + <filename>lambda/lambda.hpp</filename> defines lambda expressions for different C++ + operators, see <xref linkend="sect:operator_expressions"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/bind.hpp</filename> defines <literal>bind</literal> functions for up to 9 arguments, see <xref linkend="sect:bind_expressions"/>.</para></listitem> + + + <listitem><para> + <filename>lambda/if.hpp</filename> defines lambda function equivalents for if statements and the conditional operator, see <xref linkend="sect:lambda_expressions_for_control_structures"/> (includes <filename>lambda.hpp</filename>). + </para></listitem> + + <listitem><para> + <filename>lambda/loops.hpp</filename> defines lambda function equivalent for looping constructs, see <xref linkend="sect:lambda_expressions_for_control_structures"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/switch.hpp</filename> defines lambda function equivalent for the switch statement, see <xref linkend="sect:lambda_expressions_for_control_structures"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/construct.hpp</filename> provides tools for writing lambda expressions with constructor, destructor, new and delete invocations, see <xref linkend="sect:construction_and_destruction"/> (includes <filename>lambda.hpp</filename>). + </para></listitem> + + <listitem><para> + <filename>lambda/casts.hpp</filename> provides lambda versions of different casts, as well as <literal>sizeof</literal> and <literal>typeid</literal>, see <xref linkend="sect:cast_expressions"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/exceptions.hpp</filename> gives tools for throwing and catching + exceptions within lambda functions, <xref linkend="sect:exceptions"/> (includes + <filename>lambda.hpp</filename>). + </para></listitem> + + <listitem><para> + <filename>lambda/algorithm.hpp</filename> and <filename>lambda/numeric.hpp</filename> (cf. standard <filename>algortihm</filename> and <filename>numeric</filename> headers) allow nested STL algorithm invocations, see <xref linkend="sect:nested_stl_algorithms"/>. + </para></listitem> + + </itemizedlist> + + Any other header files in the package are for internal use. + Additionally, the library depends on two other Boost Libraries, the + <emphasis>Tuple</emphasis> <xref linkend="cit:boost::tuple"/> and the <emphasis>type_traits</emphasis> <xref linkend="cit:boost::type_traits"/> libraries, and on the <filename>boost/ref.hpp</filename> header. + </para> + + <para> + All definitions are placed in the namespace <literal>boost::lambda</literal> and its subnamespaces. + </para> + + </section> + + <section> + <title>Conventions used in this document</title> + + <para>In most code examples, we omit the namespace prefixes for names in the <literal moreinfo="none">std</literal> and <literal moreinfo="none">boost::lambda</literal> namespaces. +Implicit using declarations +<programlisting> +using namespace std; +using namespace boost::lambda; +</programlisting> +are assumed to be in effect. +</para> + + </section> + </section> + + <section> + <title>Introduction</title> + + <section> + <title>Motivation</title> + <para>The Standard Template Library (STL) + <xref role="citation" linkend="cit:stepanov:94"/>, now part of the C++ Standard Library <xref role="citation" linkend="cit:c++:98"/>, is a generic container and algorithm library. +Typically STL algorithms operate on container elements via <emphasis>function objects</emphasis>. These function objects are passed as arguments to the algorithms. +</para> + +<para> +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 <literal>plus</literal>, <literal>less</literal> and <literal>not1</literal>). +As an example, one possible implementation for the standard <literal>plus</literal> template is: + +<programlisting> +<![CDATA[template <class T> +struct plus : public binary_function<T, T, T> { + T operator()(const T& i, const T& j) const { + return i + j; + } +};]]> +</programlisting> + +The base class <literal><![CDATA[binary_function<T, T, T>]]></literal> contains typedefs for the argument and return types of the function object, which are needed to make the function object <emphasis>adaptable</emphasis>. +</para> + +<para> +In addition to the basic function object classes, such as the one above, +the STL contains <emphasis>binder</emphasis> 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: + +<programlisting> +<![CDATA[class plus_1 { + int _i; +public: + plus_1(const int& i) : _i(i) {} + int operator()(const int& j) { return _i + j; } +};]]> +</programlisting> + +the equivalent functionality can be achieved with the <literal moreinfo="none">plus</literal> template and one of the binder templates (<literal moreinfo="none">bind1st</literal>). +E.g., the following two expressions create function objects with identical functionalities; +when invoked, both return the result of adding <literal moreinfo="none">1</literal> to the argument of the function object: + +<programlisting> +<![CDATA[plus_1(1) +bind1st(plus<int>(), 1)]]> +</programlisting> + +The subexpression <literal><![CDATA[plus<int>()]]></literal> in the latter line is a binary function object which computes the sum of two integers, and <literal>bind1st</literal> invokes this function object partially binding the first argument to <literal>1</literal>. +As an example of using the above function object, the following code adds <literal>1</literal> to each element of some container <literal>a</literal> and outputs the results into the standard output stream <literal>cout</literal>. + +<programlisting> +<![CDATA[transform(a.begin(), a.end(), ostream_iterator<int>(cout), + bind1st(plus<int>(), 1));]]> +</programlisting> + +</para> + +<para> +To make the binder templates more generally applicable, the STL contains <emphasis>adaptors</emphasis> 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 <xref linkend="cit:sgi:02"/>. + </para> + +<para> +All these tools aim at one goal: to make it possible to specify +<emphasis>unnamed functions</emphasis> 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. +</para> + +<para> +The Boost Lambda Library provides solutions for the problems described above: + +<itemizedlist> +<listitem> +<para> +Unnamed functions can be created easily with an intuitive syntax. + +The above example can be written as: + +<programlisting> +<![CDATA[transform(a.begin(), a.end(), ostream_iterator<int>(cout), + 1 + _1);]]> +</programlisting> + +or even more intuitively: + +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), cout << (1 + _1));]]> +</programlisting> +</para> + +</listitem> + +<listitem> +<para> +Most of the restrictions in argument binding are removed, +arbitrary arguments of practically any C++ function can be bound. +</para> +</listitem> + +<listitem> +<para> +Separate function composition operations are not needed, +as function composition is supported implicitly. + +</para> +</listitem> + +</itemizedlist> + +</para> + +</section> + + + +<section> + <title>Introduction to lambda expressions</title> + + <para> + 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: + + +<programlisting> +lambda x<subscript>1</subscript> ... x<subscript>n</subscript>.e +</programlisting> + <!-- $\lambda x_1 \cdots x_n . e$ --> + + A lambda expression defines an unnamed function and consists of: + <itemizedlist> + <listitem> + <para> + the parameters of this function: <literal>x<subscript>1</subscript> ... x<subscript>n</subscript></literal>. + <!--$x_1 \cdots x_n$--> + </para> + </listitem> + <listitem> + <para>the expression e which computes the value of the function in terms of the parameters <literal>x<subscript>1</subscript> ... x<subscript>n</subscript></literal>. + </para> + </listitem> + </itemizedlist> + + A simple example of a lambda expression is +<programlisting> +lambda x y.x+y +</programlisting> +Applying the lambda function means substituting the formal parameters with the actual arguments: +<programlisting> +(lambda x y.x+y) 2 3 = 2 + 3 = 5 +</programlisting> + + + </para> + +<para> +In the C++ version of lambda expressions the <literal>lambda x<subscript>1</subscript> ... x<subscript>n</subscript></literal> 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 <emphasis>placeholders</emphasis>: +<literal>_1</literal>, <literal>_2</literal> and <literal>_3</literal>. +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 +<programlisting>lambda x y.x+y</programlisting> +is +<programlisting>_1 + _2</programlisting> +</para> + + <para> +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 <literal>bind</literal> function. + + As an example, consider the lambda expression: + + <programlisting>lambda x y.foo(x,y)</programlisting> + + Rather than <literal>foo(_1, _2)</literal>, the C++ counterpart for this expression is: + + <programlisting>bind(foo, _1, _2)</programlisting> + + We refer to this type of C++ lambda expressions as <emphasis>bind expressions</emphasis>. + </para> + + <para>A lambda expression defines a C++ function object, hence function application syntax is like calling any other function object, for instance: <literal>(_1 + _2)(i, j)</literal>. + + + </para> + + + +<section id="sect:partial_function_application"> +<title>Partial function application</title> + +<para> +A bind expression is in effect a <emphasis>partial function application</emphasis>. +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. + </para> + +<!-- <para>The underlying implementation of the BLL unifies the two types of lambda expressions (bind expressions and lambda expressions consisting of operator calls). + If operators are regarded as functions, it is easy to see that lambda expressions using operators are partial function applications as well. + E.g. the lambda expression <literal>_1 + 1</literal> can be seen as syntactic sugar for the pseudo code <literal>bind(operator+, _1, 1)</literal>. + </para> +--> + + </section> + + + + <section id="sect:terminology"> + <title>Terminology</title> + + <para> + A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, <emphasis>a functor</emphasis>, when evaluated. We use the name <emphasis>lambda functor</emphasis> to refer to such a function object. + Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor. + </para> + + </section> + + </section> + + + + </section> + + <section id = "sect:using_library"> + <title>Using the library</title> + + <para> +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. + + + </para> + + <section id = "sect:introductory_examples"> + <title>Introductory Examples</title> + + <para> + 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 <literal>list</literal>, to the value <literal>1</literal>: + + + <programlisting> +<![CDATA[list<int> v(10); +for_each(v.begin(), v.end(), _1 = 1);]]></programlisting> + + The expression <literal>_1 = 1</literal> creates a lambda functor which assigns the value <literal>1</literal> to every element in <literal>v</literal>.<footnote> +<para> +Strictly taken, the C++ standard defines <literal>for_each</literal> as a <emphasis>non-modifying sequence operation</emphasis>, and the function object passed to <literal moreinfo="none">for_each</literal> should not modify its argument. +The requirements for the arguments of <literal>for_each</literal> are unnecessary strict, since as long as the iterators are <emphasis>mutable</emphasis>, <literal>for_each</literal> 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<literal>std::for_each</literal> but more fine-grained requirements for its arguments. +</para> +</footnote> + </para> + + <para> + Next, we create a container of pointers and make them point to the elements in the first container <literal>v</literal>: + + <programlisting> +<![CDATA[vector<int*> vp(10); +transform(v.begin(), v.end(), vp.begin(), &_1);]]></programlisting> + +The expression <literal><![CDATA[&_1]]></literal> creates a function object for getting the address of each element in <literal>v</literal>. +The addresses get assigned to the corresponding elements in <literal>vp</literal>. + </para> + + <para> + The next code fragment changes the values in <literal>v</literal>. + For each element, the function <literal>foo</literal> is called. +The original value of the element is passed as an argument to <literal>foo</literal>. +The result of <literal>foo</literal> is assigned back to the element: + + + <programlisting> +<![CDATA[int foo(int); +for_each(v.begin(), v.end(), _1 = bind(foo, _1));]]></programlisting> + </para> + + + <para> + The next step is to sort the elements of <literal>vp</literal>: + + <programlisting>sort(vp.begin(), vp.end(), *_1 > *_2);</programlisting> + + In this call to <literal>sort</literal>, we are sorting the elements by their contents in descending order. + </para> + + <para> + Finally, the following <literal>for_each</literal> call outputs the sorted content of <literal>vp</literal> separated by line breaks: + +<programlisting> +<![CDATA[for_each(vp.begin(), vp.end(), cout << *_1 << '\n');]]> +</programlisting> + +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 +<programlisting> +<![CDATA[for_each(vp.begin(), vp.end(), cout << '\n' << *_1);]]> +</programlisting> +the subexpression <literal><![CDATA[cout << '\n']]></literal> is evaluated immediately and the effect is to output a single line break, followed by the elements of <literal>vp</literal>. +The BLL provides functions <literal>constant</literal> and <literal>var</literal> to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions: +<programlisting> +<![CDATA[for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);]]> +</programlisting> +These functions are described more thoroughly in <xref linkend="sect:delaying_constants_and_variables"/> + +</para> + + + + + + </section> + + + <section id="sect:parameter_and_return_types"> + <title>Parameter and return types of lambda functors</title> + + <para> + 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 + <literal>_1 + _2</literal> creates a binary lambda functor. + It can be called with two objects of any types <literal>A</literal> and <literal>B</literal> for which <literal>operator+(A,B)</literal> is defined (and for which BLL knows the return type of the operator, see below). + </para> + + <para> + 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. + </para> + + <!-- TODO: move this forward, and just refer to it. --> + <para> + There are, however, cases when the return type cannot be deduced. For example, suppose you have defined: + + <programlisting>C operator+(A, B);</programlisting> + + The following lambda function invocation fails, since the return type cannot be deduced: + + <programlisting>A a; B b; (_1 + _2)(a, b);</programlisting> + </para> + + <para> + There are two alternative solutions to this. + The first is to extend the BLL type deduction system to cover your own types (see <xref linkend="sect:extending_return_type_system"/>). + The second is to use a special lambda expression (<literal>ret</literal>) which defines the return type in place (see <xref linkend = "sect:overriding_deduced_return_type"/>): + + <programlisting><![CDATA[A a; B b; ret<C>(_1 + _2)(a, b);]]></programlisting> + </para> + + <para> + For bind expressions, the return type can be defined as a template argument of the bind function as well: + <programlisting><![CDATA[bind<int>(foo, _1, _2);]]></programlisting> + +<!-- + A rare case, where the <literal><![CDATA[ret<type>(bind(...))]]></literal> syntax does not work, but + <literal><![CDATA[bind<type>(...)]]></literal> does, is explained in <xref linkend="sect:nullary_functors_and_ret"/>. +--> + </para> + </section> + + <section id="sect:actual_arguments_to_lambda_functors"> + <title>About actual arguments to lambda functors</title> + + <para><emphasis>This section is no longer (or currently) relevant; + acual arguments can be non-const rvalues. + The section can, however, become relevant again, if in the future BLL will support + lambda functors with higher arities than 3.</emphasis></para> + + <para>A general restriction for the actual arguments is that they cannot be non-const rvalues. + For example: + +<programlisting> +int i = 1; int j = 2; +(_1 + _2)(i, j); // ok +(_1 + _2)(1, 2); // error (!) +</programlisting> + + 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 +<xref linkend="sect:rvalues_as_actual_arguments"/>. + + + </para> + + </section> + + +<section id="sect:storing_bound_arguments"> + +<title>Storing bound arguments in lambda functions</title> + +<para> + +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: +<programlisting> +int i = 1; +(_1 = 2, _1 + i)(i); +</programlisting> +The comma operator is overloaded to combine lambda expressions into a sequence; +the resulting unary lambda functor first assigns 2 to its argument, +then adds the value of <literal>i</literal> to it. +The value of the expression in the last line is 3, not 4. +In other words, the lambda expression that is created is +<literal>lambda x.(x = 2, x + 1)</literal> rather than +<literal>lambda x.(x = 2, x + i)</literal>. + +</para> + +<para> + +As said, this is the default behavior for which there are exceptions. +The exact rules are as follows: + +<itemizedlist> + +<listitem> + +<para> + +The programmer can control the storing mechanism with <literal>ref</literal> +and <literal>cref</literal> wrappers <xref linkend="cit:boost::ref"/>. + +Wrapping an argument with <literal>ref</literal>, or <literal>cref</literal>, +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 +<literal>i</literal> with <literal>ref</literal>, +we are creating the lambda expression <literal>lambda x.(x = 2, x + i)</literal> +and the value of the expression in the last line will be 4: + +<programlisting> +i = 1; +(_1 = 2, _1 + ref(i))(i); +</programlisting> + +Note that <literal>ref</literal> and <literal>cref</literal> are different +from <literal>var</literal> and <literal>constant</literal>. + +While the latter ones create lambda functors, the former do not. +For example: + +<programlisting> +int i; +var(i) = 1; // ok +ref(i) = 1; // not ok, ref(i) is not a lambda functor +</programlisting> + +The functions <literal>ref</literal> and <literal>cref</literal> mostly +exist for historical reasons, +and <literal>ref</literal> can always +be replaced with <literal>var</literal>, and <literal>cref</literal> with +<literal>constant_ref</literal>. +See <xref linkend="sect:delaying_constants_and_variables"/> for details. +The <literal>ref</literal> and <literal>cref</literal> functions are +general purpose utility functions in Boost, and hence defined directly +in the <literal moreinfo="none">boost</literal> namespace. + +</para> +</listitem> + +<listitem> +<para> +Array types cannot be copied, they are thus stored as const reference by default. +</para> +</listitem> + +<listitem> + +<para> +For some expressions it makes more sense to store the arguments as references. + +For example, the obvious intention of the lambda expression +<literal>i += _1</literal> is that calls to the lambda functor affect the +value of the variable <literal>i</literal>, +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: + +<itemizedlist> +<listitem> +<para>The left argument of compound assignment operators (<literal>+=</literal>, <literal>*=</literal>, etc.) are stored as references to non-const.</para> +</listitem> + +<listitem> +<para>If the left argument of <literal><![CDATA[<<]]></literal> or <literal><![CDATA[>>]]></literal> operator is derived from an instantiation of <literal>basic_ostream</literal> or respectively from <literal>basic_istream</literal>, the argument is stored as a reference to non-const. +For all other types, the argument is stored as a copy. +</para> +</listitem> + +<listitem> +<para> +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. + +</para> +</listitem> + +</itemizedlist> + +</para> +</listitem> + +</itemizedlist> +</para> + +</section> + +</section> + +<section id="sect:lambda_expressions_in_details"> +<title>Lambda expressions in details</title> + +<para> +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. + + +</para> + +<section id="sect:placeholders"> +<title>Placeholders</title> + +<para> +The BLL defines three placeholder types: <literal>placeholder1_type</literal>, <literal>placeholder2_type</literal> and <literal>placeholder3_type</literal>. +BLL has a predefined placeholder variable for each placeholder type: <literal>_1</literal>, <literal>_2</literal> and <literal>_3</literal>. +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: + +<programlisting>boost::lambda::placeholder1_type X; +boost::lambda::placeholder2_type Y; +boost::lambda::placeholder3_type Z; +</programlisting> + +With these variables defined, <literal>X += Y * Z</literal> is equivalent to <literal>_1 += _2 * _3</literal>. +</para> + +<para> +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: + +<programlisting> +_1 + 5 // unary +_1 * _1 + _1 // unary +_1 + _2 // binary +bind(f, _1, _2, _3) // 3-ary +_3 + 10 // 3-ary +</programlisting> + +Note that the last line creates a 3-ary function, which adds <literal>10</literal> to its <emphasis>third</emphasis> 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: + +<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 +</programlisting> + +See +<xref linkend="sect:why_weak_arity"/> for the design rationale behind this +functionality. + +</para> + +<para> +In addition to these three placeholder types, there is also a fourth placeholder type <literal>placeholderE_type</literal>. +The use of this placeholder is defined in <xref linkend="sect:exceptions"/> describing exception handling in lambda expressions. +</para> + +<para>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: + + +<programlisting> +<![CDATA[int i = 1; +(_1 += 2)(i); // i is now 3 +(++_1, cout << _1)(i) // i is now 4, outputs 4]]> +</programlisting> +</para> + +</section> + +<section id="sect:operator_expressions"> +<title>Operator expressions</title> + +<para> +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: + +<programlisting><![CDATA[cout << _1, _2[_3] = _1 && false]]></programlisting> +</para> + +<para> +However, there are some restrictions that originate from the C++ operator overloading rules, and some special cases. +</para> + + +<section> +<title>Operators that cannot be overloaded</title> + +<para> +Some operators cannot be overloaded at all (<literal>::</literal>, <literal>.</literal>, <literal>.*</literal>). +For some operators, the requirements on return types prevent them to be overloaded to create lambda functors. +These operators are <literal>->.</literal>, <literal>-></literal>, <literal>new</literal>, <literal>new[]</literal>, <literal>delete</literal>, <literal>delete[]</literal> and <literal>?:</literal> (the conditional operator). +</para> + +</section> + +<section id="sect:assignment_and_subscript"> +<title>Assignment and subscript operators</title> + +<para> +These operators must be implemented as class members. +Consequently, the left operand must be a lambda expression. For example: + +<programlisting> +int i; +_1 = i; // ok +i = _1; // not ok. i is not a lambda expression +</programlisting> + +There is a simple solution around this limitation, described in <xref linkend="sect:delaying_constants_and_variables"/>. +In short, +the left hand argument can be explicitly turned into a lambda functor by wrapping it with a special <literal>var</literal> function: +<programlisting> +var(i) = _1; // ok +</programlisting> + +</para> +</section> + +<section id="sect:logical_operators"> +<title>Logical operators</title> + +<para> +Logical operators obey the short-circuiting evaluation rules. For example, in the following code, <literal>i</literal> is never incremented: +<programlisting> +bool flag = true; int i = 0; +(_1 || ++_2)(flag, i); +</programlisting> +</para> +</section> + +<section id="sect:comma_operator"> +<title>Comma operator</title> + +<para> +Comma operator is the <quote>statement separator</quote> in lambda expressions. +Since comma is also the separator between arguments in a function call, extra parenthesis are sometimes needed: + +<programlisting> +for_each(a.begin(), a.end(), (++_1, cout << _1)); +</programlisting> + +Without the extra parenthesis around <literal>++_1, cout << _1</literal>, the code would be interpreted as an attempt to call <literal>for_each</literal> with four arguments. +</para> +<para> +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 <literal>a</literal> is first incremented, then written to the stream. +</para> +</section> + +<section id="sect:function_call_operator"> +<title>Function call operator</title> + +<para> +The function call operators have the effect of evaluating the lambda +functor. +Calls with too few arguments lead to a compile time error. +</para> +</section> + +<section id="sect:member_pointer_operator"> +<title>Member pointer operator</title> + +<para> +The member pointer operator <literal>operator->*</literal> 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 <literal>A</literal>, and the right hand argument is a pointer to a member of <literal>A</literal>, or a pointer to a member of a class from which <literal>A</literal> derives. +We must separate two cases: + +<itemizedlist> + +<listitem> +<para>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: +<programlisting> +<![CDATA[struct A { int d; }; +A* a = new A(); + ... +(a ->* &A::d); // returns a reference to a->d +(_1 ->* &A::d)(a); // likewise]]> +</programlisting> +</para> +</listitem> + +<listitem> +<para> +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: +<programlisting> +<![CDATA[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)]]> +</programlisting> +</para> +</listitem> +</itemizedlist> +</para> +</section> + +</section> + +<section id="sect:bind_expressions"> +<title>Bind expressions</title> + +<para> +Bind expressions can have two forms: + +<!-- TODO: shouldn't really be emphasis, but a variable or something--> +<programlisting> +bind(<parameter>target-function</parameter>, <parameter>bind-argument-list</parameter>) +bind(<parameter>target-member-function</parameter>, <parameter>object-argument</parameter>, <parameter>bind-argument-list</parameter>) +</programlisting> + +A bind expression delays the call of a function. +If this <emphasis>target function</emphasis> is <emphasis>n</emphasis>-ary, then the <literal><emphasis>bind-argument-list</emphasis></literal> must contain <emphasis>n</emphasis> arguments as well. +In the current version of the BLL, <inlineequation>0 <= n <= 9</inlineequation> must hold. +For member functions, the number of arguments must be at most <inlineequation>8</inlineequation>, as the object argument takes one argument position. + +Basically, the +<emphasis><literal>bind-argument-list</literal></emphasis> 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 <emphasis><literal>bind-argument-list</literal></emphasis> (see <xref linkend="sect:placeholders"/>). +</para> + +<para> +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: +<programlisting> +bind<<emphasis>RET</emphasis>>(<emphasis>target-function</emphasis>, <emphasis>bind-argument-list</emphasis>) +</programlisting> +This is only necessary if the return type of the target function cannot be deduced. +</para> + +<para> +The following sections describe the different types of bind expressions. +</para> + +<section id="sect:function_pointers_as_targets"> +<title>Function pointers or references as targets</title> + +<para>The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example: +<programlisting> +<![CDATA[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);]]> +</programlisting> + +The return type deduction always succeeds with this type of bind expressions. +</para> + +<para> +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.: +<programlisting> +<![CDATA[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]]> +</programlisting> +</para> +</section> + +<section id="member_functions_as_targets"> +<title>Member functions as targets</title> + +<para> +The syntax for using pointers to member function in bind expression is: +<programlisting> +bind(<parameter>target-member-function</parameter>, <parameter>object-argument</parameter>, <parameter>bind-argument-list</parameter>) +</programlisting> + +The object argument can be a reference or pointer to the object, the BLL supports both cases with a uniform interface: + +<programlisting> +<![CDATA[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));]]> +</programlisting> + +Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference: + +<programlisting> +<![CDATA[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));]]> +</programlisting> + +</para> + +<!--%The exact rules for the object argument (whether it is bound, or supplied in the lambda function invoction) are as follows: +%If the target function is a pointer to a member function of some class \snip{A}, then the object argument must be an expression of type \snip{B}, where either +%\begin{itemize} +%\item \snip{B} = \snip{A} or there is an implicit conversion from \snip{B} to \snip{A}. +%\item \snip{B} = \snip{A*}. +%\item \snip{B} = \snip{C*}, where \snip{C} is any class derived form \snip{A}. +%\end{itemize} +%For example: +%\begin{alltt} +%struct A \{ +% virtual void f(); +% void fc() const; +%\}; +% +%struct B : public A \{ +% virtual void f(); +%\}; +% +%struct C \{ +% operator A const() \{ return A(); \} +%\}; +% +% A a; B b; C c; +% ... +% bind(&A::f, a)(); +% bind(&A::f, b)(); // calls B::f +% bind(&A::fc, c)(); +% +% bind(&A::f, &a)(); +% bind(&A::f, &b)(); // calls B::f +% bind(&A::f, &c)(); // error: no conversion from C* \(\rightarrow\) A, +%\end{alltt} +--> + +<para> +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 <literal>bind</literal>-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 <xref linkend="sect:storing_bound_arguments"/>); 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: +<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; }; +}; +</programlisting> + +When a pointer is used, the behavior is what the programmer might expect: + +<programlisting> +<![CDATA[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]]> +</programlisting> + +Even though a const copy of the object argument is stored, the original object <literal>a</literal> 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: + +<programlisting> +<![CDATA[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]]> +</programlisting> +</para> + +<para> +To prevent the copying from taking place, one can use the <literal>ref</literal> or <literal>cref</literal> wrappers (<literal>var</literal> and <literal>constant_ref</literal> would do as well): +<programlisting> +<![CDATA[bind(&A::set_i, ref(a), _1)(k); // a.j == 1 +bind(&A::set_j, cref(a), _1)(k); // a.j == 1]]> +</programlisting> +</para> + +<para>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 <literal>a</literal> is not copied in the calls to the two lambda functors below: +<programlisting> +<![CDATA[A a(0,0); +bind(&A::set_i, _1, 1)(a); // a.i == 1 +bind(&A::set_j, _1, 1)(a); // a.j == 1]]> +</programlisting> +</para> +</section> + +<section id="sect:members_variables_as_targets"> +<title>Member variables as targets</title> + +<para> +A pointer to a member variable is not really a function, but +the first argument to the <literal>bind</literal> function can nevertheless +be a pointer to a member variable. +Invoking such a bind expression returns a reference to the data member. +For example: + +<programlisting> +<![CDATA[struct A { int data; }; +A a; +bind(&A::data, _1)(a) = 1; // a.data == 1]]> +</programlisting> + +The cv-qualifiers of the object whose member is accessed are respected. +For example, the following tries to write into a const location: +<programlisting> +<![CDATA[const A ca = a; +bind(&A::data, _1)(ca) = 1; // error]]> +</programlisting> + +</para> +</section> + +<section id="sect:function_objects_as_targets"> +<title>Function objects as targets</title> + +<para> + +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 are two methods for giving BLL this capability for a certain +function object class. + +</para> + +<simplesect> + +<title>The result_type typedef</title> + +<para> + +The BLL supports the standard library convention of declaring the return type +of a function object with a member typedef named <literal>result_type</literal> in the +function object class. + +Here is a simple example: +<programlisting> +<![CDATA[struct A { + typedef B result_type; + B operator()(X, Y, Z); +};]]> +</programlisting> + +If a function object does not define a <literal>result_type</literal> typedef, +the method described below (<literal>sig</literal> template) +is attempted to resolve the return type of the +function object. If a function object defines both <literal>result_type</literal> +and <literal>sig</literal>, <literal>result_type</literal> takes precedence. + +</para> + +</simplesect> + +<simplesect> + +<title>The sig template</title> + +<para> +Another mechanism that make BLL aware of the return type(s) of a function object is defining +member template struct +<literal><![CDATA[sig<Args>]]></literal> with a typedef +<literal>type</literal> that specifies the return type. + +Here is a simple example: +<programlisting> +<![CDATA[struct A { + template <class Args> struct sig { typedef B type; } + B operator()(X, Y, Z); +};]]> +</programlisting> + +The template argument <literal>Args</literal> is a +<literal>tuple</literal> (or more precisely a <literal>cons</literal> list) +type <xref linkend="cit:boost::tuple"/>, 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 defining the <literal>result_type</literal> typedef. +Howver, there are two significant restrictions with using just a simple +typedef to express the return type: +<orderedlist> +<listitem> +<para> +If the function object defines several function call operators, there is no way to specify different result types for them. +</para> +</listitem> +<listitem> +<para> +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. +</para> +</listitem> +</orderedlist> + +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 +<literal>sig</literal> template: + +<programlisting> +<![CDATA[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; + } +};]]> +</programlisting> + + +The elements of the <literal>Args</literal> tuple are always +non-reference types. + +Moreover, the element types can have a const or volatile qualifier +(jointly referred to as <emphasis>cv-qualifiers</emphasis>), 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 <literal>Args</literal> 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. +</para> + +<para> +The <literal>sig</literal> template can be seen as a +<emphasis>meta-function</emphasis> 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 <xref linkend="cit:boost::type_traits"/> and +Tuple <xref linkend="cit:boost::type_traits"/> libraries +for tools that can aid in these tasks. +The <literal>sig</literal> templates are a refined version of a similar +mechanism first introduced in the FC++ library +<xref linkend="cit:fc++"/>. +</para> + +</simplesect> + +</section> + + + +</section> + +<section id="sect:overriding_deduced_return_type"> +<title>Overriding the deduced return type</title> + +<para> +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. +<!-- (see the example in <xref linkend="sect:parameter_and_return_types"/>).--> +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 <literal>e</literal> is <literal>T</literal>, you can write: + +<programlisting><![CDATA[ret<T>(e);]]></programlisting> + +The effect is that the return type deduction is not performed for the lambda expression <literal>e</literal> at all, but instead, <literal>T</literal> is used as the return type. +Obviously <literal>T</literal> cannot be an arbitrary type, the true result of the lambda functor must be implicitly convertible to <literal>T</literal>. +For example: + +<programlisting> +<![CDATA[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]]> +</programlisting> +For bind expressions, there is a short-hand notation that can be used instead of <literal>ret</literal>. +The last line could alternatively be written as: + +<programlisting><![CDATA[bind<Z>(x, _1)(i);]]></programlisting> +This feature is modeled after the Boost Bind library <xref linkend="cit:boost::bind"/>. + +</para> + +<para>Note that within nested lambda expressions, +the <literal>ret</literal> must be used at each subexpression where +the deduction would otherwise fail. +For example: +<programlisting> +<![CDATA[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]]> +</programlisting> +</para> + +<para>If you find yourself using <literal>ret</literal> repeatedly with the same types, it is worth while extending the return type deduction (see <xref linkend="sect:extending_return_type_system"/>). +</para> + +<section id="sect:nullary_functors_and_ret"> +<title>Nullary lambda functors and ret</title> + +<para> +As stated above, the effect of <literal>ret</literal> 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 <literal>ret</literal>, best described with an example: + +<programlisting> +<![CDATA[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!]]> +</programlisting> +The BLL cannot deduce the return types of the above bind calls, as <literal>F</literal> does not define the typedef <literal>result_type</literal>. +One would expect <literal>ret</literal> 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. +</para> + +<para>The solution to this is not to use the <literal>ret</literal> function, but rather define the return type as an explicitly specified template parameter in the <literal>bind</literal> call: +<programlisting> +<![CDATA[bind<int>(f, 1); // ok]]> +</programlisting> + +The lambda functors created with +<literal>ret<<parameter>T</parameter>>(bind(<parameter>arg-list</parameter>))</literal> and +<literal>bind<<parameter>T</parameter>>(<parameter>arg-list</parameter>)</literal> have the exact same functionality — +apart from the fact that for some nullary lambda functors the former does not work while the latter does. +</para> +</section> +</section> + + +<section id="sect:delaying_constants_and_variables"> +<title>Delaying constants and variables</title> + +<para> +The unary functions <literal>constant</literal>, +<literal>constant_ref</literal> and <literal>var</literal> 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 <emphasis>delayed</emphasis> constants and variables is sometimes necessary due to the lack of explicit syntax for lambda expressions. +For example: +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), cout << _1 << ' '); +for_each(a.begin(), a.end(), cout << ' ' << _1);]]> +</programlisting> +The first line outputs the elements of <literal>a</literal> separated by spaces, while the second line outputs a space followed by the elements of <literal>a</literal> without any separators. +The reason for this is that neither of the operands of +<literal><![CDATA[cout << ' ']]></literal> is a lambda expression, hence <literal><![CDATA[cout << ' ']]></literal> is evaluated immediately. + +To delay the evaluation of <literal><![CDATA[cout << ' ']]></literal>, one of the operands must be explicitly marked as a lambda expression. +This is accomplished with the <literal>constant</literal> function: +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), cout << constant(' ') << _1);]]> +</programlisting> + +The call <literal>constant(' ')</literal> creates a nullary lambda functor which stores the character constant <literal>' '</literal> +and returns a reference to it when invoked. +The function <literal>constant_ref</literal> is similar, except that it +stores a constant reference to its argument. + +The <literal>constant</literal> and <literal>consant_ref</literal> are only +needed when the operator call has side effects, like in the above example. +</para> + +<para> +Sometimes we need to delay the evaluation of a variable. +Suppose we wanted to output the elements of a container in a numbered list: + +<programlisting> +<![CDATA[int index = 0; +for_each(a.begin(), a.end(), cout << ++index << ':' << _1 << '\n'); +for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1 << '\n');]]> +</programlisting> + +The first <literal>for_each</literal> invocation does not do what we want; <literal>index</literal> is incremented only once, and its value is written into the output stream only once. +By using <literal>var</literal> to make <literal>index</literal> a lambda expression, we get the desired effect. +<!-- Note that <literal>var</literal> accepts const objects as well, in which case +calling <literal>var</literal> equals calling <literal>constant_ref</literal>.--> +</para> + +<para> +In sum, <literal>var(x)</literal> creates a nullary lambda functor, +which stores a reference to the variable <literal>x</literal>. +When the lambda functor is invoked, a reference to <literal>x</literal> is returned. +</para> + +<simplesect> +<title>Naming delayed constants and variables</title> + +<para> +It is possible to predefine and name a delayed variable or constant outside a lambda expression. +The templates <literal>var_type</literal>, <literal>constant_type</literal> +and <literal>constant_ref_type</literal> serve for this purpose. +They are used as: +<programlisting> +<![CDATA[var_type<T>::type delayed_i(var(i)); +constant_type<T>::type delayed_c(constant(c));]]> +</programlisting> +The first line defines the variable <literal>delayed_i</literal> which is a delayed version of the variable <literal>i</literal> of type <literal>T</literal>. +Analogously, the second line defines the constant <literal>delayed_c</literal> as a delayed version of the constant <literal>c</literal>. +For example: + +<programlisting> +int i = 0; int j; +for_each(a.begin(), a.end(), (var(j) = _1, _1 = var(i), var(i) = var(j))); +</programlisting> +is equivalent to: +<programlisting> +<![CDATA[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));]]> +</programlisting> +</para> +<para> +Here is an example of naming a delayed constant: +<programlisting> +<![CDATA[constant_type<char>::type space(constant(' ')); +for_each(a.begin(),a.end(), cout << space << _1);]]> +</programlisting> +</para> + +</simplesect> + +<simplesect> +<title>About assignment and subscript operators</title> + +<para> +As described in <xref linkend="sect:assignment_and_subscript"/>, assignment and subscripting operators are always defined as member functions. +This means, that for expressions of the form +<literal>x = y</literal> or <literal>x[y]</literal> to be interpreted as lambda expressions, the left-hand operand <literal>x</literal> must be a lambda expression. +Consequently, it is sometimes necessary to use <literal>var</literal> for this purpose. +We repeat the example from <xref linkend="sect:assignment_and_subscript"/>: + +<programlisting> +int i; +i = _1; // error +var(i) = _1; // ok +</programlisting> +</para> + +<para> + +Note that the compound assignment operators <literal>+=</literal>, <literal>-=</literal> 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, <literal>i += _1</literal> is equivalent to <literal>var(i) += _1</literal>. +</para> +</simplesect> + +</section> + +<section id="sect:lambda_expressions_for_control_structures"> +<title>Lambda expressions for control structures</title> + +<para> +BLL defines several functions to create lambda functors that represent control structures. +They all take lambda functors as parameters and return <literal>void</literal>. +To start with an example, the following code outputs all even elements of some container <literal>a</literal>: + +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), + if_then(_1 % 2 == 0, cout << _1));]]> +</programlisting> +</para> + +<para> +The BLL supports the following function templates for control structures: + +<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(...) +</programlisting> + +The return types of all control construct lambda functor is +<literal>void</literal>, except for <literal>if_then_else_return</literal>, +which wraps a call to the conditional operator +<programlisting> +condition ? then_part : else_part +</programlisting> +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 +<literal>A</literal>, must be convertible to the other branch, +say of type <literal>B</literal>. +In this situation, the result type is <literal>B</literal>. +Further, if the common type is an lvalue, the return type will be an lvalue +too. +</para> + + +<para> +Delayed variables tend to be commonplace in control structure lambda expressions. +For instance, here we use the <literal>var</literal> function to turn the arguments of <literal>for_loop</literal> into lambda expressions. +The effect of the code is to add 1 to each element of a two-dimensional array: + +<programlisting> +<![CDATA[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));]]> +</programlisting> + +<!-- +As explained in <xref linkend="sect:delaying_constants_and_variables"/>, we can avoid the repeated use of wrapping of <literal>var</literal> if we define it beforehand: + +<programlisting> +<![CDATA[int i; +var_type<int>::type vi(var(i)); +for_each(a, a+5, + for_loop(vi=0, vi<10, ++vi, _1[vi] += 6));]]> +</programlisting> + +--> +</para> + +<para> +The BLL supports an alternative syntax for control expressions, suggested +by Joel de Guzmann. +By overloading the <literal>operator[]</literal> we can +get a closer resemblance with the built-in control structures: + +<programlisting> +<![CDATA[if_(condition)[then_part] +if_(condition)[then_part].else_[else_part] +while_(condition)[body] +do_[body].while_(condition) +for_(init, condition, increment)[body]]]> +</programlisting> + +For example, using this syntax the <literal>if_then</literal> example above +can be written as: +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), + if_(_1 % 2 == 0)[ cout << _1 ])]]> +</programlisting> + +As more experience is gained, we may end up deprecating one or the other +of these syntaces. + +</para> + + + +<section id="sect:switch_statement"> +<title>Switch statement</title> +</section> + +<para> +The lambda expressions for <literal>switch</literal> control structures are more complex since the number of cases may vary. +The general form of a switch lambda expression is: + +<programlisting> +switch_statement(<parameter>condition</parameter>, + case_statement<<parameter>label</parameter>>(<parameter>lambda expression</parameter>), + case_statement<<parameter>label</parameter>>(<parameter>lambda expression</parameter>), + ... + default_statement(<parameter>lambda expression</parameter>) +) +</programlisting> + +The <literal><parameter>condition</parameter></literal> argument must be a lambda expression that creates a lambda functor with an integral return type. +The different cases are created with the <literal>case_statement</literal> functions, and the optional default case with the <literal>default_statement</literal> function. +The case labels are given as explicitly specified template arguments to <literal>case_statement</literal> functions and +<literal>break</literal> statements are implicitly part of each case. +For example, <literal><![CDATA[case_statement<1>(a)]]></literal>, where <literal>a</literal> is some lambda functor, generates the code: + +<programlisting> +case 1: + <parameter>evaluate lambda functor</parameter> a; + break; +</programlisting> +The <literal>switch_statement</literal> function is specialized for up to 9 case statements. + +</para> + +<para> +As a concrete example, the following code iterates over some container <literal>v</literal> and ouptuts <quote>zero</quote> for each <literal>0</literal>, <quote>one</quote> for each <literal>1</literal>, and <quote>other: <parameter>n</parameter></quote> for any other value <parameter>n</parameter>. +Note that another lambda expression is sequenced after the <literal>switch_statement</literal> to output a line break after each element: + +<programlisting> +<![CDATA[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") + ) +);]]> +</programlisting> +</para> + +</section> + +<section id="sect:exceptions"> +<title>Exceptions</title> + +<para> +The BLL provides lambda functors that throw and catch exceptions. +Lambda functors for throwing exceptions are created with the unary function <literal>throw_exception</literal>. +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 <literal>rethrow</literal> function. +</para> + +<para> +Lambda expressions for handling exceptions are somewhat more complex. +The general form of a lambda expression for try catch blocks is as follows: + +<programlisting> +try_catch( + <parameter>lambda expression</parameter>, + catch_exception<<parameter>type</parameter>>(<parameter>lambda expression</parameter>), + catch_exception<<parameter>type</parameter>>(<parameter>lambda expression</parameter>), + ... + catch_all(<parameter>lambda expression</parameter>) +) +</programlisting> + +The first lambda expression is the try block. +Each <literal>catch_exception</literal> defines a catch block where the +explicitly specified template argument defines the type of the exception +to catch. + +The lambda expression within the <literal>catch_exception</literal> defines +the actions to take if the exception is caught. + +Note that the resulting exception handlers catch the exceptions as +references, i.e., <literal>catch_exception<T>(...)</literal> +results in the catch block: + +<programlisting> +catch(T& e) { ... } +</programlisting> + +The last catch block can alternatively be a call to +<literal>catch_exception<<parameter>type</parameter>></literal> +or to +<literal>catch_all</literal>, which is the lambda expression equivalent to +<literal>catch(...)</literal>. + +</para> + +<para> + +The <xref linkend="ex:exceptions"/> demonstrates the use of the BLL +exception handling tools. +The first handler catches exceptions of type <literal>foo_exception</literal>. +Note the use of <literal>_1</literal> placeholder in the body of the handler. +</para> + +<para> +The second handler shows how to throw exceptions, and demonstrates the +use of the <emphasis>exception placeholder</emphasis> <literal>_e</literal>. + +It is a special placeholder, which refers to the caught exception object +within the handler body. + +Here we are handling an exception of type <literal>std::exception</literal>, +which carries a string explaining the cause of the exception. + +This explanation can be queried with the zero-argument member +function <literal>what</literal>. + +The expression +<literal>bind(&std::exception::what, _e)</literal> creates the lambda +function for making that call. + +Note that <literal>_e</literal> cannot be used outside of an exception handler lambda expression. +<!--Violating this rule is caught by the compiler.--> + +The last line of the second handler constructs a new exception object and +throws that with <literal>throw exception</literal>. + +Constructing and destructing objects within lambda expressions is +explained in <xref linkend="sect:construction_and_destruction"/> +</para> + +<para> +Finally, the third handler (<literal>catch_all</literal>) demonstrates +rethrowing exceptions. +</para> + +<example id="ex:exceptions"> +<title>Throwing and handling exceptions in lambda expressions.</title> +<programlisting> +<![CDATA[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()) + ) + ) +);]]> +</programlisting> +</example> + +</section> + +<section id="sect:construction_and_destruction"> +<title>Construction and destruction</title> + + +<para> +Operators <literal>new</literal> and <literal>delete</literal> 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 +<literal>new</literal> and <literal>delete</literal> 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: + +<programlisting> +<![CDATA[int* a[10]; +for_each(a, a+10, _1 = bind(new_ptr<int>())); +for_each(a, a+10, bind(delete_ptr(), _1));]]> +</programlisting> + +The <literal>new_ptr<int>()</literal> expression creates +a function object that calls <literal>new int()</literal> when invoked, +and wrapping that inside <literal>bind</literal> makes it a lambda functor. + +In the same way, the expression <literal>delete_ptr()</literal> creates +a function object that invokes <literal>delete</literal> on its argument. + +Note that <literal>new_ptr<<parameter>T</parameter>>()</literal> +can take arguments as well. + +They are passed directly to the constructor invocation and thus allow +calls to constructors which take arguments. + +</para> + +<para> + +As an example of constructor calls in lambda expressions, +the following code reads integers from two containers <literal>x</literal> +and <literal>y</literal>, +constructs pairs out of them and inserts them into a third container: + +<programlisting> +<![CDATA[vector<pair<int, int> > v; +transform(x.begin(), x.end(), y.begin(), back_inserter(v), + bind(constructor<pair<int, int> >(), _1, _2));]]> +</programlisting> + +<xref linkend="table:constructor_destructor_fos"/> 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. + +</para> + + + +<table id="table:constructor_destructor_fos"> +<title>Construction and destruction related function objects.</title> +<tgroup cols="2"> +<thead> +<row> +<entry>Function object call</entry> +<entry>Wrapped expression</entry> +</row> +</thead> +<tbody> +<row> +<entry><literal>constructor<T>()(<parameter>arg_list</parameter>)</literal></entry> +<entry>T(<parameter>arg_list</parameter>)</entry> +</row> +<row> +<entry><literal>destructor()(a)</literal></entry> +<entry><literal>a.~A()</literal>, where <literal>a</literal> is of type <literal>A</literal></entry> +</row> +<row> +<entry><literal>destructor()(pa)</literal></entry> +<entry><literal>pa->~A()</literal>, where <literal>pa</literal> is of type <literal>A*</literal></entry> +</row> +<row> +<entry><literal>new_ptr<T>()(<parameter>arg_list</parameter>)</literal></entry> +<entry><literal>new T(<parameter>arg_list</parameter>)</literal></entry> +</row> +<row> +<entry><literal>new_array<T>()(sz)</literal></entry> +<entry><literal>new T[sz]</literal></entry> +</row> +<row> +<entry><literal>delete_ptr()(p)</literal></entry> +<entry><literal>delete p</literal></entry> +</row> +<row> +<entry><literal>delete_array()(p)</literal></entry> +<entry><literal>delete p[]</literal></entry> +</row> + + +</tbody> +</tgroup> +</table> + +</section> + + +<section> +<title>Special lambda expressions</title> + +<section> +<title>Preventing argument substitution</title> + +<para> +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. +</para> + + +<para> +The arguments to a bind expression can be arbitrary lambda expressions, +e.g., other bind expressions. + +For example: + +<programlisting> +int foo(int); int bar(int); +... +int i; +bind(foo, bind(bar, _1)(i); +</programlisting> + +The last line makes the call <literal>foo(bar(i));</literal> + +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: + +<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); +</programlisting> + +</para> + + + +<section id="sect:unlambda"> +<title>Unlambda</title> + +<para>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. +</para> + +<para>Consider the following function template: + +<programlisting> +<![CDATA[template<class F> +int nested(const F& f) { + int x; + ... + bind(f, _1)(x); + ... +}]]> +</programlisting> + +Somewhere inside the function the formal parameter +<literal>f</literal> is used as a target function in a bind expression. + +In order for this <literal>bind</literal> call to be valid, +<literal>f</literal> must be a unary function. + +Suppose the following two calls to <literal>nested</literal> are made: + +<programlisting> +<![CDATA[int foo(int); +int bar(int, int); +nested(&foo); +nested(bind(bar, 1, _1));]]> +</programlisting> + +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 <literal>nested</literal> +will become: + +<programlisting> +bind(bind(bar, 1, _1), _1) +</programlisting> + +When this is invoked with <literal>x</literal>, +after substituitions we end up trying to call + +<programlisting> +bar(1, x)(x) +</programlisting> + +which is an error. + +The call to <literal>bar</literal> returns int, +not a unary function or function object. +</para> + +<para> +In the example above, the intent of the bind expression in the +<literal>nested</literal> function is to treat <literal>f</literal> +as an ordinary function object, instead of a lambda functor. + +The BLL provides the function template <literal>unlambda</literal> to +express this: a lambda functor wrapped inside <literal>unlambda</literal> +is not a lambda functor anymore, and does not take part into the +argument substitution process. + +Note that for all other argument types <literal>unlambda</literal> is +an identity operation, except for making non-const objects const. +</para> + +<para> +Using <literal>unlambda</literal>, the <literal>nested</literal> +function is written as: + +<programlisting> +<![CDATA[template<class F> +int nested(const F& f) { + int x; + ... + bind(unlambda(f), _1)(x); + ... +}]]> +</programlisting> + +</para> + +</section> + +<section> +<title>Protect</title> + +<para> +The <literal>protect</literal> function is related to unlambda. + +It is also used to prevent the argument substitution taking place, +but whereas <literal>unlambda</literal> turns a lambda functor into +an ordinary function object for good, <literal>protect</literal> does +this temporarily, for just one evaluation round. + +For example: + +<programlisting> +int x = 1, y = 10; +(_1 + protect(_1 + 2))(x)(y); +</programlisting> + +The first call substitutes <literal>x</literal> for the leftmost +<literal>_1</literal>, and results in another lambda functor +<literal>x + (_1 + 2)</literal>, which after the call with +<literal>y</literal> becomes <literal>x + (y + 2)</literal>, +and thus finally 13. +</para> + +<para> +Primary motivation for including <literal>protect</literal> into the library, +was to allow nested STL algorithm invocations +(<xref linkend="sect:nested_stl_algorithms"/>). +</para> + +</section> + +</section> + +<section id="sect:rvalues_as_actual_arguments"> +<title>Rvalues as actual arguments to lambda functors</title> + + <para><emphasis>This section and all of its subsections + are no longer (or currently) relevant; + acual arguments can be non-const rvalues and these workarounds are thus + not needed. + The section can, however, become relevant again, if in the future BLL will support + lambda functors with higher arities than 3.</emphasis></para> + +<para> +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 +<xref linkend="sect:actual_arguments_to_lambda_functors"/> and list the +different solutions: + +<programlisting> +int i = 1; int j = 2; +(_1 + _2)(i, j); // ok +(_1 + _2)(1, 2); // error (!) +</programlisting> + +<orderedlist> +<listitem> +<para> +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. +</para> +</listitem> + +<listitem> +<para> +If the lambda function call is accessible, the <literal>make_const</literal> +function can be used to <emphasis>constify</emphasis> the rvalue. E.g.: + +<programlisting> +(_1 + _2)(make_const(1), make_const(2)); // ok +</programlisting> + +Commonly the lambda function call site is inside a standard algorithm +function template, preventing this solution to be used. + +</para> +</listitem> + +<listitem> +<para> +If neither of the above is possible, the lambda expression can be wrapped +in a <literal>const_parameters</literal> function. +It creates another type of lambda functor, which takes its arguments as +const references. For example: + +<programlisting> +const_parameters(_1 + _2)(1, 2); // ok +</programlisting> + +Note that <literal>const_parameters</literal> 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. +</para> + +</listitem> + +<listitem> +<para>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 +<literal>break_const</literal> to alert the user of the potential dangers +of this function. + +The <literal>break_const</literal> 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: +<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 +</programlisting> + +Note, that the results of <literal> break_const</literal> or +<literal>const_parameters</literal> are not lambda functors, +so they cannot be used as subexpressions of lambda expressions. For instance: + +<programlisting> +break_const(_1 + _2) + _3; // fails. +const_parameters(_1 + _2) + _3; // fails. +</programlisting> + +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. +</para> +</listitem> + +</orderedlist> + +</para> +</section> + +</section> + + +<section> +<title>Casts, sizeof and typeid</title> + +<section id="sect:cast_expressions"> +<title> +Cast expressions +</title> +<para> +The BLL defines its counterparts for the four cast expressions +<literal>static_cast</literal>, <literal>dynamic_cast</literal>, +<literal>const_cast</literal> and <literal>reinterpret_cast</literal>. + +The BLL versions of the cast expressions have the prefix +<literal>ll_</literal>. + +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 <literal>ll_dynamic_cast</literal> +to count the number of <literal>derived</literal> instances in the container +<literal>a</literal>: + +<programlisting> +<![CDATA[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)));]]> +</programlisting> +</para> +</section> + +<section> +<title>Sizeof and typeid</title> +<para> +The BLL counterparts for these expressions are named +<literal>ll_sizeof</literal> and <literal>ll_typeid</literal>. + +Both take one argument, which can be a lambda expression. +The lambda functor created wraps the <literal>sizeof</literal> or +<literal>typeid</literal> call, and when the lambda functor is called +the wrapped operation is performed. + +For example: + +<programlisting> +<![CDATA[vector<base*> a; +... +for_each(a.begin(), a.end(), + cout << bind(&type_info::name, ll_typeid(*_1)));]]> +</programlisting> + +Here <literal>ll_typeid</literal> creates a lambda functor for +calling <literal>typeid</literal> for each element. + +The result of a <literal>typeid</literal> call is an instance of +the <literal>type_info</literal> class, and the bind expression creates +a lambda functor for calling the <literal>name</literal> member +function of that class. + +</para> +</section> + + + +</section> + +<section id="sect:nested_stl_algorithms"> +<title>Nesting STL algorithm invocations</title> + +<para> +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. + +<programlisting> +int a[100][200]; +int sum = 0; + +std::for_each(a, a + 100, + bind(ll::for_each(), _1, _1 + 200, protect(sum += _1))); +</programlisting> + +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 <literal>std</literal> namespace. +All these structs are placed in the subnamespace <literal>boost::lambda:ll</literal>. +<!--The supported algorithms are listed in <xref linkend="table:nested_algorithms"/>.--> +</para> + +<para> +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 <literal>begin</literal> function has more than one overloaded +definitions in container templates. + +In general, something analogous to the pseudo-code below cannot be written: + +<programlisting> +std::for_each(a.begin(), a.end(), + bind(ll::for_each(), _1.begin(), _1.end(), protect(sum += _1))); +</programlisting> + +Some aid for common special cases can be provided though. + +The BLL defines two helper function object classes, +<literal>call_begin</literal> and <literal>call_end</literal>, +which wrap a call to the <literal>begin</literal> and, respectively, +<literal>end</literal> functions of a container, and return the +<literal>const_iterator</literal> type of the container. + +With these helper templates, the above code becomes: +<programlisting> +std::for_each(a.begin(), a.end(), + bind(ll::for_each(), + bind(call_begin(), _1), bind(call_end(), _1), + protect(sum += _1))); +</programlisting> + +</para> + +<!-- +<table id="table:nested_algorithms"> +<title>The nested STL algorithms.</title> +<tgroup cols="1"> +<thead> +<trow><entry>Otsikko</entry></trow> +</thead> +<tbody> +<row><entry><literal>for_each</literal></entry></row> +<row><entry><literal>find</literal></entry></row> +<row><entry><literal>find_if</literal></entry></row> +<row><entry><literal>find_end</literal></entry></row> +<row><entry><literal>find_first_of</literal></entry></row> +<row><entry><literal>transform</literal></entry></row> +</tbody> +</tgroup> + +</table> + +--> + +</section> + + +</section> + + +<!-- +<section> +<title>Common gothcas</title> + +calling member functions a.begin() + +calling templated functions ... + +</section> + +--> + +<section id="sect:extending_return_type_system"> +<title>Extending return type deduction system</title> + +<para> +<!--The <xref linkend = "sect:overriding_deduced_return_type"/> showed how to make BLL aware of the return type of a function object in bind expressions.--> + +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 +<literal>bool</literal>, 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. + +</para> + +<para> +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 + +<literal> +<![CDATA[plain_return_type_1<Action, A>]]> +</literal> + +and + +<literal> +<![CDATA[return_type_1<Action, A>]]> +</literal>, and + +<literal> +<![CDATA[plain_return_type_2<Action, A, B>]]> +</literal> + +and + +<literal> +<![CDATA[return_type_2<Action, A, B>]]> +</literal> + +respectively for binary functors. + +</para> + +<para> +The first parameter (<literal>Action</literal>) to all these templates +is the <emphasis>action</emphasis> class, which specifies the operator. + +Operators with similar return type rules are grouped together into +<emphasis>action groups</emphasis>, +and only the action class and action group together define the operator +unambiguously. + +As an example, the action type +<literal><![CDATA[arithmetic_action<plus_action>]]></literal> stands for +<literal>operator+</literal>. + +The complete listing of different action types is shown in +<xref linkend="table:actions"/>. +</para> + +<para> +The latter parameters, <literal>A</literal> in the unary case, +or <literal>A</literal> and <literal>B</literal> in the binary case, +stand for the argument types of the operator call. + +The two sets of templates, +<literal>plain_return_type_<parameter>n</parameter></literal> and +<literal>return_type_<parameter>n</parameter></literal> +(<parameter>n</parameter> 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 <literal>return_type_2</literal> specializations. +</para> + +<para> +Suppose the user has overloaded the following operators for some user defined +types <literal>X</literal>, <literal>Y</literal> and <literal>Z</literal>: + +<programlisting> +<![CDATA[Z operator+(const X&, const Y&); +Z operator-(const X&, const Y&);]]> +</programlisting> + +Now, one can add a specialization stating, that if the left hand argument +is of type <literal>X</literal>, and the right hand one of type +<literal>Y</literal>, the return type of all such binary arithmetic +operators is <literal>Z</literal>: + +<programlisting> +<![CDATA[namespace boost { +namespace lambda { + +template<class Act> +struct plain_return_type_2<arithmetic_action<Act>, X, Y> { + typedef Z type; +}; + +} +}]]> +</programlisting> + +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, +<literal>::boost::lambda</literal>, with the primary template. + +For brevity, we do not show the namespace definitions in the examples below. +</para> + +<para> +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 <literal>X</literal> +and <literal>Y</literal>: + +<programlisting> +<![CDATA[X operator*(const X&, const Y&);]]> +</programlisting> + +Our first rule for all arithmetic operators specifies that the return +type of this operator is <literal>Z</literal>, +which obviously is not the case. +Hence, we provide a new rule for the multiplication operator: + +<programlisting> +<![CDATA[template<> +struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> { + typedef X type; +};]]> +</programlisting> +</para> + +<para> +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: + +<programlisting> +<![CDATA[template <class T> class my_vector;]]> +</programlisting> + +Suppose the addition operator is defined between any two +<literal>my_vector</literal> instantiations, +as long as the addition operator is defined between their element types. + +Furthermore, the element type of the resulting <literal>my_vector</literal> +is the same as the result type of the addition between the element types. + +E.g., adding <literal><![CDATA[my_vector<int>]]></literal> and +<literal><![CDATA[my_vector<double>]]></literal> results in +<literal><![CDATA[my_vector<double>]]></literal>. + +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: + +<programlisting> +<![CDATA[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>(); +}]]> +</programlisting> +</para> + +<para> +To allow BLL to deduce the type of <literal>my_vector</literal> +additions correctly, we can define: + +<programlisting> +<![CDATA[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; +};]]> +</programlisting> +Note, that we are reusing the existing specializations for the +BLL <literal>return_type_2</literal> template, +which require that the argument types are references. +</para> + +<!-- TODO: is an example of specifying the other level needed at all --> +<!-- TODO: comma operator is a special case for that --> + +<table id = "table:actions"> +<title>Action types</title> +<tgroup cols="2"> +<tbody> + +<row><entry><literal><![CDATA[+]]></literal></entry><entry><literal><![CDATA[arithmetic_action<plus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[-]]></literal></entry><entry><literal><![CDATA[arithmetic_action<minus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[*]]></literal></entry><entry><literal><![CDATA[arithmetic_action<multiply_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[/]]></literal></entry><entry><literal><![CDATA[arithmetic_action<divide_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[%]]></literal></entry><entry><literal><![CDATA[arithmetic_action<remainder_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[+]]></literal></entry><entry><literal><![CDATA[unary_arithmetic_action<plus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[-]]></literal></entry><entry><literal><![CDATA[unary_arithmetic_action<minus_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&]]></literal></entry><entry><literal><![CDATA[bitwise_action<and_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[|]]></literal></entry><entry><literal><![CDATA[bitwise_action<or_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[~]]></literal></entry><entry><literal><![CDATA[bitwise_action<not_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[^]]></literal></entry><entry><literal><![CDATA[bitwise_action<xor_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[<<]]></literal></entry><entry><literal><![CDATA[bitwise_action<leftshift_action_no_stream>]]></literal></entry></row> +<row><entry><literal><![CDATA[>>]]></literal></entry><entry><literal><![CDATA[bitwise_action<rightshift_action_no_stream>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&&]]></literal></entry><entry><literal><![CDATA[logical_action<and_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[||]]></literal></entry><entry><literal><![CDATA[logical_action<or_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[!]]></literal></entry><entry><literal><![CDATA[logical_action<not_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[<]]></literal></entry><entry><literal><![CDATA[relational_action<less_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[>]]></literal></entry><entry><literal><![CDATA[relational_action<greater_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[<=]]></literal></entry><entry><literal><![CDATA[relational_action<lessorequal_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[>=]]></literal></entry><entry><literal><![CDATA[relational_action<greaterorequal_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[==]]></literal></entry><entry><literal><![CDATA[relational_action<equal_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[!=]]></literal></entry><entry><literal><![CDATA[relational_action<notequal_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[+=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<plus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[-=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<minus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[*=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<multiply_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[/=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<divide_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[%=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<remainder_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<and_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[=|]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<or_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[^=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<xor_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[<<=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<leftshift_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[>>=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<rightshift_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[++]]></literal></entry><entry><literal><![CDATA[pre_increment_decrement_action<increment_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[--]]></literal></entry><entry><literal><![CDATA[pre_increment_decrement_action<decrement_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[++]]></literal></entry><entry><literal><![CDATA[post_increment_decrement_action<increment_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[--]]></literal></entry><entry><literal><![CDATA[post_increment_decrement_action<decrement_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&]]></literal></entry><entry><literal><![CDATA[other_action<address_of_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[*]]></literal></entry><entry><literal><![CDATA[other_action<contents_of_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[,]]></literal></entry><entry><literal><![CDATA[other_action<comma_action>]]></literal></entry></row> + +</tbody> +</tgroup> +</table> + +</section> + + +<section> +<title>Practical considerations</title> + + +<section> +<title>Performance</title> + +<para>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. +</para> + +<para> +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<superscript>5</superscript>. +The expressions were called inside a <literal>std::transform</literal> loop, +reading the argument from one <literal><![CDATA[std::vector<int>]]></literal> +and placing the result into another. +The length of the vectors was 100 elements. +The running times are listed in +<xref linkend="table:increasing_arithmetic_test"/>. + +We can observe that there is no significant difference between the +two approaches. +</para> + +<para> +In the second test we again used <literal>std::transform</literal> to +perform an operation to each element in a 100-element long vector. +This time the element type of the vectors was <literal>double</literal> +and we started with very simple arithmetic expressions and moved to +more complex ones. +The running times are listed in <xref linkend="table:ll_vs_stl_test"/>. + +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 <xref linkend="table:ll_vs_stl_test"/> written with +classic STL tools contains 7 calls to <literal>compose2</literal>, +8 calls to <literal>bind1st</literal> +and altogether 14 constructor invocations for creating +<literal>multiplies</literal>, <literal>minus</literal> +and <literal>plus</literal> 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. +</para> + +<para> +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. + +<!-- We repeated both tests with the KAI C++ 4.0f compiler (using +K2 -O3 flags), +generally considered a good optimizing compiler. +We do not list the results here, since the running times for the two alternatives in the first test were essentially the same, just as the running times +for the three different alternatives in the second test. +These tests suggest there to be no performance penalty at all +with a good optimizing compiler. +--> + +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 experienced +this for some seemingly simple expressions. + + +<table id = "table:increasing_arithmetic_test"> +<title>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.</title> +<tgroup cols="3"> +<thead> +<row> +<entry>expression</entry><entry>lambda expression</entry><entry>hand-coded function object</entry></row> +</thead> + +<tbody> + +<row> +<entry>x</entry><entry>240</entry><entry>230</entry> +</row> + +<row> +<entry>x*x</entry><entry>340</entry><entry>350</entry> +</row> + +<row> +<entry>x*x*x</entry><entry>770</entry><entry>760</entry> +</row> + +<row> +<entry>x*x*x*x</entry><entry>1180</entry><entry>1210</entry> +</row> + +<row> +<entry>x*x*x*x*x</entry><entry>1950</entry><entry>1910</entry> +</row> + +</tbody> +</tgroup> +</table> +</para> + +<!-- +16:19:49 bench [601] ./arith.out 100 1000000 + +Number of elements = 100 +L1 : 240 +L2 : 340 +L3 : 770 +L4 : 1180 +L5 : 1950 + +P2 : 1700 +P3 : 2130 +P4 : 2530 +P5 : 3000 + +F1 : 230 +F2 : 350 +F3 : 760 +F4 : 1210 +F5 : 1910 + + +Number of elements = 100 +Number of outer_iters = 1000000 +L1 : 330 +L2 : 350 +L3 : 470 +L4 : 620 +L5 : 1660 +LP : 1230 +C1 : 370 +C2 : 370 +C3 : 500 +C4 : 670 +C5 : 1660 +CP : 1770 +F1 : 290 +F2 : 310 +F3 : 420 +F4 : 600 +F5 : 1460 +FP : 1040 + +--> + + +<para> +<table id = "table:ll_vs_stl_test"> +<title>Test 2. CPU time of arithmetic expressions written as lambda +expressions, as classic STL unnamed functions (using <literal>compose2</literal>, <literal>bind1st</literal> etc.) and as traditional hand-coded function object classes. +Using BLL terminology, +<literal>a</literal> and <literal>b</literal> are bound arguments in the expressions, and <literal>x</literal> is open. +All variables were of types <literal>double</literal>. +The running times are expressed in arbitrary units.</title> +<tgroup cols="4"> +<thead> +<row> +<entry>expression</entry><entry>lambda expression</entry><entry>classic STL expression</entry><entry>hand-coded function object</entry></row> +</thead> + +<tbody> + +<row> +<entry>ax</entry><entry>330</entry><entry>370</entry><entry>290</entry> +</row> + +<row> +<entry>-ax</entry><entry>350</entry><entry>370</entry><entry>310</entry> +</row> + +<row> +<entry>ax-(a+x)</entry><entry>470</entry><entry>500</entry><entry>420</entry> +</row> + +<row> +<entry>(ax-(a+x))(a+x)</entry><entry>620</entry><entry>670</entry><entry>600</entry> +</row> + +<row> +<entry>((ax) - (a+x))(bx - (b+x))(ax - (b+x))(bx - (a+x))</entry><entry>1660</entry><entry>1660</entry><entry>1460</entry> +</row> + +</tbody> +</tgroup> + +</table> +</para> + + +<para>Some additional performance testing with an earlier version of the +library is described +<xref linkend="cit:jarvi:00"/>. +</para> + +</section> + <section> + <title>About compiling</title> + + <para>The BLL uses templates rather heavily, performing numerous recursive instantiations of the same templates. +This has (at least) three implications: +<itemizedlist> + +<listitem> +<para> +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. +</para> +</listitem> + + +<listitem> +<para> +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 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. +</para> +</listitem> + +<listitem> +<para> +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. +</para> +</listitem> +</itemizedlist></para> + + </section> + + <section> + <title>Portability</title> + <para> +The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL: + + <itemizedlist> + <listitem>GCC 3.0.4 + </listitem> + <listitem>KCC 4.0f with EDG 2.43.1 + </listitem> + <listitem>GCC 2.96 (fails with one test case, the <filename>exception_test.cpp</filename> results in an internal compiler error. +) + + </listitem> + </itemizedlist> +</para> + + <section> + <title>Test coverage</title> + +<para>The following list describes the test files included and the features that each file covers: + +<itemizedlist> +<listitem> +<para> +<filename>bind_tests_simple.cpp</filename> : Bind expressions of different arities and types of target functions: function pointers, function objects and member functions. +Function composition with bind expressions.</para> +</listitem> + +<listitem> +<para><filename>bind_tests_simple_function_references.cpp</filename> : +Repeats all tests from <filename moreinfo="none">bind_tests_simple.cpp</filename> where the target function is a function pointer, but uses function references instead. +</para></listitem> + + +<listitem> +<para><filename>bind_tests_advanced.cpp</filename> : Contains tests for nested bind expressions, <literal>unlambda</literal>, <literal>protect</literal>, <literal>const_parameters</literal> and <literal>break_const</literal>. +Tests passing lambda functors as actual arguments to other lambda functors, currying, and using the <literal>sig</literal> template to specify the return type of a function object. +</para> +</listitem> + +<listitem> +<para> +<filename>operator_tests_simple.cpp</filename> : +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. +</para> +</listitem> + +<listitem> +<para><filename>member_pointer_test.cpp</filename> : The pointer to member operator is complex enough to warrant a separate test file. +</para> +</listitem> + +<listitem> +<para> +<filename>control_structures.cpp</filename> : +Tests for the looping and if constructs. +</para></listitem> + +<listitem> +<para> +<filename>switch_construct.cpp</filename> : +Includes tests for all supported arities of the switch statement, both with and without the default case. +</para> +</listitem> + +<listitem> +<para> +<filename>exception_test.cpp</filename> : +Includes tests for throwing exceptions and for try/catch constructs with varying number of catch blocks. +</para> +</listitem> + +<listitem> +<para> +<filename>constructor_tests.cpp</filename> : +Contains tests for <literal>constructor</literal>, <literal>destructor</literal>, <literal>new_ptr</literal>, <literal>delete_ptr</literal>, <literal>new_array</literal> and <literal>delete_array</literal>. +</para> +</listitem> + +<listitem> +<para> +<filename>cast_test.cpp</filename> : Tests for the four cast expressions, as well as <filename>typeid</filename> and <literal>sizeof</literal>. +</para> +</listitem> + +<listitem> +<para> +<filename>extending_return_type_traits.cpp</filename> : 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. +</para> +</listitem> + +<listitem> +<para> +<filename>is_instance_of_test.cpp</filename> : Includes tests for an internally used traits template, which can detect whether a given type is an instance of a certain template or not. +</para></listitem> + +<listitem> +<para> +<filename>bll_and_function.cpp</filename> : +Contains tests for using <literal>boost::function</literal> together with lambda functors. +</para></listitem> + + </itemizedlist> + +</para> + + </section> + + </section> + + +</section> + + +<section> +<title>Relation to other Boost libraries</title> + +<section> +<title>Boost Function</title> + +<para>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. +<emphasis>The Boost Function library</emphasis> <xref linkend="cit:boost::function"/> defines wrappers for arbitrary function objects, for example +lambda functors; and these wrappers have types that are easy to type out. + +For example: + +<programlisting> +<![CDATA[boost::function<int(int, int)> f = _1 + _2; +boost::function<int&(int&)> g = (_1 += 10); +int i = 1, j = 2; +f(i, j); // returns 3 +g(i); // sets i to = 11;]]> +</programlisting> + +The return and parameter types of the wrapped function object must be written explicilty as the template argument to the wrapper template <literal>boost::function</literal>; even when lambda functors, which otherwise have generic parameters, are wrapped. +Wrapping a function object with <literal>boost::function</literal> introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used. + +Note that storing lambda functors inside <literal>boost::function</literal> +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 <literal>boost::function</literal> +may continue to exist longer, creating the possibility of dangling references. +For example: + +<programlisting> +<![CDATA[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]]> +</programlisting> + +</para> + +</section> + +<section> +<title>Boost Bind</title> +<para> +<emphasis>The Boost Bind</emphasis> <xref linkend="cit:boost::bind"/> 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. +</para> +<para> +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 <literal>boost</literal> namespace, +whereas the BLL names are in <literal>boost::lambda</literal> namespace. +</para> + +<para> +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. +</para> + +<para> +The following two sections describe what are the semantic differences +between the bind expressions in BB and BLL. +</para> + + + + +<section> +<title>First argument of bind expression</title> + +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: + +<programlisting> +<![CDATA[template<class F> +int foo(const F& f) { + int x; + .. + bind(f, _1)(x); + ... +}]]> +</programlisting> + +<programlisting> +<![CDATA[int bar(int, int); +nested(bind(bar, 1, _1));]]> +</programlisting> + +The bind expression inside <literal>foo</literal> becomes: +<programlisting> +bind(bind(bar, 1, _1), _1)(x) +</programlisting> + +The BLL interpretes this as: +<programlisting> +bar(1, x)(x) +</programlisting> +whereas the BB library as +<programlisting> +bar(1, x) +</programlisting> + +To get this functionality in BLL, the bind expression inside the <literal moreinfo="none">foo</literal> function can be written as: +<programlisting> +bind(unlambda(f), _1)(x); +</programlisting> +as explained in <xref linkend = "sect:unlambda"/>. + +</section> + + + + +<para> +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. +</para> + +</section> + + </section> + + +<section> +<title>Contributors</title> + +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. + +</section> + + + +<appendix> +<title>Rationale for some of the design decisions</title> + +<section id="sect:why_weak_arity"> +<title> +Lambda functor arity +</title> + +<para> +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: + +<programlisting> +bind(g, _3, _3, _3)(x, y, z); +bind(g, _1, _1, _1)(x, y, z); +</programlisting> + +This first line discards arguments <literal>x</literal> and +<literal>y</literal>, and makes the call: +<programlisting> +g(z, z, z) +</programlisting> +whereas the second line discards arguments <literal>y</literal> and +<literal>z</literal>, and calls: +<programlisting> +g(x, x, x) +</programlisting> +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 <emphasis>strict arity</emphasis> 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: +<programlisting> +(_3, bind(g, _1, _1, _1))(x, y, z); +</programlisting> +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 +<literal>g(x, x, x)</literal> +even with the strict arity. +</para> + +<para> +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 +<literal>_1 + _2</literal> but mistakenly wrote <literal>_1 + 2</literal>, +with strict arity checking, the complier would spot the error. +However, if the erroneous expression was <literal>1 + _2</literal> 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. +</para> + +</section> + +</appendix> + + + +<bibliography> + +<biblioentry id="cit:stepanov:94"> +<abbrev>STL94</abbrev> +<authorgroup> +<author> +<surname>Stepanov</surname> +<firstname>A. A.</firstname> +</author> +<author> +<surname>Lee</surname> +<firstname>M.</firstname> +</author> +</authorgroup> +<title>The Standard Template Library</title> +<orgname>Hewlett-Packard Laboratories</orgname> +<pubdate>1994</pubdate> +<bibliomisc> +<ulink url="http://www.hpl.hp.com/techreports">www.hpl.hp.com/techreports</ulink> +</bibliomisc> +</biblioentry> + +<biblioentry id="cit:sgi:02"> +<abbrev>SGI02</abbrev> +<title>The SGI Standard Template Library</title> +<pubdate>2002</pubdate> +<bibliomisc><ulink url="http://www.sgi.com/tech/stl/">www.sgi.com/tech/stl/</ulink></bibliomisc> + +</biblioentry> + +<biblioentry id="cit:c++:98"> +<abbrev>C++98</abbrev> +<title>International Standard, Programming Languages – C++</title> +<subtitle>ISO/IEC:14882</subtitle> +<pubdate>1998</pubdate> +</biblioentry> + + +<biblioentry id="cit:jarvi:99"> +<abbrev>Jär99</abbrev> + +<articleinfo> +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> +<title>C++ Function Object Binders Made Easy</title> +</articleinfo> + +<title>Lecture Notes in Computer Science</title> +<volumenum>1977</volumenum> +<publishername>Springer</publishername> + +<pubdate>2000</pubdate> +</biblioentry> + + + +<biblioentry id="cit:jarvi:00"> +<abbrev>Jär00</abbrev> +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> +<author> +<firstname>Gary</firstname> +<surname>Powell</surname> +</author> +<title>The Lambda Library : Lambda Abstraction in C++</title> + <orgname>Turku Centre for Computer Science</orgname> +<bibliomisc>Technical Report </bibliomisc> + <issuenum>378</issuenum> +<pubdate>2000</pubdate> +<bibliomisc><ulink url="http://www.tucs.fi/Publications/techreports/TR378.php">www.tucs.fi/publications</ulink></bibliomisc> + + +</biblioentry> + + +<biblioentry id="cit:jarvi:01"> +<abbrev>Jär01</abbrev> +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> +<author> +<firstname>Gary</firstname> +<surname>Powell</surname> +</author> +<title>The Lambda Library : Lambda Abstraction in C++</title> + <confgroup> + <conftitle>Second Workshop on C++ Template Programming</conftitle> + <address>Tampa Bay, OOPSLA'01</address> + </confgroup> +<pubdate>2001</pubdate> +<bibliomisc><ulink url="http://www.oonumerics.org/tmpw01/">www.oonumerics.org/tmpw01/</ulink></bibliomisc> +</biblioentry> + +<biblioentry id="cit:jarvi:03"> +<abbrev>Jär03</abbrev> + +<articleinfo> + +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> + +<author> +<firstname>Gary</firstname> +<surname>Powell</surname> +</author> + +<author> +<firstname>Andrew</firstname> +<surname>Lumsdaine</surname> +</author> +<title>The Lambda Library : unnamed functions in C++</title> + +</articleinfo> + +<title>Software - Practice and Expreience</title> +<volumenum>33:259-291</volumenum> + + +<pubdate>2003</pubdate> +</biblioentry> + + +<biblioentry id="cit:boost::tuple"> +<abbrev>tuple</abbrev> +<title>The Boost Tuple Library</title> +<bibliomisc><ulink url="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">www.boost.org/libs/tuple/doc/tuple_users_guide.html</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::type_traits"> +<abbrev>type_traits</abbrev> +<title>The Boost type_traits</title> +<bibliomisc><ulink url="http://www.boost.org/libs/type_traits/index.htm">www.boost.org/libs/type_traits/</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::ref"> +<abbrev>ref</abbrev> +<title>Boost ref</title> +<bibliomisc><ulink url="http://www.boost.org/libs/bind/ref.html">www.boost.org/libs/bind/ref.html</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::bind"> +<abbrev>bind</abbrev> +<title>Boost Bind Library</title> +<bibliomisc><ulink url="http://www.boost.org/libs/bind/bind.html">www.boost.org/libs/bind/bind.html</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::function"> +<abbrev>function</abbrev> +<title>Boost Function Library</title> +<bibliomisc><ulink url="http://www.boost.org/libs/function/">www.boost.org/libs/function/</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:fc++"> +<abbrev>fc++</abbrev> +<title>The FC++ library: Functional Programming in C++</title> +<author> +<surname>Smaragdakis</surname> +<firstname>Yannis</firstname> +</author> +<author> +<firstname>Brian</firstname> +<surname>McNamara</surname> +</author> +<bibliomisc><ulink url="http://www.cc.gatech.edu/~yannis/fc++/">www.cc.gatech.edu/~yannis/fc++/</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + + + + +</bibliography> + + + +</library> + + + + + + diff --git a/libs/lambda/doc/detail/lambda_doc.xsl b/libs/lambda/doc/detail/lambda_doc.xsl new file mode 100644 index 000000000..3a622ecd6 --- /dev/null +++ b/libs/lambda/doc/detail/lambda_doc.xsl @@ -0,0 +1,19 @@ +<?xml version='1.0'?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version='1.0' + xmlns="http://www.w3.org/TR/xhtml1/transitional" + exclude-result-prefixes="#default"> + +<xsl:import href="/u/jajarvi/dtd/docbook-xsl/html/docbook.xsl"/> + + +<!-- Add other variable definitions here --> + +<xsl:variable name="shade.verbatim">0</xsl:variable> + +<xsl:variable name="section.autolabel">1</xsl:variable> + +<xsl:variable name="bibliography.collection">lambda_bib.xml</xsl:variable> + + +</xsl:stylesheet> diff --git a/libs/lambda/doc/detail/lambda_doc_chunks.xsl b/libs/lambda/doc/detail/lambda_doc_chunks.xsl new file mode 100644 index 000000000..a63d37929 --- /dev/null +++ b/libs/lambda/doc/detail/lambda_doc_chunks.xsl @@ -0,0 +1,19 @@ +<?xml version='1.0'?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version='1.0' + xmlns="http://www.w3.org/TR/xhtml1/transitional" + exclude-result-prefixes="#default"> + +<xsl:import href="/u/jajarvi/dtd/docbook-xsl/html/chunk.xsl"/> + + +<!-- Add other variable definitions here --> + +<xsl:variable name="shade.verbatim">0</xsl:variable> + +<xsl:variable name="section.autolabel">1</xsl:variable> + +<xsl:variable name="bibliography.collection">lambda_bib.xml</xsl:variable> + + +</xsl:stylesheet> diff --git a/libs/lambda/doc/index.html b/libs/lambda/doc/index.html new file mode 100644 index 000000000..59f1bfc58 --- /dev/null +++ b/libs/lambda/doc/index.html @@ -0,0 +1,12 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; URL=../../../doc/html/lambda.html"> +</head> +<body> +Automatic redirection failed, please go to <a href="../../../doc/html/lambda.html">www.boost.org/doc/html/lambda.html</a> <hr> +<p>© Copyright Beman Dawes, 2001</p> +<p>Distributed under the Boost Software License, Version 1.0. (See accompanying +file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy +at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p> +</body> +</html> diff --git a/libs/lambda/doc/lambda.xml b/libs/lambda/doc/lambda.xml new file mode 100644 index 000000000..6f617aabd --- /dev/null +++ b/libs/lambda/doc/lambda.xml @@ -0,0 +1,3452 @@ +<?xml version="1.0" encoding="ISO-Latin-1"?> +<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" + "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd"> +<library name="Lambda" dirname="lambda" id="lambda" + last-revision="$Date: 2009-06-13 14:18:10 -0700 (Sat, 13 Jun 2009) $" + xmlns:xi="http://www.w3.org/2001/XInclude"> +<libraryinfo> + <author> + <firstname>Jaakko</firstname> + <surname>Järvi</surname> + <email>jarvi at cs tamu edu</email> + </author> + + <copyright> + <year>1999</year> + <year>2000</year> + <year>2001</year> + <year>2002</year> + <year>2003</year> + <year>2004</year> + <holder>Jaakko Järvi</holder> + <holder>Gary Powell</holder> + </copyright> + + <legalnotice> + <para>Use, modification and distribution is subject to the Boost + Software License, Version 1.0. (See accompanying file + <filename>LICENSE_1_0.txt</filename> or copy at <ulink + url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)</para> + </legalnotice> + + <librarypurpose>Define small unnamed function objects at the actual call site, and more</librarypurpose> + <librarycategory name="category:higher-order"/> +</libraryinfo> + +<title>Boost.Lambda</title> + + <!-- --> + + <section id="introduction"> + + <title>In a nutshell</title> + + <para> + + The Boost Lambda Library (BLL in the sequel) is a C++ template + library, which implements a form of <emphasis>lambda abstractions</emphasis> 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 + <literal>a</literal> separated by spaces: + + <programlisting><![CDATA[for_each(a.begin(), a.end(), std::cout << _1 << ' ');]]></programlisting> + + The expression <literal><![CDATA[std::cout << _1 << ' ']]></literal> defines a unary function object. + The variable <literal>_1</literal> is the parameter of this function, a <emphasis>placeholder</emphasis> for the actual argument. + Within each iteration of <literal>for_each</literal>, the function is + called with an element of <literal>a</literal> as the actual argument. + This actual argument is substituted for the placeholder, and the <quote>body</quote> of the function is evaluated. + </para> + + <para>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. + </para> + </section> + + <section id="lambda.getting_started"> + <title>Getting Started</title> + + <section> + <title>Installing the library</title> + + + <para> + The library consists of include files only, hence there is no + installation procedure. The <literal>boost</literal> include directory + must be on the include path. + There are a number of include files that give different functionality: + + <!-- TODO: tarkista vielä riippuvuudet--> + <itemizedlist> + + <listitem><para> + <filename>lambda/lambda.hpp</filename> defines lambda expressions for different C++ + operators, see <xref linkend="lambda.operator_expressions"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/bind.hpp</filename> defines <literal>bind</literal> functions for up to 9 arguments, see <xref linkend="lambda.bind_expressions"/>.</para></listitem> + + + <listitem><para> + <filename>lambda/if.hpp</filename> defines lambda function equivalents for if statements and the conditional operator, see <xref linkend="lambda.lambda_expressions_for_control_structures"/> (includes <filename>lambda.hpp</filename>). + </para></listitem> + + <listitem><para> + <filename>lambda/loops.hpp</filename> defines lambda function equivalent for looping constructs, see <xref linkend="lambda.lambda_expressions_for_control_structures"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/switch.hpp</filename> defines lambda function equivalent for the switch statement, see <xref linkend="lambda.lambda_expressions_for_control_structures"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/construct.hpp</filename> provides tools for writing lambda expressions with constructor, destructor, new and delete invocations, see <xref linkend="lambda.construction_and_destruction"/> (includes <filename>lambda.hpp</filename>). + </para></listitem> + + <listitem><para> + <filename>lambda/casts.hpp</filename> provides lambda versions of different casts, as well as <literal>sizeof</literal> and <literal>typeid</literal>, see <xref linkend="lambda.cast_expressions"/>. + </para></listitem> + + <listitem><para> + <filename>lambda/exceptions.hpp</filename> gives tools for throwing and catching + exceptions within lambda functions, <xref linkend="lambda.exceptions"/> (includes + <filename>lambda.hpp</filename>). + </para></listitem> + + <listitem><para> + <filename>lambda/algorithm.hpp</filename> and <filename>lambda/numeric.hpp</filename> (cf. standard <filename>algortihm</filename> and <filename>numeric</filename> headers) allow nested STL algorithm invocations, see <xref linkend="lambda.nested_stl_algorithms"/>. + </para></listitem> + + </itemizedlist> + + Any other header files in the package are for internal use. + Additionally, the library depends on two other Boost Libraries, the + <emphasis>Tuple</emphasis> <xref linkend="cit:boost::tuple"/> and the <emphasis>type_traits</emphasis> <xref linkend="cit:boost::type_traits"/> libraries, and on the <filename>boost/ref.hpp</filename> header. + </para> + + <para> + All definitions are placed in the namespace <literal>boost::lambda</literal> and its subnamespaces. + </para> + + </section> + + <section> + <title>Conventions used in this document</title> + + <para>In most code examples, we omit the namespace prefixes for names in the <literal moreinfo="none">std</literal> and <literal moreinfo="none">boost::lambda</literal> namespaces. +Implicit using declarations +<programlisting> +using namespace std; +using namespace boost::lambda; +</programlisting> +are assumed to be in effect. +</para> + + </section> + </section> + + <section> + <title>Introduction</title> + + <section> + <title>Motivation</title> + <para>The Standard Template Library (STL) + <xref role="citation" linkend="cit:stepanov:94"/>, now part of the C++ Standard Library <xref role="citation" linkend="cit:c++:98"/>, is a generic container and algorithm library. +Typically STL algorithms operate on container elements via <emphasis>function objects</emphasis>. These function objects are passed as arguments to the algorithms. +</para> + +<para> +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 <literal>plus</literal>, <literal>less</literal> and <literal>not1</literal>). +As an example, one possible implementation for the standard <literal>plus</literal> template is: + +<programlisting> +<![CDATA[template <class T> +struct plus : public binary_function<T, T, T> { + T operator()(const T& i, const T& j) const { + return i + j; + } +};]]> +</programlisting> + +The base class <literal><![CDATA[binary_function<T, T, T>]]></literal> contains typedefs for the argument and return types of the function object, which are needed to make the function object <emphasis>adaptable</emphasis>. +</para> + +<para> +In addition to the basic function object classes, such as the one above, +the STL contains <emphasis>binder</emphasis> 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: + +<programlisting> +<![CDATA[class plus_1 { + int _i; +public: + plus_1(const int& i) : _i(i) {} + int operator()(const int& j) { return _i + j; } +};]]> +</programlisting> + +the equivalent functionality can be achieved with the <literal moreinfo="none">plus</literal> template and one of the binder templates (<literal moreinfo="none">bind1st</literal>). +E.g., the following two expressions create function objects with identical functionalities; +when invoked, both return the result of adding <literal moreinfo="none">1</literal> to the argument of the function object: + +<programlisting> +<![CDATA[plus_1(1) +bind1st(plus<int>(), 1)]]> +</programlisting> + +The subexpression <literal><![CDATA[plus<int>()]]></literal> in the latter line is a binary function object which computes the sum of two integers, and <literal>bind1st</literal> invokes this function object partially binding the first argument to <literal>1</literal>. +As an example of using the above function object, the following code adds <literal>1</literal> to each element of some container <literal>a</literal> and outputs the results into the standard output stream <literal>cout</literal>. + +<programlisting> +<![CDATA[transform(a.begin(), a.end(), ostream_iterator<int>(cout), + bind1st(plus<int>(), 1));]]> +</programlisting> + +</para> + +<para> +To make the binder templates more generally applicable, the STL contains <emphasis>adaptors</emphasis> 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 <xref linkend="cit:sgi:02"/>. + </para> + +<para> +All these tools aim at one goal: to make it possible to specify +<emphasis>unnamed functions</emphasis> 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. +</para> + +<para> +The Boost Lambda Library provides solutions for the problems described above: + +<itemizedlist> +<listitem> +<para> +Unnamed functions can be created easily with an intuitive syntax. + +The above example can be written as: + +<programlisting> +<![CDATA[transform(a.begin(), a.end(), ostream_iterator<int>(cout), + 1 + _1);]]> +</programlisting> + +or even more intuitively: + +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), cout << (1 + _1));]]> +</programlisting> +</para> + +</listitem> + +<listitem> +<para> +Most of the restrictions in argument binding are removed, +arbitrary arguments of practically any C++ function can be bound. +</para> +</listitem> + +<listitem> +<para> +Separate function composition operations are not needed, +as function composition is supported implicitly. + +</para> +</listitem> + +</itemizedlist> + +</para> + +</section> + + + +<section> + <title>Introduction to lambda expressions</title> + + <para> + 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: + + +<programlisting> +lambda x<subscript>1</subscript> ... x<subscript>n</subscript>.e +</programlisting> + <!-- $\lambda x_1 \cdots x_n . e$ --> + + A lambda expression defines an unnamed function and consists of: + <itemizedlist> + <listitem> + <para> + the parameters of this function: <literal>x<subscript>1</subscript> ... x<subscript>n</subscript></literal>. + <!--$x_1 \cdots x_n$--> + </para> + </listitem> + <listitem> + <para>the expression e which computes the value of the function in terms of the parameters <literal>x<subscript>1</subscript> ... x<subscript>n</subscript></literal>. + </para> + </listitem> + </itemizedlist> + + A simple example of a lambda expression is +<programlisting> +lambda x y.x+y +</programlisting> +Applying the lambda function means substituting the formal parameters with the actual arguments: +<programlisting> +(lambda x y.x+y) 2 3 = 2 + 3 = 5 +</programlisting> + + + </para> + +<para> +In the C++ version of lambda expressions the <literal>lambda x<subscript>1</subscript> ... x<subscript>n</subscript></literal> 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 <emphasis>placeholders</emphasis>: +<literal>_1</literal>, <literal>_2</literal> and <literal>_3</literal>. +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 +<programlisting>lambda x y.x+y</programlisting> +is +<programlisting>_1 + _2</programlisting> +</para> + + <para> +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 <literal>bind</literal> function. + + As an example, consider the lambda expression: + + <programlisting>lambda x y.foo(x,y)</programlisting> + + Rather than <literal>foo(_1, _2)</literal>, the C++ counterpart for this expression is: + + <programlisting>bind(foo, _1, _2)</programlisting> + + We refer to this type of C++ lambda expressions as <emphasis>bind expressions</emphasis>. + </para> + + <para>A lambda expression defines a C++ function object, hence function application syntax is like calling any other function object, for instance: <literal>(_1 + _2)(i, j)</literal>. + + + </para> + + + +<section id="lambda.partial_function_application"> +<title>Partial function application</title> + +<para> +A bind expression is in effect a <emphasis>partial function application</emphasis>. +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. + </para> + +<!-- <para>The underlying implementation of the BLL unifies the two types of lambda expressions (bind expressions and lambda expressions consisting of operator calls). + If operators are regarded as functions, it is easy to see that lambda expressions using operators are partial function applications as well. + E.g. the lambda expression <literal>_1 + 1</literal> can be seen as syntactic sugar for the pseudo code <literal>bind(operator+, _1, 1)</literal>. + </para> +--> + + </section> + + + + <section id="lambda.terminology"> + <title>Terminology</title> + + <para> + A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, <emphasis>a functor</emphasis>, when evaluated. We use the name <emphasis>lambda functor</emphasis> to refer to such a function object. + Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor. + </para> + + </section> + + </section> + + + + </section> + + <section id = "lambda.using_library"> + <title>Using the library</title> + + <para> +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. + + + </para> + + <section id = "lambda.introductory_examples"> + <title>Introductory Examples</title> + + <para> + 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 <literal>list</literal>, to the value <literal>1</literal>: + + + <programlisting> +<![CDATA[list<int> v(10); +for_each(v.begin(), v.end(), _1 = 1);]]></programlisting> + + The expression <literal>_1 = 1</literal> creates a lambda functor which assigns the value <literal>1</literal> to every element in <literal>v</literal>.<footnote> +<para> +Strictly taken, the C++ standard defines <literal>for_each</literal> as a <emphasis>non-modifying sequence operation</emphasis>, and the function object passed to <literal moreinfo="none">for_each</literal> should not modify its argument. +The requirements for the arguments of <literal>for_each</literal> are unnecessary strict, since as long as the iterators are <emphasis>mutable</emphasis>, <literal>for_each</literal> 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<literal>std::for_each</literal> but more fine-grained requirements for its arguments. +</para> +</footnote> + </para> + + <para> + Next, we create a container of pointers and make them point to the elements in the first container <literal>v</literal>: + + <programlisting> +<![CDATA[vector<int*> vp(10); +transform(v.begin(), v.end(), vp.begin(), &_1);]]></programlisting> + +The expression <literal><![CDATA[&_1]]></literal> creates a function object for getting the address of each element in <literal>v</literal>. +The addresses get assigned to the corresponding elements in <literal>vp</literal>. + </para> + + <para> + The next code fragment changes the values in <literal>v</literal>. + For each element, the function <literal>foo</literal> is called. +The original value of the element is passed as an argument to <literal>foo</literal>. +The result of <literal>foo</literal> is assigned back to the element: + + + <programlisting> +<![CDATA[int foo(int); +for_each(v.begin(), v.end(), _1 = bind(foo, _1));]]></programlisting> + </para> + + + <para> + The next step is to sort the elements of <literal>vp</literal>: + + <programlisting>sort(vp.begin(), vp.end(), *_1 > *_2);</programlisting> + + In this call to <literal>sort</literal>, we are sorting the elements by their contents in descending order. + </para> + + <para> + Finally, the following <literal>for_each</literal> call outputs the sorted content of <literal>vp</literal> separated by line breaks: + +<programlisting> +<![CDATA[for_each(vp.begin(), vp.end(), cout << *_1 << '\n');]]> +</programlisting> + +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 +<programlisting> +<![CDATA[for_each(vp.begin(), vp.end(), cout << '\n' << *_1);]]> +</programlisting> +the subexpression <literal><![CDATA[cout << '\n']]></literal> is evaluated immediately and the effect is to output a single line break, followed by the elements of <literal>vp</literal>. +The BLL provides functions <literal>constant</literal> and <literal>var</literal> to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions: +<programlisting> +<![CDATA[for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);]]> +</programlisting> +These functions are described more thoroughly in <xref linkend="lambda.delaying_constants_and_variables"/> + +</para> + + + + + + </section> + + + <section id="lambda.parameter_and_return_types"> + <title>Parameter and return types of lambda functors</title> + + <para> + 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 + <literal>_1 + _2</literal> creates a binary lambda functor. + It can be called with two objects of any types <literal>A</literal> and <literal>B</literal> for which <literal>operator+(A,B)</literal> is defined (and for which BLL knows the return type of the operator, see below). + </para> + + <para> + 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. + </para> + + <!-- TODO: move this forward, and just refer to it. --> + <para> + There are, however, cases when the return type cannot be deduced. For example, suppose you have defined: + + <programlisting>C operator+(A, B);</programlisting> + + The following lambda function invocation fails, since the return type cannot be deduced: + + <programlisting>A a; B b; (_1 + _2)(a, b);</programlisting> + </para> + + <para> + There are two alternative solutions to this. + The first is to extend the BLL type deduction system to cover your own types (see <xref linkend="lambda.extending"/>). + The second is to use a special lambda expression (<literal>ret</literal>) which defines the return type in place (see <xref linkend = "lambda.overriding_deduced_return_type"/>): + + <programlisting><![CDATA[A a; B b; ret<C>(_1 + _2)(a, b);]]></programlisting> + </para> + + <para> + For bind expressions, the return type can be defined as a template argument of the bind function as well: + <programlisting><![CDATA[bind<int>(foo, _1, _2);]]></programlisting> + +<!-- + A rare case, where the <literal><![CDATA[ret<type>(bind(...))]]></literal> syntax does not work, but + <literal><![CDATA[bind<type>(...)]]></literal> does, is explained in <xref linkend="lambda.nullary_functors_and_ret"/>. +--> + </para> + </section> + + <section id="lambda.actual_arguments_to_lambda_functors"> + <title>About actual arguments to lambda functors</title> + +<!-- <para><emphasis>This section is no longer (or currently) relevant; + acual arguments can be non-const rvalues. + The section can, however, become relevant again, if in the future BLL will support + lambda functors with higher arities than 3.</emphasis></para> --> + + <para>A general restriction for the actual arguments is that they cannot be non-const rvalues. + For example: + +<programlisting> +int i = 1; int j = 2; +(_1 + _2)(i, j); // ok +(_1 + _2)(1, 2); // error (!) +</programlisting> + + 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 +<xref linkend="lambda.rvalues_as_actual_arguments"/>. + + + </para> + + </section> + + +<section id="lambda.storing_bound_arguments"> + +<title>Storing bound arguments in lambda functions</title> + +<para> + +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: +<programlisting> +int i = 1; +(_1 = 2, _1 + i)(i); +</programlisting> +The comma operator is overloaded to combine lambda expressions into a sequence; +the resulting unary lambda functor first assigns 2 to its argument, +then adds the value of <literal>i</literal> to it. +The value of the expression in the last line is 3, not 4. +In other words, the lambda expression that is created is +<literal>lambda x.(x = 2, x + 1)</literal> rather than +<literal>lambda x.(x = 2, x + i)</literal>. + +</para> + +<para> + +As said, this is the default behavior for which there are exceptions. +The exact rules are as follows: + +<itemizedlist> + +<listitem> + +<para> + +The programmer can control the storing mechanism with <literal>ref</literal> +and <literal>cref</literal> wrappers <xref linkend="cit:boost::ref"/>. + +Wrapping an argument with <literal>ref</literal>, or <literal>cref</literal>, +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 +<literal>i</literal> with <literal>ref</literal>, +we are creating the lambda expression <literal>lambda x.(x = 2, x + i)</literal> +and the value of the expression in the last line will be 4: + +<programlisting> +i = 1; +(_1 = 2, _1 + ref(i))(i); +</programlisting> + +Note that <literal>ref</literal> and <literal>cref</literal> are different +from <literal>var</literal> and <literal>constant</literal>. + +While the latter ones create lambda functors, the former do not. +For example: + +<programlisting> +int i; +var(i) = 1; // ok +ref(i) = 1; // not ok, ref(i) is not a lambda functor +</programlisting> + +The functions <literal>ref</literal> and <literal>cref</literal> mostly +exist for historical reasons, +and <literal>ref</literal> can always +be replaced with <literal>var</literal>, and <literal>cref</literal> with +<literal>constant_ref</literal>. +See <xref linkend="lambda.delaying_constants_and_variables"/> for details. +The <literal>ref</literal> and <literal>cref</literal> functions are +general purpose utility functions in Boost, and hence defined directly +in the <literal moreinfo="none">boost</literal> namespace. + +</para> +</listitem> + +<listitem> +<para> +Array types cannot be copied, they are thus stored as const reference by default. +</para> +</listitem> + +<listitem> + +<para> +For some expressions it makes more sense to store the arguments as references. + +For example, the obvious intention of the lambda expression +<literal>i += _1</literal> is that calls to the lambda functor affect the +value of the variable <literal>i</literal>, +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: + +<itemizedlist> +<listitem> +<para>The left argument of compound assignment operators (<literal>+=</literal>, <literal>*=</literal>, etc.) are stored as references to non-const.</para> +</listitem> + +<listitem> +<para>If the left argument of <literal><![CDATA[<<]]></literal> or <literal><![CDATA[>>]]></literal> operator is derived from an instantiation of <literal>basic_ostream</literal> or respectively from <literal>basic_istream</literal>, the argument is stored as a reference to non-const. +For all other types, the argument is stored as a copy. +</para> +</listitem> + +<listitem> +<para> +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. + +</para> +</listitem> + +</itemizedlist> + +</para> +</listitem> + +</itemizedlist> +</para> + +</section> + +</section> + +<section id="lambda.le_in_details"> +<title>Lambda expressions in details</title> + +<para> +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. + + +</para> + +<section id="lambda.placeholders"> +<title>Placeholders</title> + +<para> +The BLL defines three placeholder types: <literal>placeholder1_type</literal>, <literal>placeholder2_type</literal> and <literal>placeholder3_type</literal>. +BLL has a predefined placeholder variable for each placeholder type: <literal>_1</literal>, <literal>_2</literal> and <literal>_3</literal>. +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: + +<programlisting>boost::lambda::placeholder1_type X; +boost::lambda::placeholder2_type Y; +boost::lambda::placeholder3_type Z; +</programlisting> + +With these variables defined, <literal>X += Y * Z</literal> is equivalent to <literal>_1 += _2 * _3</literal>. +</para> + +<para> +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: + +<programlisting> +_1 + 5 // unary +_1 * _1 + _1 // unary +_1 + _2 // binary +bind(f, _1, _2, _3) // 3-ary +_3 + 10 // 3-ary +</programlisting> + +Note that the last line creates a 3-ary function, which adds <literal>10</literal> to its <emphasis>third</emphasis> 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: + +<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 +</programlisting> + +See +<xref linkend="lambda.why_weak_arity"/> for the design rationale behind this +functionality. + +</para> + +<para> +In addition to these three placeholder types, there is also a fourth placeholder type <literal>placeholderE_type</literal>. +The use of this placeholder is defined in <xref linkend="lambda.exceptions"/> describing exception handling in lambda expressions. +</para> + +<para>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: + + +<programlisting> +<![CDATA[int i = 1; +(_1 += 2)(i); // i is now 3 +(++_1, cout << _1)(i) // i is now 4, outputs 4]]> +</programlisting> +</para> + +</section> + +<section id="lambda.operator_expressions"> +<title>Operator expressions</title> + +<para> +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: + +<programlisting><![CDATA[cout << _1, _2[_3] = _1 && false]]></programlisting> +</para> + +<para> +However, there are some restrictions that originate from the C++ operator overloading rules, and some special cases. +</para> + + +<section> +<title>Operators that cannot be overloaded</title> + +<para> +Some operators cannot be overloaded at all (<literal>::</literal>, <literal>.</literal>, <literal>.*</literal>). +For some operators, the requirements on return types prevent them to be overloaded to create lambda functors. +These operators are <literal>->.</literal>, <literal>-></literal>, <literal>new</literal>, <literal>new[]</literal>, <literal>delete</literal>, <literal>delete[]</literal> and <literal>?:</literal> (the conditional operator). +</para> + +</section> + +<section id="lambda.assignment_and_subscript"> +<title>Assignment and subscript operators</title> + +<para> +These operators must be implemented as class members. +Consequently, the left operand must be a lambda expression. For example: + +<programlisting> +int i; +_1 = i; // ok +i = _1; // not ok. i is not a lambda expression +</programlisting> + +There is a simple solution around this limitation, described in <xref linkend="lambda.delaying_constants_and_variables"/>. +In short, +the left hand argument can be explicitly turned into a lambda functor by wrapping it with a special <literal>var</literal> function: +<programlisting> +var(i) = _1; // ok +</programlisting> + +</para> +</section> + +<section id="lambda.logical_operators"> +<title>Logical operators</title> + +<para> +Logical operators obey the short-circuiting evaluation rules. For example, in the following code, <literal>i</literal> is never incremented: +<programlisting> +bool flag = true; int i = 0; +(_1 || ++_2)(flag, i); +</programlisting> +</para> +</section> + +<section id="lambda.comma_operator"> +<title>Comma operator</title> + +<para> +Comma operator is the <quote>statement separator</quote> in lambda expressions. +Since comma is also the separator between arguments in a function call, extra parenthesis are sometimes needed: + +<programlisting> +for_each(a.begin(), a.end(), (++_1, cout << _1)); +</programlisting> + +Without the extra parenthesis around <literal>++_1, cout << _1</literal>, the code would be interpreted as an attempt to call <literal>for_each</literal> with four arguments. +</para> +<para> +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 <literal>a</literal> is first incremented, then written to the stream. +</para> +</section> + +<section id="lambda.function_call_operator"> +<title>Function call operator</title> + +<para> +The function call operators have the effect of evaluating the lambda +functor. +Calls with too few arguments lead to a compile time error. +</para> +</section> + +<section id="lambda.member_pointer_operator"> +<title>Member pointer operator</title> + +<para> +The member pointer operator <literal>operator->*</literal> 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 <literal>A</literal>, and the right hand argument is a pointer to a member of <literal>A</literal>, or a pointer to a member of a class from which <literal>A</literal> derives. +We must separate two cases: + +<itemizedlist> + +<listitem> +<para>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: +<programlisting> +<![CDATA[struct A { int d; }; +A* a = new A(); + ... +(a ->* &A::d); // returns a reference to a->d +(_1 ->* &A::d)(a); // likewise]]> +</programlisting> +</para> +</listitem> + +<listitem> +<para> +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: +<programlisting> +<![CDATA[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)]]> +</programlisting> +</para> +</listitem> +</itemizedlist> +</para> +</section> + +</section> + +<section id="lambda.bind_expressions"> +<title>Bind expressions</title> + +<para> +Bind expressions can have two forms: + +<!-- TODO: shouldn't really be emphasis, but a variable or something--> +<programlisting> +bind(<parameter>target-function</parameter>, <parameter>bind-argument-list</parameter>) +bind(<parameter>target-member-function</parameter>, <parameter>object-argument</parameter>, <parameter>bind-argument-list</parameter>) +</programlisting> + +A bind expression delays the call of a function. +If this <emphasis>target function</emphasis> is <emphasis>n</emphasis>-ary, then the <literal><emphasis>bind-argument-list</emphasis></literal> must contain <emphasis>n</emphasis> arguments as well. +In the current version of the BLL, <inlineequation>0 <= n <= 9</inlineequation> must hold. +For member functions, the number of arguments must be at most <inlineequation>8</inlineequation>, as the object argument takes one argument position. + +Basically, the +<emphasis><literal>bind-argument-list</literal></emphasis> 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 <emphasis><literal>bind-argument-list</literal></emphasis> (see <xref linkend="lambda.placeholders"/>). +</para> + +<para> +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: +<programlisting> +bind<<emphasis>RET</emphasis>>(<emphasis>target-function</emphasis>, <emphasis>bind-argument-list</emphasis>) +</programlisting> +This is only necessary if the return type of the target function cannot be deduced. +</para> + +<para> +The following sections describe the different types of bind expressions. +</para> + +<section id="lambda.function_pointers_as_targets"> +<title>Function pointers or references as targets</title> + +<para>The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example: +<programlisting> +<![CDATA[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);]]> +</programlisting> + +The return type deduction always succeeds with this type of bind expressions. +</para> + +<para> +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.: +<programlisting> +<![CDATA[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]]> +</programlisting> +</para> +</section> + +<section id="member_functions_as_targets"> +<title>Member functions as targets</title> + +<para> +The syntax for using pointers to member function in bind expression is: +<programlisting> +bind(<parameter>target-member-function</parameter>, <parameter>object-argument</parameter>, <parameter>bind-argument-list</parameter>) +</programlisting> + +The object argument can be a reference or pointer to the object, the BLL supports both cases with a uniform interface: + +<programlisting> +<![CDATA[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));]]> +</programlisting> + +Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference: + +<programlisting> +<![CDATA[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));]]> +</programlisting> + +</para> + +<!--%The exact rules for the object argument (whether it is bound, or supplied in the lambda function invoction) are as follows: +%If the target function is a pointer to a member function of some class \snip{A}, then the object argument must be an expression of type \snip{B}, where either +%\begin{itemize} +%\item \snip{B} = \snip{A} or there is an implicit conversion from \snip{B} to \snip{A}. +%\item \snip{B} = \snip{A*}. +%\item \snip{B} = \snip{C*}, where \snip{C} is any class derived form \snip{A}. +%\end{itemize} +%For example: +%\begin{alltt} +%struct A \{ +% virtual void f(); +% void fc() const; +%\}; +% +%struct B : public A \{ +% virtual void f(); +%\}; +% +%struct C \{ +% operator A const() \{ return A(); \} +%\}; +% +% A a; B b; C c; +% ... +% bind(&A::f, a)(); +% bind(&A::f, b)(); // calls B::f +% bind(&A::fc, c)(); +% +% bind(&A::f, &a)(); +% bind(&A::f, &b)(); // calls B::f +% bind(&A::f, &c)(); // error: no conversion from C* \(\rightarrow\) A, +%\end{alltt} +--> + +<para> +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 <literal>bind</literal>-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 <xref linkend="lambda.storing_bound_arguments"/>); 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: +<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; }; +}; +</programlisting> + +When a pointer is used, the behavior is what the programmer might expect: + +<programlisting> +<![CDATA[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]]> +</programlisting> + +Even though a const copy of the object argument is stored, the original object <literal>a</literal> 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: + +<programlisting> +<![CDATA[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]]> +</programlisting> +</para> + +<para> +To prevent the copying from taking place, one can use the <literal>ref</literal> or <literal>cref</literal> wrappers (<literal>var</literal> and <literal>constant_ref</literal> would do as well): +<programlisting> +<![CDATA[bind(&A::set_i, ref(a), _1)(k); // a.j == 1 +bind(&A::set_j, cref(a), _1)(k); // a.j == 1]]> +</programlisting> +</para> + +<para>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 <literal>a</literal> is not copied in the calls to the two lambda functors below: +<programlisting> +<![CDATA[A a(0,0); +bind(&A::set_i, _1, 1)(a); // a.i == 1 +bind(&A::set_j, _1, 1)(a); // a.j == 1]]> +</programlisting> +</para> +</section> + +<section id="lambda.members_variables_as_targets"> +<title>Member variables as targets</title> + +<para> +A pointer to a member variable is not really a function, but +the first argument to the <literal>bind</literal> function can nevertheless +be a pointer to a member variable. +Invoking such a bind expression returns a reference to the data member. +For example: + +<programlisting> +<![CDATA[struct A { int data; }; +A a; +bind(&A::data, _1)(a) = 1; // a.data == 1]]> +</programlisting> + +The cv-qualifiers of the object whose member is accessed are respected. +For example, the following tries to write into a const location: +<programlisting> +<![CDATA[const A ca = a; +bind(&A::data, _1)(ca) = 1; // error]]> +</programlisting> + +</para> +</section> + +<section id="lambda.function_objects_as_targets"> +<title>Function objects as targets</title> + +<para> + +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 are two methods for giving BLL this capability for a certain +function object class. + +</para> + +<simplesect> + +<title>The result_type typedef</title> + +<para> + +The BLL supports the standard library convention of declaring the return type +of a function object with a member typedef named <literal>result_type</literal> in the +function object class. + +Here is a simple example: +<programlisting> +<![CDATA[struct A { + typedef B result_type; + B operator()(X, Y, Z); +};]]> +</programlisting> + +If a function object does not define a <literal>result_type</literal> typedef, +the method described below (<literal>sig</literal> template) +is attempted to resolve the return type of the +function object. If a function object defines both <literal>result_type</literal> +and <literal>sig</literal>, <literal>result_type</literal> takes precedence. + +</para> + +</simplesect> + +<simplesect> + +<title>The sig template</title> + +<para> +Another mechanism that make BLL aware of the return type(s) of a function object is defining +member template struct +<literal><![CDATA[sig<Args>]]></literal> with a typedef +<literal>type</literal> that specifies the return type. + +Here is a simple example: +<programlisting> +<![CDATA[struct A { + template <class Args> struct sig { typedef B type; } + B operator()(X, Y, Z); +};]]> +</programlisting> + +The template argument <literal>Args</literal> is a +<literal>tuple</literal> (or more precisely a <literal>cons</literal> list) +type <xref linkend="cit:boost::tuple"/>, 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 defining the <literal>result_type</literal> typedef. +Howver, there are two significant restrictions with using just a simple +typedef to express the return type: +<orderedlist> +<listitem> +<para> +If the function object defines several function call operators, there is no way to specify different result types for them. +</para> +</listitem> +<listitem> +<para> +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. +</para> +</listitem> +</orderedlist> + +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 +<literal>sig</literal> template: + +<programlisting> +<![CDATA[struct A { + + // the return type equals the third argument type: + template<class T1, class T2, class T3> + T3 operator()(const T1& t1, const T2& t2, const T3& t3) const; + + 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; + }; +};]]> +</programlisting> + + +The elements of the <literal>Args</literal> tuple are always +non-reference types. + +Moreover, the element types can have a const or volatile qualifier +(jointly referred to as <emphasis>cv-qualifiers</emphasis>), 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 <literal>Args</literal> 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. +</para> + +<para> +The <literal>sig</literal> template can be seen as a +<emphasis>meta-function</emphasis> 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 <xref linkend="cit:boost::type_traits"/> and +Tuple <xref linkend="cit:boost::type_traits"/> libraries +for tools that can aid in these tasks. +The <literal>sig</literal> templates are a refined version of a similar +mechanism first introduced in the FC++ library +<xref linkend="cit:fc++"/>. +</para> + +</simplesect> + +</section> + + + +</section> + +<section id="lambda.overriding_deduced_return_type"> +<title>Overriding the deduced return type</title> + +<para> +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. +<!-- (see the example in <xref linkend="lambda.parameter_and_return_types"/>).--> +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 <literal>e</literal> is <literal>T</literal>, you can write: + +<programlisting><![CDATA[ret<T>(e);]]></programlisting> + +The effect is that the return type deduction is not performed for the lambda expression <literal>e</literal> at all, but instead, <literal>T</literal> is used as the return type. +Obviously <literal>T</literal> cannot be an arbitrary type, the true result of the lambda functor must be implicitly convertible to <literal>T</literal>. +For example: + +<programlisting> +<![CDATA[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]]> +</programlisting> +For bind expressions, there is a short-hand notation that can be used instead of <literal>ret</literal>. +The last line could alternatively be written as: + +<programlisting><![CDATA[bind<Z>(x, _1)(i);]]></programlisting> +This feature is modeled after the Boost Bind library <xref linkend="cit:boost::bind"/>. + +</para> + +<para>Note that within nested lambda expressions, +the <literal>ret</literal> must be used at each subexpression where +the deduction would otherwise fail. +For example: +<programlisting> +<![CDATA[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]]> +</programlisting> +</para> + +<para>If you find yourself using <literal>ret</literal> repeatedly with the same types, it is worth while extending the return type deduction (see <xref linkend="lambda.extending"/>). +</para> + +<section id="lambda.nullary_functors_and_ret"> +<title>Nullary lambda functors and ret</title> + +<para> +As stated above, the effect of <literal>ret</literal> 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 <literal>ret</literal>, best described with an example: + +<programlisting> +<![CDATA[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!]]> +</programlisting> +The BLL cannot deduce the return types of the above bind calls, as <literal>F</literal> does not define the typedef <literal>result_type</literal>. +One would expect <literal>ret</literal> 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. +</para> + +<para>The solution to this is not to use the <literal>ret</literal> function, but rather define the return type as an explicitly specified template parameter in the <literal>bind</literal> call: +<programlisting> +<![CDATA[bind<int>(f, 1); // ok]]> +</programlisting> + +The lambda functors created with +<literal>ret<<parameter>T</parameter>>(bind(<parameter>arg-list</parameter>))</literal> and +<literal>bind<<parameter>T</parameter>>(<parameter>arg-list</parameter>)</literal> have the exact same functionality — +apart from the fact that for some nullary lambda functors the former does not work while the latter does. +</para> +</section> +</section> + + +<section id="lambda.delaying_constants_and_variables"> +<title>Delaying constants and variables</title> + +<para> +The unary functions <literal>constant</literal>, +<literal>constant_ref</literal> and <literal>var</literal> 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 <emphasis>delayed</emphasis> constants and variables is sometimes necessary due to the lack of explicit syntax for lambda expressions. +For example: +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), cout << _1 << ' '); +for_each(a.begin(), a.end(), cout << ' ' << _1);]]> +</programlisting> +The first line outputs the elements of <literal>a</literal> separated by spaces, while the second line outputs a space followed by the elements of <literal>a</literal> without any separators. +The reason for this is that neither of the operands of +<literal><![CDATA[cout << ' ']]></literal> is a lambda expression, hence <literal><![CDATA[cout << ' ']]></literal> is evaluated immediately. + +To delay the evaluation of <literal><![CDATA[cout << ' ']]></literal>, one of the operands must be explicitly marked as a lambda expression. +This is accomplished with the <literal>constant</literal> function: +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), cout << constant(' ') << _1);]]> +</programlisting> + +The call <literal>constant(' ')</literal> creates a nullary lambda functor which stores the character constant <literal>' '</literal> +and returns a reference to it when invoked. +The function <literal>constant_ref</literal> is similar, except that it +stores a constant reference to its argument. + +The <literal>constant</literal> and <literal>consant_ref</literal> are only +needed when the operator call has side effects, like in the above example. +</para> + +<para> +Sometimes we need to delay the evaluation of a variable. +Suppose we wanted to output the elements of a container in a numbered list: + +<programlisting> +<![CDATA[int index = 0; +for_each(a.begin(), a.end(), cout << ++index << ':' << _1 << '\n'); +for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1 << '\n');]]> +</programlisting> + +The first <literal>for_each</literal> invocation does not do what we want; <literal>index</literal> is incremented only once, and its value is written into the output stream only once. +By using <literal>var</literal> to make <literal>index</literal> a lambda expression, we get the desired effect. +<!-- Note that <literal>var</literal> accepts const objects as well, in which case +calling <literal>var</literal> equals calling <literal>constant_ref</literal>.--> +</para> + +<para> +In sum, <literal>var(x)</literal> creates a nullary lambda functor, +which stores a reference to the variable <literal>x</literal>. +When the lambda functor is invoked, a reference to <literal>x</literal> is returned. +</para> + +<simplesect> +<title>Naming delayed constants and variables</title> + +<para> +It is possible to predefine and name a delayed variable or constant outside a lambda expression. +The templates <literal>var_type</literal>, <literal>constant_type</literal> +and <literal>constant_ref_type</literal> serve for this purpose. +They are used as: +<programlisting> +<![CDATA[var_type<T>::type delayed_i(var(i)); +constant_type<T>::type delayed_c(constant(c));]]> +</programlisting> +The first line defines the variable <literal>delayed_i</literal> which is a delayed version of the variable <literal>i</literal> of type <literal>T</literal>. +Analogously, the second line defines the constant <literal>delayed_c</literal> as a delayed version of the constant <literal>c</literal>. +For example: + +<programlisting> +int i = 0; int j; +for_each(a.begin(), a.end(), (var(j) = _1, _1 = var(i), var(i) = var(j))); +</programlisting> +is equivalent to: +<programlisting> +<![CDATA[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));]]> +</programlisting> +</para> +<para> +Here is an example of naming a delayed constant: +<programlisting> +<![CDATA[constant_type<char>::type space(constant(' ')); +for_each(a.begin(),a.end(), cout << space << _1);]]> +</programlisting> +</para> + +</simplesect> + +<simplesect> +<title>About assignment and subscript operators</title> + +<para> +As described in <xref linkend="lambda.assignment_and_subscript"/>, assignment and subscripting operators are always defined as member functions. +This means, that for expressions of the form +<literal>x = y</literal> or <literal>x[y]</literal> to be interpreted as lambda expressions, the left-hand operand <literal>x</literal> must be a lambda expression. +Consequently, it is sometimes necessary to use <literal>var</literal> for this purpose. +We repeat the example from <xref linkend="lambda.assignment_and_subscript"/>: + +<programlisting> +int i; +i = _1; // error +var(i) = _1; // ok +</programlisting> +</para> + +<para> + +Note that the compound assignment operators <literal>+=</literal>, <literal>-=</literal> 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, <literal>i += _1</literal> is equivalent to <literal>var(i) += _1</literal>. +</para> +</simplesect> + +</section> + +<section id="lambda.lambda_expressions_for_control_structures"> +<title>Lambda expressions for control structures</title> + +<para> +BLL defines several functions to create lambda functors that represent control structures. +They all take lambda functors as parameters and return <literal>void</literal>. +To start with an example, the following code outputs all even elements of some container <literal>a</literal>: + +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), + if_then(_1 % 2 == 0, cout << _1));]]> +</programlisting> +</para> + +<para> +The BLL supports the following function templates for control structures: + +<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(...) +</programlisting> + +The return types of all control construct lambda functor is +<literal>void</literal>, except for <literal>if_then_else_return</literal>, +which wraps a call to the conditional operator +<programlisting> +condition ? then_part : else_part +</programlisting> +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 +<literal>A</literal>, must be convertible to the other branch, +say of type <literal>B</literal>. +In this situation, the result type is <literal>B</literal>. +Further, if the common type is an lvalue, the return type will be an lvalue +too. +</para> + + +<para> +Delayed variables tend to be commonplace in control structure lambda expressions. +For instance, here we use the <literal>var</literal> function to turn the arguments of <literal>for_loop</literal> into lambda expressions. +The effect of the code is to add 1 to each element of a two-dimensional array: + +<programlisting> +<![CDATA[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));]]> +</programlisting> + +<!-- +As explained in <xref linkend="lambda.delaying_constants_and_variables"/>, we can avoid the repeated use of wrapping of <literal>var</literal> if we define it beforehand: + +<programlisting> +<![CDATA[int i; +var_type<int>::type vi(var(i)); +for_each(a, a+5, + for_loop(vi=0, vi<10, ++vi, _1[vi] += 6));]]> +</programlisting> + +--> +</para> + +<para> +The BLL supports an alternative syntax for control expressions, suggested +by Joel de Guzmann. +By overloading the <literal>operator[]</literal> we can +get a closer resemblance with the built-in control structures: + +<programlisting> +<![CDATA[if_(condition)[then_part] +if_(condition)[then_part].else_[else_part] +while_(condition)[body] +do_[body].while_(condition) +for_(init, condition, increment)[body]]]> +</programlisting> + +For example, using this syntax the <literal>if_then</literal> example above +can be written as: +<programlisting> +<![CDATA[for_each(a.begin(), a.end(), + if_(_1 % 2 == 0)[ cout << _1 ])]]> +</programlisting> + +As more experience is gained, we may end up deprecating one or the other +of these syntaces. + +</para> + + + +<section id="lambda.switch_statement"> +<title>Switch statement</title> +</section> + +<para> +The lambda expressions for <literal>switch</literal> control structures are more complex since the number of cases may vary. +The general form of a switch lambda expression is: + +<programlisting> +switch_statement(<parameter>condition</parameter>, + case_statement<<parameter>label</parameter>>(<parameter>lambda expression</parameter>), + case_statement<<parameter>label</parameter>>(<parameter>lambda expression</parameter>), + ... + default_statement(<parameter>lambda expression</parameter>) +) +</programlisting> + +The <literal><parameter>condition</parameter></literal> argument must be a lambda expression that creates a lambda functor with an integral return type. +The different cases are created with the <literal>case_statement</literal> functions, and the optional default case with the <literal>default_statement</literal> function. +The case labels are given as explicitly specified template arguments to <literal>case_statement</literal> functions and +<literal>break</literal> statements are implicitly part of each case. +For example, <literal><![CDATA[case_statement<1>(a)]]></literal>, where <literal>a</literal> is some lambda functor, generates the code: + +<programlisting> +case 1: + <parameter>evaluate lambda functor</parameter> a; + break; +</programlisting> +The <literal>switch_statement</literal> function is specialized for up to 9 case statements. + +</para> + +<para> +As a concrete example, the following code iterates over some container <literal>v</literal> and ouptuts <quote>zero</quote> for each <literal>0</literal>, <quote>one</quote> for each <literal>1</literal>, and <quote>other: <parameter>n</parameter></quote> for any other value <parameter>n</parameter>. +Note that another lambda expression is sequenced after the <literal>switch_statement</literal> to output a line break after each element: + +<programlisting> +<![CDATA[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") + ) +);]]> +</programlisting> +</para> + +</section> + +<section id="lambda.exceptions"> +<title>Exceptions</title> + +<para> +The BLL provides lambda functors that throw and catch exceptions. +Lambda functors for throwing exceptions are created with the unary function <literal>throw_exception</literal>. +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 <literal>rethrow</literal> function. +</para> + +<para> +Lambda expressions for handling exceptions are somewhat more complex. +The general form of a lambda expression for try catch blocks is as follows: + +<programlisting> +try_catch( + <parameter>lambda expression</parameter>, + catch_exception<<parameter>type</parameter>>(<parameter>lambda expression</parameter>), + catch_exception<<parameter>type</parameter>>(<parameter>lambda expression</parameter>), + ... + catch_all(<parameter>lambda expression</parameter>) +) +</programlisting> + +The first lambda expression is the try block. +Each <literal>catch_exception</literal> defines a catch block where the +explicitly specified template argument defines the type of the exception +to catch. + +The lambda expression within the <literal>catch_exception</literal> defines +the actions to take if the exception is caught. + +Note that the resulting exception handlers catch the exceptions as +references, i.e., <literal>catch_exception<T>(...)</literal> +results in the catch block: + +<programlisting> +catch(T& e) { ... } +</programlisting> + +The last catch block can alternatively be a call to +<literal>catch_exception<<parameter>type</parameter>></literal> +or to +<literal>catch_all</literal>, which is the lambda expression equivalent to +<literal>catch(...)</literal>. + +</para> + +<para> + +The <xref linkend="ex:exceptions"/> demonstrates the use of the BLL +exception handling tools. +The first handler catches exceptions of type <literal>foo_exception</literal>. +Note the use of <literal>_1</literal> placeholder in the body of the handler. +</para> + +<para> +The second handler shows how to throw exceptions, and demonstrates the +use of the <emphasis>exception placeholder</emphasis> <literal>_e</literal>. + +It is a special placeholder, which refers to the caught exception object +within the handler body. + +Here we are handling an exception of type <literal>std::exception</literal>, +which carries a string explaining the cause of the exception. + +This explanation can be queried with the zero-argument member +function <literal>what</literal>. + +The expression +<literal>bind(&std::exception::what, _e)</literal> creates the lambda +function for making that call. + +Note that <literal>_e</literal> cannot be used outside of an exception handler lambda expression. +<!--Violating this rule is caught by the compiler.--> + +The last line of the second handler constructs a new exception object and +throws that with <literal>throw exception</literal>. + +Constructing and destructing objects within lambda expressions is +explained in <xref linkend="lambda.construction_and_destruction"/> +</para> + +<para> +Finally, the third handler (<literal>catch_all</literal>) demonstrates +rethrowing exceptions. +</para> + +<example id="ex:exceptions"> +<title>Throwing and handling exceptions in lambda expressions.</title> +<programlisting> +<![CDATA[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()) + ) + ) +);]]> +</programlisting> +</example> + +</section> + +<section id="lambda.construction_and_destruction"> +<title>Construction and destruction</title> + + +<para> +Operators <literal>new</literal> and <literal>delete</literal> 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 +<literal>new</literal> and <literal>delete</literal> 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: + +<programlisting> +<![CDATA[int* a[10]; +for_each(a, a+10, _1 = bind(new_ptr<int>())); +for_each(a, a+10, bind(delete_ptr(), _1));]]> +</programlisting> + +The <literal>new_ptr<int>()</literal> expression creates +a function object that calls <literal>new int()</literal> when invoked, +and wrapping that inside <literal>bind</literal> makes it a lambda functor. + +In the same way, the expression <literal>delete_ptr()</literal> creates +a function object that invokes <literal>delete</literal> on its argument. + +Note that <literal>new_ptr<<parameter>T</parameter>>()</literal> +can take arguments as well. + +They are passed directly to the constructor invocation and thus allow +calls to constructors which take arguments. + +</para> + +<para> + +As an example of constructor calls in lambda expressions, +the following code reads integers from two containers <literal>x</literal> +and <literal>y</literal>, +constructs pairs out of them and inserts them into a third container: + +<programlisting> +<![CDATA[vector<pair<int, int> > v; +transform(x.begin(), x.end(), y.begin(), back_inserter(v), + bind(constructor<pair<int, int> >(), _1, _2));]]> +</programlisting> + +<xref linkend="table:constructor_destructor_fos"/> 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. + +</para> + + + +<table id="table:constructor_destructor_fos"> +<title>Construction and destruction related function objects.</title> +<tgroup cols="2"> +<thead> +<row> +<entry>Function object call</entry> +<entry>Wrapped expression</entry> +</row> +</thead> +<tbody> +<row> +<entry><literal>constructor<T>()(<parameter>arg_list</parameter>)</literal></entry> +<entry>T(<parameter>arg_list</parameter>)</entry> +</row> +<row> +<entry><literal>destructor()(a)</literal></entry> +<entry><literal>a.~A()</literal>, where <literal>a</literal> is of type <literal>A</literal></entry> +</row> +<row> +<entry><literal>destructor()(pa)</literal></entry> +<entry><literal>pa->~A()</literal>, where <literal>pa</literal> is of type <literal>A*</literal></entry> +</row> +<row> +<entry><literal>new_ptr<T>()(<parameter>arg_list</parameter>)</literal></entry> +<entry><literal>new T(<parameter>arg_list</parameter>)</literal></entry> +</row> +<row> +<entry><literal>new_array<T>()(sz)</literal></entry> +<entry><literal>new T[sz]</literal></entry> +</row> +<row> +<entry><literal>delete_ptr()(p)</literal></entry> +<entry><literal>delete p</literal></entry> +</row> +<row> +<entry><literal>delete_array()(p)</literal></entry> +<entry><literal>delete p[]</literal></entry> +</row> + + +</tbody> +</tgroup> +</table> + +</section> + + +<section> +<title>Special lambda expressions</title> + +<section> +<title>Preventing argument substitution</title> + +<para> +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. +</para> + + +<para> +The arguments to a bind expression can be arbitrary lambda expressions, +e.g., other bind expressions. + +For example: + +<programlisting> +int foo(int); int bar(int); +... +int i; +bind(foo, bind(bar, _1))(i); +</programlisting> + +The last line makes the call <literal>foo(bar(i));</literal> + +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: + +<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); +</programlisting> + +</para> + + + +<section id="lambda.unlambda"> +<title>Unlambda</title> + +<para>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. +</para> + +<para>Consider the following function template: + +<programlisting> +<![CDATA[template<class F> +int nested(const F& f) { + int x; + ... + bind(f, _1)(x); + ... +}]]> +</programlisting> + +Somewhere inside the function the formal parameter +<literal>f</literal> is used as a target function in a bind expression. + +In order for this <literal>bind</literal> call to be valid, +<literal>f</literal> must be a unary function. + +Suppose the following two calls to <literal>nested</literal> are made: + +<programlisting> +<![CDATA[int foo(int); +int bar(int, int); +nested(&foo); +nested(bind(bar, 1, _1));]]> +</programlisting> + +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 <literal>nested</literal> +will become: + +<programlisting> +bind(bind(bar, 1, _1), _1) +</programlisting> + +When this is invoked with <literal>x</literal>, +after substituitions we end up trying to call + +<programlisting> +bar(1, x)(x) +</programlisting> + +which is an error. + +The call to <literal>bar</literal> returns int, +not a unary function or function object. +</para> + +<para> +In the example above, the intent of the bind expression in the +<literal>nested</literal> function is to treat <literal>f</literal> +as an ordinary function object, instead of a lambda functor. + +The BLL provides the function template <literal>unlambda</literal> to +express this: a lambda functor wrapped inside <literal>unlambda</literal> +is not a lambda functor anymore, and does not take part into the +argument substitution process. + +Note that for all other argument types <literal>unlambda</literal> is +an identity operation, except for making non-const objects const. +</para> + +<para> +Using <literal>unlambda</literal>, the <literal>nested</literal> +function is written as: + +<programlisting> +<![CDATA[template<class F> +int nested(const F& f) { + int x; + ... + bind(unlambda(f), _1)(x); + ... +}]]> +</programlisting> + +</para> + +</section> + +<section> +<title>Protect</title> + +<para> +The <literal>protect</literal> function is related to unlambda. + +It is also used to prevent the argument substitution taking place, +but whereas <literal>unlambda</literal> turns a lambda functor into +an ordinary function object for good, <literal>protect</literal> does +this temporarily, for just one evaluation round. + +For example: + +<programlisting> +int x = 1, y = 10; +(_1 + protect(_1 + 2))(x)(y); +</programlisting> + +The first call substitutes <literal>x</literal> for the leftmost +<literal>_1</literal>, and results in another lambda functor +<literal>x + (_1 + 2)</literal>, which after the call with +<literal>y</literal> becomes <literal>x + (y + 2)</literal>, +and thus finally 13. +</para> + +<para> +Primary motivation for including <literal>protect</literal> into the library, +was to allow nested STL algorithm invocations +(<xref linkend="lambda.nested_stl_algorithms"/>). +</para> + +</section> + +</section> + +<section id="lambda.rvalues_as_actual_arguments"> +<title>Rvalues as actual arguments to lambda functors</title> + +<!-- <para><emphasis>This section and all of its subsections + are no longer (or currently) relevant; + acual arguments can be non-const rvalues and these workarounds are thus + not needed. + The section can, however, become relevant again, if in the future BLL will support + lambda functors with higher arities than 3.</emphasis></para> --> + +<para> +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 +<xref linkend="lambda.actual_arguments_to_lambda_functors"/> and list the +different solutions: + +<programlisting> +int i = 1; int j = 2; +(_1 + _2)(i, j); // ok +(_1 + _2)(1, 2); // error (!) +</programlisting> + +<orderedlist> +<listitem> +<para> +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. +</para> +</listitem> + +<listitem> +<para> +If the lambda function call is accessible, the <literal>make_const</literal> +function can be used to <emphasis>constify</emphasis> the rvalue. E.g.: + +<programlisting> +(_1 + _2)(make_const(1), make_const(2)); // ok +</programlisting> + +Commonly the lambda function call site is inside a standard algorithm +function template, preventing this solution to be used. + +</para> +</listitem> + +<listitem> +<para> +If neither of the above is possible, the lambda expression can be wrapped +in a <literal>const_parameters</literal> function. +It creates another type of lambda functor, which takes its arguments as +const references. For example: + +<programlisting> +const_parameters(_1 + _2)(1, 2); // ok +</programlisting> + +Note that <literal>const_parameters</literal> 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. +</para> + +</listitem> + +<listitem> +<para>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 +<literal>break_const</literal> to alert the user of the potential dangers +of this function. + +The <literal>break_const</literal> 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: +<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 +</programlisting> + +Note, that the results of <literal> break_const</literal> or +<literal>const_parameters</literal> are not lambda functors, +so they cannot be used as subexpressions of lambda expressions. For instance: + +<programlisting> +break_const(_1 + _2) + _3; // fails. +const_parameters(_1 + _2) + _3; // fails. +</programlisting> + +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. +</para> +</listitem> + +</orderedlist> + +</para> +</section> + +</section> + + +<section> +<title>Casts, sizeof and typeid</title> + +<section id="lambda.cast_expressions"> +<title> +Cast expressions +</title> +<para> +The BLL defines its counterparts for the four cast expressions +<literal>static_cast</literal>, <literal>dynamic_cast</literal>, +<literal>const_cast</literal> and <literal>reinterpret_cast</literal>. + +The BLL versions of the cast expressions have the prefix +<literal>ll_</literal>. + +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 <literal>ll_dynamic_cast</literal> +to count the number of <literal>derived</literal> instances in the container +<literal>a</literal>: + +<programlisting> +<![CDATA[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)));]]> +</programlisting> +</para> +</section> + +<section> +<title>Sizeof and typeid</title> +<para> +The BLL counterparts for these expressions are named +<literal>ll_sizeof</literal> and <literal>ll_typeid</literal>. + +Both take one argument, which can be a lambda expression. +The lambda functor created wraps the <literal>sizeof</literal> or +<literal>typeid</literal> call, and when the lambda functor is called +the wrapped operation is performed. + +For example: + +<programlisting> +<![CDATA[vector<base*> a; +... +for_each(a.begin(), a.end(), + cout << bind(&type_info::name, ll_typeid(*_1)));]]> +</programlisting> + +Here <literal>ll_typeid</literal> creates a lambda functor for +calling <literal>typeid</literal> for each element. + +The result of a <literal>typeid</literal> call is an instance of +the <literal>type_info</literal> class, and the bind expression creates +a lambda functor for calling the <literal>name</literal> member +function of that class. + +</para> +</section> + + + +</section> + +<section id="lambda.nested_stl_algorithms"> +<title>Nesting STL algorithm invocations</title> + +<para> +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. + +<programlisting> +int a[100][200]; +int sum = 0; + +std::for_each(a, a + 100, + bind(ll::for_each(), _1, _1 + 200, protect(sum += _1))); +</programlisting> + +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 <literal>std</literal> namespace. +All these structs are placed in the subnamespace <literal>boost::lambda:ll</literal>. +<!--The supported algorithms are listed in <xref linkend="table:nested_algorithms"/>.--> +</para> + +<para> +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 <literal>begin</literal> function has more than one overloaded +definitions in container templates. + +In general, something analogous to the pseudo-code below cannot be written: + +<programlisting> +std::for_each(a.begin(), a.end(), + bind(ll::for_each(), _1.begin(), _1.end(), protect(sum += _1))); +</programlisting> + +Some aid for common special cases can be provided though. + +The BLL defines two helper function object classes, +<literal>call_begin</literal> and <literal>call_end</literal>, +which wrap a call to the <literal>begin</literal> and, respectively, +<literal>end</literal> functions of a container, and return the +<literal>const_iterator</literal> type of the container. + +With these helper templates, the above code becomes: +<programlisting> +std::for_each(a.begin(), a.end(), + bind(ll::for_each(), + bind(call_begin(), _1), bind(call_end(), _1), + protect(sum += _1))); +</programlisting> + +</para> + +<!-- +<table id="table:nested_algorithms"> +<title>The nested STL algorithms.</title> +<tgroup cols="1"> +<thead> +<trow><entry>Otsikko</entry></trow> +</thead> +<tbody> +<row><entry><literal>for_each</literal></entry></row> +<row><entry><literal>find</literal></entry></row> +<row><entry><literal>find_if</literal></entry></row> +<row><entry><literal>find_end</literal></entry></row> +<row><entry><literal>find_first_of</literal></entry></row> +<row><entry><literal>transform</literal></entry></row> +</tbody> +</tgroup> + +</table> + +--> + +</section> + + +</section> + + +<!-- +<section> +<title>Common gothcas</title> + +calling member functions a.begin() + +calling templated functions ... + +</section> + +--> + +<section id="lambda.extending"> +<title>Extending return type deduction system</title> + +<para> +<!--The <xref linkend = "lambda.overriding_deduced_return_type"/> showed how to make BLL aware of the return type of a function object in bind expressions.--> + +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 +<literal>bool</literal>, 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. + +</para> + +<para> +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 + +<literal> +<![CDATA[plain_return_type_1<Action, A>]]> +</literal> + +and + +<literal> +<![CDATA[return_type_1<Action, A>]]> +</literal>, and + +<literal> +<![CDATA[plain_return_type_2<Action, A, B>]]> +</literal> + +and + +<literal> +<![CDATA[return_type_2<Action, A, B>]]> +</literal> + +respectively for binary functors. + +</para> + +<para> +The first parameter (<literal>Action</literal>) to all these templates +is the <emphasis>action</emphasis> class, which specifies the operator. + +Operators with similar return type rules are grouped together into +<emphasis>action groups</emphasis>, +and only the action class and action group together define the operator +unambiguously. + +As an example, the action type +<literal><![CDATA[arithmetic_action<plus_action>]]></literal> stands for +<literal>operator+</literal>. + +The complete listing of different action types is shown in +<xref linkend="table:actions"/>. +</para> + +<para> +The latter parameters, <literal>A</literal> in the unary case, +or <literal>A</literal> and <literal>B</literal> in the binary case, +stand for the argument types of the operator call. + +The two sets of templates, +<literal>plain_return_type_<parameter>n</parameter></literal> and +<literal>return_type_<parameter>n</parameter></literal> +(<parameter>n</parameter> 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 <literal>return_type_2</literal> specializations. +</para> + +<para> +Suppose the user has overloaded the following operators for some user defined +types <literal>X</literal>, <literal>Y</literal> and <literal>Z</literal>: + +<programlisting> +<![CDATA[Z operator+(const X&, const Y&); +Z operator-(const X&, const Y&);]]> +</programlisting> + +Now, one can add a specialization stating, that if the left hand argument +is of type <literal>X</literal>, and the right hand one of type +<literal>Y</literal>, the return type of all such binary arithmetic +operators is <literal>Z</literal>: + +<programlisting> +<![CDATA[namespace boost { +namespace lambda { + +template<class Act> +struct plain_return_type_2<arithmetic_action<Act>, X, Y> { + typedef Z type; +}; + +} +}]]> +</programlisting> + +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, +<literal>::boost::lambda</literal>, with the primary template. + +For brevity, we do not show the namespace definitions in the examples below. +</para> + +<para> +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 <literal>X</literal> +and <literal>Y</literal>: + +<programlisting> +<![CDATA[X operator*(const X&, const Y&);]]> +</programlisting> + +Our first rule for all arithmetic operators specifies that the return +type of this operator is <literal>Z</literal>, +which obviously is not the case. +Hence, we provide a new rule for the multiplication operator: + +<programlisting> +<![CDATA[template<> +struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> { + typedef X type; +};]]> +</programlisting> +</para> + +<para> +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: + +<programlisting> +<![CDATA[template <class T> class my_vector;]]> +</programlisting> + +Suppose the addition operator is defined between any two +<literal>my_vector</literal> instantiations, +as long as the addition operator is defined between their element types. + +Furthermore, the element type of the resulting <literal>my_vector</literal> +is the same as the result type of the addition between the element types. + +E.g., adding <literal><![CDATA[my_vector<int>]]></literal> and +<literal><![CDATA[my_vector<double>]]></literal> results in +<literal><![CDATA[my_vector<double>]]></literal>. + +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: + +<programlisting> +<![CDATA[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>(); +}]]> +</programlisting> +</para> + +<para> +To allow BLL to deduce the type of <literal>my_vector</literal> +additions correctly, we can define: + +<programlisting> +<![CDATA[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; +};]]> +</programlisting> +Note, that we are reusing the existing specializations for the +BLL <literal>return_type_2</literal> template, +which require that the argument types are references. +</para> + +<!-- TODO: is an example of specifying the other level needed at all --> +<!-- TODO: comma operator is a special case for that --> + +<table id = "table:actions"> +<title>Action types</title> +<tgroup cols="2"> +<tbody> + +<row><entry><literal><![CDATA[+]]></literal></entry><entry><literal><![CDATA[arithmetic_action<plus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[-]]></literal></entry><entry><literal><![CDATA[arithmetic_action<minus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[*]]></literal></entry><entry><literal><![CDATA[arithmetic_action<multiply_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[/]]></literal></entry><entry><literal><![CDATA[arithmetic_action<divide_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[%]]></literal></entry><entry><literal><![CDATA[arithmetic_action<remainder_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[+]]></literal></entry><entry><literal><![CDATA[unary_arithmetic_action<plus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[-]]></literal></entry><entry><literal><![CDATA[unary_arithmetic_action<minus_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&]]></literal></entry><entry><literal><![CDATA[bitwise_action<and_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[|]]></literal></entry><entry><literal><![CDATA[bitwise_action<or_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[~]]></literal></entry><entry><literal><![CDATA[bitwise_action<not_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[^]]></literal></entry><entry><literal><![CDATA[bitwise_action<xor_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[<<]]></literal></entry><entry><literal><![CDATA[bitwise_action<leftshift_action_no_stream>]]></literal></entry></row> +<row><entry><literal><![CDATA[>>]]></literal></entry><entry><literal><![CDATA[bitwise_action<rightshift_action_no_stream>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&&]]></literal></entry><entry><literal><![CDATA[logical_action<and_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[||]]></literal></entry><entry><literal><![CDATA[logical_action<or_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[!]]></literal></entry><entry><literal><![CDATA[logical_action<not_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[<]]></literal></entry><entry><literal><![CDATA[relational_action<less_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[>]]></literal></entry><entry><literal><![CDATA[relational_action<greater_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[<=]]></literal></entry><entry><literal><![CDATA[relational_action<lessorequal_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[>=]]></literal></entry><entry><literal><![CDATA[relational_action<greaterorequal_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[==]]></literal></entry><entry><literal><![CDATA[relational_action<equal_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[!=]]></literal></entry><entry><literal><![CDATA[relational_action<notequal_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[+=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<plus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[-=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<minus_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[*=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<multiply_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[/=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<divide_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[%=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<remainder_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<and_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[=|]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<or_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[^=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<xor_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[<<=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<leftshift_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[>>=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<rightshift_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[++]]></literal></entry><entry><literal><![CDATA[pre_increment_decrement_action<increment_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[--]]></literal></entry><entry><literal><![CDATA[pre_increment_decrement_action<decrement_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[++]]></literal></entry><entry><literal><![CDATA[post_increment_decrement_action<increment_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[--]]></literal></entry><entry><literal><![CDATA[post_increment_decrement_action<decrement_action>]]></literal></entry></row> + + + +<row><entry><literal><![CDATA[&]]></literal></entry><entry><literal><![CDATA[other_action<address_of_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[*]]></literal></entry><entry><literal><![CDATA[other_action<contents_of_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[,]]></literal></entry><entry><literal><![CDATA[other_action<comma_action>]]></literal></entry></row> +<row><entry><literal><![CDATA[->*]]></literal></entry><entry><literal><![CDATA[other_action<member_pointer_action>]]></literal></entry></row> + +</tbody> +</tgroup> +</table> + +</section> + + +<section> +<title>Practical considerations</title> + + +<section> +<title>Performance</title> + +<para>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. +</para> + +<para> +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<superscript>5</superscript>. +The expressions were called inside a <literal>std::transform</literal> loop, +reading the argument from one <literal><![CDATA[std::vector<int>]]></literal> +and placing the result into another. +The length of the vectors was 100 elements. +The running times are listed in +<xref linkend="table:increasing_arithmetic_test"/>. + +We can observe that there is no significant difference between the +two approaches. +</para> + +<para> +In the second test we again used <literal>std::transform</literal> to +perform an operation to each element in a 100-element long vector. +This time the element type of the vectors was <literal>double</literal> +and we started with very simple arithmetic expressions and moved to +more complex ones. +The running times are listed in <xref linkend="table:ll_vs_stl_test"/>. + +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 <xref linkend="table:ll_vs_stl_test"/> written with +classic STL tools contains 7 calls to <literal>compose2</literal>, +8 calls to <literal>bind1st</literal> +and altogether 14 constructor invocations for creating +<literal>multiplies</literal>, <literal>minus</literal> +and <literal>plus</literal> 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. +</para> + +<para> +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. + +<!-- We repeated both tests with the KAI C++ 4.0f compiler (using +K2 -O3 flags), +generally considered a good optimizing compiler. +We do not list the results here, since the running times for the two alternatives in the first test were essentially the same, just as the running times +for the three different alternatives in the second test. +These tests suggest there to be no performance penalty at all +with a good optimizing compiler. +--> + +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 experienced +this for some seemingly simple expressions. + + +<table id = "table:increasing_arithmetic_test"> +<title>Test 1</title> +<caption>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.</caption> +<tgroup cols="3"> +<thead> +<row> +<entry>expression</entry><entry>lambda expression</entry><entry>hand-coded function object</entry></row> +</thead> + +<tbody> + +<row> +<entry>x</entry><entry>240</entry><entry>230</entry> +</row> + +<row> +<entry>x*x</entry><entry>340</entry><entry>350</entry> +</row> + +<row> +<entry>x*x*x</entry><entry>770</entry><entry>760</entry> +</row> + +<row> +<entry>x*x*x*x</entry><entry>1180</entry><entry>1210</entry> +</row> + +<row> +<entry>x*x*x*x*x</entry><entry>1950</entry><entry>1910</entry> +</row> + +</tbody> +</tgroup> +</table> +</para> + +<!-- +16:19:49 bench [601] ./arith.out 100 1000000 + +Number of elements = 100 +L1 : 240 +L2 : 340 +L3 : 770 +L4 : 1180 +L5 : 1950 + +P2 : 1700 +P3 : 2130 +P4 : 2530 +P5 : 3000 + +F1 : 230 +F2 : 350 +F3 : 760 +F4 : 1210 +F5 : 1910 + + +Number of elements = 100 +Number of outer_iters = 1000000 +L1 : 330 +L2 : 350 +L3 : 470 +L4 : 620 +L5 : 1660 +LP : 1230 +C1 : 370 +C2 : 370 +C3 : 500 +C4 : 670 +C5 : 1660 +CP : 1770 +F1 : 290 +F2 : 310 +F3 : 420 +F4 : 600 +F5 : 1460 +FP : 1040 + +--> + + +<para> +<table id = "table:ll_vs_stl_test"> +<title>Test 2</title> +<caption>CPU time of arithmetic expressions written as lambda +expressions, as classic STL unnamed functions (using <literal>compose2</literal>, <literal>bind1st</literal> etc.) and as traditional hand-coded function object classes. +Using BLL terminology, +<literal>a</literal> and <literal>b</literal> are bound arguments in the expressions, and <literal>x</literal> is open. +All variables were of types <literal>double</literal>. +The running times are expressed in arbitrary units.</caption> +<tgroup cols="4"> +<thead> +<row> +<entry>expression</entry><entry>lambda expression</entry><entry>classic STL expression</entry><entry>hand-coded function object</entry></row> +</thead> + +<tbody> + +<row> +<entry>ax</entry><entry>330</entry><entry>370</entry><entry>290</entry> +</row> + +<row> +<entry>-ax</entry><entry>350</entry><entry>370</entry><entry>310</entry> +</row> + +<row> +<entry>ax-(a+x)</entry><entry>470</entry><entry>500</entry><entry>420</entry> +</row> + +<row> +<entry>(ax-(a+x))(a+x)</entry><entry>620</entry><entry>670</entry><entry>600</entry> +</row> + +<row> +<entry>((ax) - (a+x))(bx - (b+x))(ax - (b+x))(bx - (a+x))</entry><entry>1660</entry><entry>1660</entry><entry>1460</entry> +</row> + +</tbody> +</tgroup> + +</table> +</para> + + +<para>Some additional performance testing with an earlier version of the +library is described +<xref linkend="cit:jarvi:00"/>. +</para> + +</section> + <section> + <title>About compiling</title> + + <para>The BLL uses templates rather heavily, performing numerous recursive instantiations of the same templates. +This has (at least) three implications: +<itemizedlist> + +<listitem> +<para> +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. +</para> +</listitem> + + +<listitem> +<para> +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 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. +</para> +</listitem> + +<listitem> +<para> +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. +</para> +</listitem> +</itemizedlist></para> + + </section> + + <section> + <title>Portability</title> + <para> +The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL: + + <itemizedlist> + <listitem>GCC 3.0.4 + </listitem> + <listitem>KCC 4.0f with EDG 2.43.1 + </listitem> + <listitem>GCC 2.96 (fails with one test case, the <filename>exception_test.cpp</filename> results in an internal compiler error. +) + + </listitem> + </itemizedlist> +</para> + + <section> + <title>Test coverage</title> + +<para>The following list describes the test files included and the features that each file covers: + +<itemizedlist> +<listitem> +<para> +<filename>bind_tests_simple.cpp</filename> : Bind expressions of different arities and types of target functions: function pointers, function objects and member functions. +Function composition with bind expressions.</para> +</listitem> + +<listitem> +<para><filename>bind_tests_simple_function_references.cpp</filename> : +Repeats all tests from <filename moreinfo="none">bind_tests_simple.cpp</filename> where the target function is a function pointer, but uses function references instead. +</para></listitem> + + +<listitem> +<para><filename>bind_tests_advanced.cpp</filename> : Contains tests for nested bind expressions, <literal>unlambda</literal>, <literal>protect</literal>, <literal>const_parameters</literal> and <literal>break_const</literal>. +Tests passing lambda functors as actual arguments to other lambda functors, currying, and using the <literal>sig</literal> template to specify the return type of a function object. +</para> +</listitem> + +<listitem> +<para> +<filename>operator_tests_simple.cpp</filename> : +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. +</para> +</listitem> + +<listitem> +<para><filename>member_pointer_test.cpp</filename> : The pointer to member operator is complex enough to warrant a separate test file. +</para> +</listitem> + +<listitem> +<para> +<filename>control_structures.cpp</filename> : +Tests for the looping and if constructs. +</para></listitem> + +<listitem> +<para> +<filename>switch_construct.cpp</filename> : +Includes tests for all supported arities of the switch statement, both with and without the default case. +</para> +</listitem> + +<listitem> +<para> +<filename>exception_test.cpp</filename> : +Includes tests for throwing exceptions and for try/catch constructs with varying number of catch blocks. +</para> +</listitem> + +<listitem> +<para> +<filename>constructor_tests.cpp</filename> : +Contains tests for <literal>constructor</literal>, <literal>destructor</literal>, <literal>new_ptr</literal>, <literal>delete_ptr</literal>, <literal>new_array</literal> and <literal>delete_array</literal>. +</para> +</listitem> + +<listitem> +<para> +<filename>cast_test.cpp</filename> : Tests for the four cast expressions, as well as <filename>typeid</filename> and <literal>sizeof</literal>. +</para> +</listitem> + +<listitem> +<para> +<filename>extending_return_type_traits.cpp</filename> : 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. +</para> +</listitem> + +<listitem> +<para> +<filename>is_instance_of_test.cpp</filename> : Includes tests for an internally used traits template, which can detect whether a given type is an instance of a certain template or not. +</para></listitem> + +<listitem> +<para> +<filename>bll_and_function.cpp</filename> : +Contains tests for using <literal>boost::function</literal> together with lambda functors. +</para></listitem> + + </itemizedlist> + +</para> + + </section> + + </section> + + +</section> + + +<section> +<title>Relation to other Boost libraries</title> + +<section> +<title>Boost Function</title> + +<para>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. +<emphasis>The Boost Function library</emphasis> <xref linkend="cit:boost::function"/> defines wrappers for arbitrary function objects, for example +lambda functors; and these wrappers have types that are easy to type out. + +For example: + +<programlisting> +<![CDATA[boost::function<int(int, int)> f = _1 + _2; +boost::function<int&(int&)> g = (_1 += 10); +int i = 1, j = 2; +f(i, j); // returns 3 +g(i); // sets i to = 11;]]> +</programlisting> + +The return and parameter types of the wrapped function object must be written explicilty as the template argument to the wrapper template <literal>boost::function</literal>; even when lambda functors, which otherwise have generic parameters, are wrapped. +Wrapping a function object with <literal>boost::function</literal> introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used. + +Note that storing lambda functors inside <literal>boost::function</literal> +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 <literal>boost::function</literal> +may continue to exist longer, creating the possibility of dangling references. +For example: + +<programlisting> +<![CDATA[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]]> +</programlisting> + +</para> + +</section> + +<section> +<title>Boost Bind</title> +<para> +<emphasis>The Boost Bind</emphasis> <xref linkend="cit:boost::bind"/> 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. +</para> +<para> +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 <literal>boost</literal> namespace, +whereas the BLL names are in <literal>boost::lambda</literal> namespace. +</para> + +<para> +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. +</para> + +<para> +The following two sections describe what are the semantic differences +between the bind expressions in BB and BLL. +</para> + + + + +<section> +<title>First argument of bind expression</title> + +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: + +<programlisting> +<![CDATA[template<class F> +int foo(const F& f) { + int x; + .. + bind(f, _1)(x); + ... +}]]> +</programlisting> + +<programlisting> +<![CDATA[int bar(int, int); +nested(bind(bar, 1, _1));]]> +</programlisting> + +The bind expression inside <literal>foo</literal> becomes: +<programlisting> +bind(bind(bar, 1, _1), _1)(x) +</programlisting> + +The BLL interpretes this as: +<programlisting> +bar(1, x)(x) +</programlisting> +whereas the BB library as +<programlisting> +bar(1, x) +</programlisting> + +To get this functionality in BLL, the bind expression inside the <literal moreinfo="none">foo</literal> function can be written as: +<programlisting> +bind(unlambda(f), _1)(x); +</programlisting> +as explained in <xref linkend = "lambda.unlambda"/>. + +</section> + + + + +<para> +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. +</para> + +</section> + + </section> + + +<section> +<title>Contributors</title> + +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. + +</section> + + + +<section> +<title>Rationale for some of the design decisions</title> + +<section id="lambda.why_weak_arity"> +<title> +Lambda functor arity +</title> + +<para> +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: + +<programlisting> +bind(g, _3, _3, _3)(x, y, z); +bind(g, _1, _1, _1)(x, y, z); +</programlisting> + +This first line discards arguments <literal>x</literal> and +<literal>y</literal>, and makes the call: +<programlisting> +g(z, z, z) +</programlisting> +whereas the second line discards arguments <literal>y</literal> and +<literal>z</literal>, and calls: +<programlisting> +g(x, x, x) +</programlisting> +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 <emphasis>strict arity</emphasis> 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: +<programlisting> +(_3, bind(g, _1, _1, _1))(x, y, z); +</programlisting> +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 +<literal>g(x, x, x)</literal> +even with the strict arity. +</para> + +<para> +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 +<literal>_1 + _2</literal> but mistakenly wrote <literal>_1 + 2</literal>, +with strict arity checking, the complier would spot the error. +However, if the erroneous expression was <literal>1 + _2</literal> 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. +</para> + +</section> + +</section> + + + +<bibliography> + +<biblioentry id="cit:stepanov:94"> +<abbrev>STL94</abbrev> +<authorgroup> +<author> +<surname>Stepanov</surname> +<firstname>A. A.</firstname> +</author> +<author> +<surname>Lee</surname> +<firstname>M.</firstname> +</author> +</authorgroup> +<title>The Standard Template Library</title> +<orgname>Hewlett-Packard Laboratories</orgname> +<pubdate>1994</pubdate> +<bibliomisc> +<ulink url="http://www.hpl.hp.com/techreports">www.hpl.hp.com/techreports</ulink> +</bibliomisc> +</biblioentry> + +<biblioentry id="cit:sgi:02"> +<abbrev>SGI02</abbrev> +<title>The SGI Standard Template Library</title> +<pubdate>2002</pubdate> +<bibliomisc><ulink url="http://www.sgi.com/tech/stl/">www.sgi.com/tech/stl/</ulink></bibliomisc> + +</biblioentry> + +<biblioentry id="cit:c++:98"> +<abbrev>C++98</abbrev> +<title>International Standard, Programming Languages – C++</title> +<subtitle>ISO/IEC:14882</subtitle> +<pubdate>1998</pubdate> +</biblioentry> + + +<biblioentry id="cit:jarvi:99"> +<abbrev>Jär99</abbrev> + +<articleinfo> +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> +<title>C++ Function Object Binders Made Easy</title> +</articleinfo> + +<title>Lecture Notes in Computer Science</title> +<volumenum>1977</volumenum> +<publishername>Springer</publishername> + +<pubdate>2000</pubdate> +</biblioentry> + + + +<biblioentry id="cit:jarvi:00"> +<abbrev>Jär00</abbrev> +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> +<author> +<firstname>Gary</firstname> +<surname>Powell</surname> +</author> +<title>The Lambda Library : Lambda Abstraction in C++</title> + <orgname>Turku Centre for Computer Science</orgname> +<bibliomisc>Technical Report </bibliomisc> + <issuenum>378</issuenum> +<pubdate>2000</pubdate> +<bibliomisc><ulink url="http://www.tucs.fi/Publications/techreports/TR378.php">www.tucs.fi/publications</ulink></bibliomisc> + + +</biblioentry> + + +<biblioentry id="cit:jarvi:01"> +<abbrev>Jär01</abbrev> +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> +<author> +<firstname>Gary</firstname> +<surname>Powell</surname> +</author> +<title>The Lambda Library : Lambda Abstraction in C++</title> + <confgroup> + <conftitle>Second Workshop on C++ Template Programming</conftitle> + <address>Tampa Bay, OOPSLA'01</address> + </confgroup> +<pubdate>2001</pubdate> +<bibliomisc><ulink url="http://www.oonumerics.org/tmpw01/">www.oonumerics.org/tmpw01/</ulink></bibliomisc> +</biblioentry> + +<biblioentry id="cit:jarvi:03"> +<abbrev>Jär03</abbrev> + +<articleinfo> + +<author> +<surname>Järvi</surname> +<firstname>Jaakko</firstname> +</author> + +<author> +<firstname>Gary</firstname> +<surname>Powell</surname> +</author> + +<author> +<firstname>Andrew</firstname> +<surname>Lumsdaine</surname> +</author> +<title>The Lambda Library : unnamed functions in C++</title> + +</articleinfo> + +<title>Software - Practice and Expreience</title> +<volumenum>33:259-291</volumenum> + + +<pubdate>2003</pubdate> +</biblioentry> + + +<biblioentry id="cit:boost::tuple"> +<abbrev>tuple</abbrev> +<title>The Boost Tuple Library</title> +<bibliomisc><ulink url="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">www.boost.org/libs/tuple/doc/tuple_users_guide.html</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::type_traits"> +<abbrev>type_traits</abbrev> +<title>The Boost type_traits</title> +<bibliomisc><ulink url="http://www.boost.org/libs/type_traits/index.htm">www.boost.org/libs/type_traits/</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::ref"> +<abbrev>ref</abbrev> +<title>Boost ref</title> +<bibliomisc><ulink url="http://www.boost.org/libs/bind/ref.html">www.boost.org/libs/bind/ref.html</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::bind"> +<abbrev>bind</abbrev> +<title>Boost Bind Library</title> +<bibliomisc><ulink url="http://www.boost.org/libs/bind/bind.html">www.boost.org/libs/bind/bind.html</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:boost::function"> +<abbrev>function</abbrev> +<title>Boost Function Library</title> +<bibliomisc><ulink url="http://www.boost.org/libs/function/">www.boost.org/libs/function/</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + +<biblioentry id="cit:fc++"> +<abbrev>fc++</abbrev> +<title>The FC++ library: Functional Programming in C++</title> +<author> +<surname>Smaragdakis</surname> +<firstname>Yannis</firstname> +</author> +<author> +<firstname>Brian</firstname> +<surname>McNamara</surname> +</author> +<bibliomisc><ulink url="http://www.cc.gatech.edu/~yannis/fc++/">www.cc.gatech.edu/~yannis/fc++/</ulink> +</bibliomisc> +<pubdate>2002</pubdate> +</biblioentry> + + +</bibliography> + + +</library> diff --git a/libs/lambda/index.html b/libs/lambda/index.html new file mode 100644 index 000000000..788ea5cba --- /dev/null +++ b/libs/lambda/index.html @@ -0,0 +1,12 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; URL=../../doc/html/lambda.html"> +</head> +<body> +Automatic redirection failed, please go to <a href="../../doc/html/lambda.html">www.boost.org/doc/html/lambda.html</a> <hr> +<p>© Copyright Beman Dawes, 2001</p> +<p>Distributed under the Boost Software License, Version 1.0. (See accompanying +file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy +at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p> +</body> +</html>
\ No newline at end of file diff --git a/libs/lambda/test/Jamfile b/libs/lambda/test/Jamfile new file mode 100644 index 000000000..7e1a5a7e2 --- /dev/null +++ b/libs/lambda/test/Jamfile @@ -0,0 +1,35 @@ +# Lambda library + +# Copyright (C) 2001-2003 Jaakko Järvi + +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +# For more information, see http://www.boost.org/ + +import testing ; + +project + : requirements <toolset>msvc:<asynch-exceptions>on + ; + +test-suite lambda + : [ run algorithm_test.cpp ] + [ run bind_tests_simple.cpp ] + [ run bind_tests_advanced.cpp ] + [ run bind_tests_simple_f_refs.cpp ] + [ run bll_and_function.cpp ] + [ run cast_test.cpp : : : : lambda_cast_test ] + [ run constructor_tests.cpp ] + [ run control_structures.cpp ] + [ run exception_test.cpp ] + [ run extending_rt_traits.cpp ] + [ run is_instance_of_test.cpp ] + [ run member_pointer_test.cpp ] + [ run operator_tests_simple.cpp ] + [ run phoenix_control_structures.cpp ] + [ run switch_construct.cpp ] + [ run result_of_tests.cpp ] + [ run ret_test.cpp ] + ; diff --git a/libs/lambda/test/Makefile b/libs/lambda/test/Makefile new file mode 100644 index 000000000..f25b5e4ff --- /dev/null +++ b/libs/lambda/test/Makefile @@ -0,0 +1,89 @@ +BOOST = ../../.. + +CXX = g++ +EXTRAFLAGS = -pedantic -Wno-long-long -Wno-long-double -ftemplate-depth-50 +LIBS = -lstdc++ + +#CXX = KCC +#EXTRAFLAGS = --strict --display_error_number --diag_suppress 450 --max_pending_instantiations 50 +#LIBS = + +INCLUDES = -I$(BOOST) + + + +CXXFLAGS = $(INCLUDES) $(EXTRAFLAGS) + +LIBFLAGS = $(LIBS) + + +AR = ar + +.SUFFIXES: .cpp .o + +SOURCES = \ +is_instance_of_test.cpp \ +operator_tests_simple.cpp \ +member_pointer_test.cpp \ +control_structures.cpp \ +switch_construct.cpp \ +bind_tests_simple.cpp \ +bind_tests_advanced.cpp \ +bll_and_function.cpp \ +constructor_tests.cpp \ +extending_rt_traits.cpp \ +bind_tests_simple_f_refs.cpp \ +cast_test.cpp \ +phoenix_control_structures.cpp \ +exception_test.cpp \ + + +# Create lists of object files from the source file lists. + +OBJECTS = ${SOURCES:.cpp=.o} + +TARGETS = ${SOURCES:.cpp=.exe} + +all: $(TARGETS) + +%.exe: %.o + $(CXX) $(LIBFLAGS) $(CXXFLAGS) -o $@ $< + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + +%.dep: %.cpp + set -e; $(CXX) -M $(INCLUDES) -c $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +DEP_FILES = $(SOURCES:.cpp=.dep) + +include $(DEP_FILES) + +clean: + /bin/rm -rf $(TARGETS) $(OBJECTS) $(DEP_FILES) + +run: + ./is_instance_of_test.exe + ./member_pointer_test.exe + ./operator_tests_simple.exe + ./control_structures.exe + ./switch_construct.exe + ./extending_rt_traits.exe + ./constructor_tests.exe + ./cast_test.exe + ./bind_tests_simple.exe + ./bind_tests_advanced.exe + ./bll_and_function.exe + ./bind_tests_simple_f_refs.exe + ./phoenix_control_structures.exe + ./exception_test.exe + + + + + + + + diff --git a/libs/lambda/test/README_gcc2.9x_users b/libs/lambda/test/README_gcc2.9x_users new file mode 100644 index 000000000..5ecec2e51 --- /dev/null +++ b/libs/lambda/test/README_gcc2.9x_users @@ -0,0 +1,6 @@ +gcc 2.96 +cannot compile + +exception_test.cpp (internal compiler error) + + diff --git a/libs/lambda/test/algorithm_test.cpp b/libs/lambda/test/algorithm_test.cpp new file mode 100644 index 000000000..079b771d2 --- /dev/null +++ b/libs/lambda/test/algorithm_test.cpp @@ -0,0 +1,60 @@ +// bll_and_function.cpp - The Boost Lambda Library ----------------------- +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// test using BLL and boost::function + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/bind.hpp" +#include "boost/lambda/algorithm.hpp" + +#include <vector> +#include <map> +#include <set> +#include <string> + +#include <iostream> + + + +void test_foreach() { + using namespace boost::lambda; + + int a[10][20]; + int sum = 0; + + std::for_each(a, a + 10, + bind(ll::for_each(), _1, _1 + 20, + protect((_1 = var(sum), ++var(sum))))); + + sum = 0; + std::for_each(a, a + 10, + bind(ll::for_each(), _1, _1 + 20, + protect((sum += _1)))); + + BOOST_CHECK(sum == (199 + 1)/ 2 * 199); +} + +// More tests needed (for all algorithms) + +int test_main(int, char *[]) { + + test_foreach(); + + return 0; +} + + + + + + diff --git a/libs/lambda/test/bind_tests_advanced.cpp b/libs/lambda/test/bind_tests_advanced.cpp new file mode 100644 index 000000000..d696e4999 --- /dev/null +++ b/libs/lambda/test/bind_tests_advanced.cpp @@ -0,0 +1,420 @@ +// bind_tests_advanced.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// Copyright (C) 2010 Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/bind.hpp" + + +#include "boost/any.hpp" +#include "boost/type_traits/is_reference.hpp" +#include "boost/mpl/assert.hpp" +#include "boost/mpl/if.hpp" + +#include <iostream> + +#include <functional> + +#include <algorithm> + + +using namespace boost::lambda; +namespace bl = boost::lambda; + +int sum_0() { return 0; } +int sum_1(int a) { return a; } +int sum_2(int a, int b) { return a+b; } + +int product_2(int a, int b) { return a*b; } + +// unary function that returns a pointer to a binary function +typedef int (*fptr_type)(int, int); +fptr_type sum_or_product(bool x) { + return x ? sum_2 : product_2; +} + +// a nullary functor that returns a pointer to a unary function that +// returns a pointer to a binary function. +struct which_one { + typedef fptr_type (*result_type)(bool x); + template <class T> struct sig { typedef result_type type; }; + + result_type operator()() const { return sum_or_product; } +}; + +void test_nested_binds() +{ + int j = 2; int k = 3; + +// bind calls can be nested (the target function can be a lambda functor) +// The interpretation is, that the innermost lambda functor returns something +// that is bindable (another lambda functor, function pointer ...) + bool condition; + + condition = true; + BOOST_CHECK(bind(bind(&sum_or_product, _1), 1, 2)(condition)==3); + BOOST_CHECK(bind(bind(&sum_or_product, _1), _2, _3)(condition, j, k)==5); + + condition = false; + BOOST_CHECK(bind(bind(&sum_or_product, _1), 1, 2)(condition)==2); + BOOST_CHECK(bind(bind(&sum_or_product, _1), _2, _3)(condition, j, k)==6); + + + which_one wo; + BOOST_CHECK(bind(bind(bind(wo), _1), _2, _3)(condition, j, k)==6); + + + return; +} + + +// unlambda ------------------------------------------------- + + // Sometimes it may be necessary to prevent the argument substitution of + // taking place. For example, we may end up with a nested bind expression + // inadvertently when using the target function is received as a parameter + +template<class F> +int call_with_100(const F& f) { + + + + // bind(f, _1)(make_const(100)); + // This would result in; + // bind(_1 + 1, _1)(make_const(100)) , which would be a compile time error + + return bl::bind(unlambda(f), _1)(make_const(100)); + + // for other functors than lambda functors, unlambda has no effect + // (except for making them const) +} + +template<class F> +int call_with_101(const F& f) { + + return bind(unlambda(f), _1)(make_const(101)); + +} + + +void test_unlambda() { + + int i = 1; + + BOOST_CHECK(unlambda(_1 + _2)(i, i) == 2); + BOOST_CHECK(unlambda(++var(i))() == 2); + BOOST_CHECK(call_with_100(_1 + 1) == 101); + + + BOOST_CHECK(call_with_101(_1 + 1) == 102); + + BOOST_CHECK(call_with_100(bl::bind(std_functor(std::bind1st(std::plus<int>(), 1)), _1)) == 101); + + // std_functor insturcts LL that the functor defines a result_type typedef + // rather than a sig template. + bl::bind(std_functor(std::plus<int>()), _1, _2)(i, i); +} + + + + +// protect ------------------------------------------------------------ + +// protect protects a lambda functor from argument substitution. +// protect is useful e.g. with nested stl algorithm calls. + +namespace ll { + +struct for_each { + + // note, std::for_each returns it's last argument + // We want the same behaviour from our ll::for_each. + // However, the functor can be called with any arguments, and + // the return type thus depends on the argument types. + + // 1. Provide a sig class member template: + + // The return type deduction system instantiate this class as: + // sig<Args>::type, where Args is a boost::tuples::cons-list + // The head type is the function object type itself + // cv-qualified (so it is possilbe to provide different return types + // for differently cv-qualified operator()'s. + + // The tail type is the list of the types of the actual arguments the + // function was called with. + // So sig should contain a typedef type, which defines a mapping from + // the operator() arguments to its return type. + // Note, that it is possible to provide different sigs for the same functor + // if the functor has several operator()'s, even if they have different + // number of arguments. + + // Note, that the argument types in Args are guaranteed to be non-reference + // types, but they can have cv-qualifiers. + + template <class Args> + struct sig { + typedef typename boost::remove_const< + typename boost::tuples::element<3, Args>::type + >::type type; + }; + + template <class A, class B, class C> + C + operator()(const A& a, const B& b, const C& c) const + { return std::for_each(a, b, c);} +}; + +} // end of ll namespace + +void test_protect() +{ + int i = 0; + int b[3][5]; + int* a[3]; + + for(int j=0; j<3; ++j) a[j] = b[j]; + + std::for_each(a, a+3, + bind(ll::for_each(), _1, _1 + 5, protect(_1 = ++var(i)))); + + // This is how you could output the values (it is uncommented, no output + // from a regression test file): + // std::for_each(a, a+3, + // bind(ll::for_each(), _1, _1 + 5, + // std::cout << constant("\nLine ") << (&_1 - a) << " : " + // << protect(_1) + // ) + // ); + + int sum = 0; + + std::for_each(a, a+3, + bind(ll::for_each(), _1, _1 + 5, + protect(sum += _1)) + ); + BOOST_CHECK(sum == (1+15)*15/2); + + sum = 0; + + std::for_each(a, a+3, + bind(ll::for_each(), _1, _1 + 5, + sum += 1 + protect(_1)) // add element count + ); + BOOST_CHECK(sum == (1+15)*15/2 + 15); + + (1 + protect(_1))(sum); + + int k = 0; + ((k += constant(1)) += protect(constant(2)))(); + BOOST_CHECK(k==1); + + k = 0; + ((k += constant(1)) += protect(constant(2)))()(); + BOOST_CHECK(k==3); + + // note, the following doesn't work: + + // ((var(k) = constant(1)) = protect(constant(2)))(); + + // (var(k) = constant(1))() returns int& and thus the + // second assignment fails. + + // We should have something like: + // bind(var, var(k) = constant(1)) = protect(constant(2)))(); + // But currently var is not bindable. + + // The same goes with ret. A bindable ret could be handy sometimes as well + // (protect(std::cout << _1), std::cout << _1)(i)(j); does not work + // because the comma operator tries to store the result of the evaluation + // of std::cout << _1 as a copy (and you can't copy std::ostream). + // something like this: + // (protect(std::cout << _1), bind(ref, std::cout << _1))(i)(j); + + + // the stuff below works, but we do not want extra output to + // cout, must be changed to stringstreams but stringstreams do not + // work due to a bug in the type deduction. Will be fixed... +#if 0 + // But for now, ref is not bindable. There are other ways around this: + + int x = 1, y = 2; + (protect(std::cout << _1), (std::cout << _1, 0))(x)(y); + + // added one dummy value to make the argument to comma an int + // instead of ostream& + + // Note, the same problem is more apparent without protect + // (std::cout << 1, std::cout << constant(2))(); // does not work + + (boost::ref(std::cout << 1), std::cout << constant(2))(); // this does + +#endif + +} + + +void test_lambda_functors_as_arguments_to_lambda_functors() { + +// lambda functor is a function object, and can therefore be used +// as an argument to another lambda functors function call object. + + // Note however, that the argument/type substitution is not entered again. + // This means, that something like this will not work: + + (_1 + _2)(_1, make_const(7)); + (_1 + _2)(bind(&sum_0), make_const(7)); + + // or it does work, but the effect is not to call + // sum_0() + 7, but rather + // bind(sum_0) + 7, which results in another lambda functor + // (lambda functor + int) and can be called again + BOOST_CHECK((_1 + _2)(bind(&sum_0), make_const(7))() == 7); + + int i = 3, j = 12; + BOOST_CHECK((_1 - _2)(_2, _1)(i, j) == j - i); + + // also, note that lambda functor are no special case for bind if received + // as a parameter. In oder to be bindable, the functor must + // defint the sig template, or then + // the return type must be defined within the bind call. Lambda functors + // do define the sig template, so if the return type deduction system + // covers the case, there is no need to specify the return type + // explicitly. + + int a = 5, b = 6; + + // Let type deduction find out the return type + BOOST_CHECK(bind(_1, _2, _3)(unlambda(_1 + _2), a, b) == 11); + + //specify it yourself: + BOOST_CHECK(bind(_1, _2, _3)(ret<int>(_1 + _2), a, b) == 11); + BOOST_CHECK(ret<int>(bind(_1, _2, _3))(_1 + _2, a, b) == 11); + BOOST_CHECK(bind<int>(_1, _2, _3)(_1 + _2, a, b) == 11); + + bind(_1,1.0)(_1+_1); + return; + +} + + +void test_const_parameters() { + + // (_1 + _2)(1, 2); // this would fail, + + // Either make arguments const: + BOOST_CHECK((_1 + _2)(make_const(1), make_const(2)) == 3); + + // Or use const_parameters: + BOOST_CHECK(const_parameters(_1 + _2)(1, 2) == 3); + + + +} + +void test_rvalue_arguments() +{ + // Not quite working yet. + // Problems with visual 7.1 + // BOOST_CHECK((_1 + _2)(1, 2) == 3); +} + +void test_break_const() +{ + + // break_const is currently unnecessary, as LL supports perfect forwarding + // for up to there argument lambda functors, and LL does not support + // lambda functors with more than 3 args. + + // I'll keep the test case around anyway, if more arguments will be supported + // in the future. + + + + // break_const breaks constness! Be careful! + // You need this only if you need to have side effects on some argument(s) + // and some arguments are non-const rvalues and your lambda functors + // take more than 3 arguments. + + + int i = 1; + // OLD COMMENT: (_1 += _2)(i, 2) // fails, 2 is a non-const rvalue + // OLD COMMENT: const_parameters(_1 += _2)(i, 2) // fails, side-effect to i + break_const(_1 += _2)(i, 2); // ok + BOOST_CHECK(i == 3); +} + +template<class T> +struct func { + template<class Args> + struct sig { + typedef typename boost::tuples::element<1, Args>::type arg1; + // If the argument type is not the same as the expected type, + // return void, which will cause an error. Note that we + // can't just assert that the types are the same, because + // both const and non-const versions can be instantiated + // even though only one is ultimately used. + typedef typename boost::mpl::if_<boost::is_same<arg1, T>, + typename boost::remove_const<arg1>::type, + void + >::type type; + }; + template<class U> + U operator()(const U& arg) const { + return arg; + } +}; + +void test_sig() +{ + int i = 1; + BOOST_CHECK(bind(func<int>(), 1)() == 1); + BOOST_CHECK(bind(func<const int>(), _1)(static_cast<const int&>(i)) == 1); + BOOST_CHECK(bind(func<int>(), _1)(i) == 1); +} + +class base { +public: + virtual int foo() = 0; +}; + +class derived : public base { +public: + virtual int foo() { + return 1; + } +}; + +void test_abstract() +{ + derived d; + base& b = d; + BOOST_CHECK(bind(&base::foo, var(b))() == 1); + BOOST_CHECK(bind(&base::foo, *_1)(&b) == 1); +} + +int test_main(int, char *[]) { + + test_nested_binds(); + test_unlambda(); + test_protect(); + test_lambda_functors_as_arguments_to_lambda_functors(); + test_const_parameters(); + test_rvalue_arguments(); + test_break_const(); + test_sig(); + test_abstract(); + return 0; +} diff --git a/libs/lambda/test/bind_tests_simple.cpp b/libs/lambda/test/bind_tests_simple.cpp new file mode 100644 index 000000000..1e63d6958 --- /dev/null +++ b/libs/lambda/test/bind_tests_simple.cpp @@ -0,0 +1,187 @@ +// bind_tests_simple.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/bind.hpp" + +#include <iostream> + +using namespace boost::lambda; + + +int sum_of_args_0() { return 0; } +int sum_of_args_1(int a) { return a; } +int sum_of_args_2(int a, int b) { return a+b; } +int sum_of_args_3(int a, int b, int c) { return a+b+c; } +int sum_of_args_4(int a, int b, int c, int d) { return a+b+c+d; } +int sum_of_args_5(int a, int b, int c, int d, int e) { return a+b+c+d+e; } +int sum_of_args_6(int a, int b, int c, int d, int e, int f) { return a+b+c+d+e+f; } +int sum_of_args_7(int a, int b, int c, int d, int e, int f, int g) { return a+b+c+d+e+f+g; } +int sum_of_args_8(int a, int b, int c, int d, int e, int f, int g, int h) { return a+b+c+d+e+f+g+h; } +int sum_of_args_9(int a, int b, int c, int d, int e, int f, int g, int h, int i) { return a+b+c+d+e+f+g+h+i; } + + +// ---------------------------- + +class A { + int i; +public: + A(int n) : i(n) {}; + int add(const int& j) { return i + j; } + int add2(int a1, int a2) { return i + a1 + a2; } + int add3(int a1, int a2, int a3) { return i + a1 + a2 + a3; } + int add4(int a1, int a2, int a3, int a4) { return i + a1 + a2 + a3 + a4; } + int add5(int a1, int a2, int a3, int a4, int a5) + { return i + a1 + a2 + a3 + a4 + a5; } + int add6(int a1, int a2, int a3, int a4, int a5, int a6) + { return i + a1 + a2 + a3 + a4 + a5 + a6; } + int add7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) + { return i + a1 + a2 + a3 + a4 + a5 + a6 + a7; } + int add8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) + { return i + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; } + +}; + +void test_member_functions() +{ + using boost::ref; + A a(10); + int i = 1; + + + + + BOOST_CHECK(bind(&A::add, ref(a), _1)(i) == 11); + BOOST_CHECK(bind(&A::add, &a, _1)(i) == 11); + BOOST_CHECK(bind(&A::add, _1, 1)(a) == 11); + BOOST_CHECK(bind(&A::add, _1, 1)(make_const(&a)) == 11); + + BOOST_CHECK(bind(&A::add2, _1, 1, 1)(a) == 12); + BOOST_CHECK(bind(&A::add3, _1, 1, 1, 1)(a) == 13); + BOOST_CHECK(bind(&A::add4, _1, 1, 1, 1, 1)(a) == 14); + BOOST_CHECK(bind(&A::add5, _1, 1, 1, 1, 1, 1)(a) == 15); + BOOST_CHECK(bind(&A::add6, _1, 1, 1, 1, 1, 1, 1)(a) == 16); + BOOST_CHECK(bind(&A::add7, _1, 1, 1, 1, 1, 1, 1, 1)(a) == 17); + BOOST_CHECK(bind(&A::add8, _1, 1, 1, 1, 1, 1, 1, 1, 1)(a) == 18); + + // This should fail, as lambda functors store arguments as const + // bind(&A::add, a, _1); +} + +struct B { + B(int n) : i(n) {}; + int i; +}; + +void test_data_members() +{ + using boost::ref; + B b(10); + BOOST_CHECK(bind(&B::i, ref(b))() == 10); + BOOST_CHECK(bind(&B::i, b)() == 10); + BOOST_CHECK(bind(&B::i, _1)(b) == 10); + BOOST_CHECK(bind(&B::i, _1)(B(11)) == 11); + bind(&B::i, ref(b))() = 1; + BOOST_CHECK(b.i == 1); +} + +int test_main(int, char *[]) { + + int i = 1; int j = 2; int k = 3; + int result; + + // bind all parameters + BOOST_CHECK(bind(&sum_of_args_0)()==0); + BOOST_CHECK(bind(&sum_of_args_1, 1)()==1); + BOOST_CHECK(bind(&sum_of_args_2, 1, 2)()==3); + BOOST_CHECK(bind(&sum_of_args_3, 1, 2, 3)()==6); + BOOST_CHECK(bind(&sum_of_args_4, 1, 2, 3, 4)()==10); + BOOST_CHECK(bind(&sum_of_args_5, 1, 2, 3, 4, 5)()==15); + BOOST_CHECK(bind(&sum_of_args_6, 1, 2, 3, 4, 5, 6)()==21); + BOOST_CHECK(bind(&sum_of_args_7, 1, 2, 3, 4, 5, 6, 7)()==28); + BOOST_CHECK(bind(&sum_of_args_8, 1, 2, 3, 4, 5, 6, 7, 8)()==36); + BOOST_CHECK(bind(&sum_of_args_9, 1, 2, 3, 4, 5, 6, 7, 8, 9)()==45); + + // first parameter open + BOOST_CHECK(bind(&sum_of_args_0)()==0); + BOOST_CHECK(bind(&sum_of_args_1, _1)(i)==1); + BOOST_CHECK(bind(&sum_of_args_2, _1, 2)(i)==3); + BOOST_CHECK(bind(&sum_of_args_3, _1, 2, 3)(i)==6); + BOOST_CHECK(bind(&sum_of_args_4, _1, 2, 3, 4)(i)==10); + BOOST_CHECK(bind(&sum_of_args_5, _1, 2, 3, 4, 5)(i)==15); + BOOST_CHECK(bind(&sum_of_args_6, _1, 2, 3, 4, 5, 6)(i)==21); + BOOST_CHECK(bind(&sum_of_args_7, _1, 2, 3, 4, 5, 6, 7)(i)==28); + BOOST_CHECK(bind(&sum_of_args_8, _1, 2, 3, 4, 5, 6, 7, 8)(i)==36); + BOOST_CHECK(bind(&sum_of_args_9, _1, 2, 3, 4, 5, 6, 7, 8, 9)(i)==45); + + // two open arguments + BOOST_CHECK(bind(&sum_of_args_0)()==0); + BOOST_CHECK(bind(&sum_of_args_1, _1)(i)==1); + BOOST_CHECK(bind(&sum_of_args_2, _1, _2)(i, j)==3); + BOOST_CHECK(bind(&sum_of_args_3, _1, _2, 3)(i, j)==6); + BOOST_CHECK(bind(&sum_of_args_4, _1, _2, 3, 4)(i, j)==10); + BOOST_CHECK(bind(&sum_of_args_5, _1, _2, 3, 4, 5)(i, j)==15); + BOOST_CHECK(bind(&sum_of_args_6, _1, _2, 3, 4, 5, 6)(i, j)==21); + BOOST_CHECK(bind(&sum_of_args_7, _1, _2, 3, 4, 5, 6, 7)(i, j)==28); + BOOST_CHECK(bind(&sum_of_args_8, _1, _2, 3, 4, 5, 6, 7, 8)(i, j)==36); + BOOST_CHECK(bind(&sum_of_args_9, _1, _2, 3, 4, 5, 6, 7, 8, 9)(i, j)==45); + + // three open arguments + BOOST_CHECK(bind(&sum_of_args_0)()==0); + BOOST_CHECK(bind(&sum_of_args_1, _1)(i)==1); + BOOST_CHECK(bind(&sum_of_args_2, _1, _2)(i, j)==3); + BOOST_CHECK(bind(&sum_of_args_3, _1, _2, _3)(i, j, k)==6); + BOOST_CHECK(bind(&sum_of_args_4, _1, _2, _3, 4)(i, j, k)==10); + BOOST_CHECK(bind(&sum_of_args_5, _1, _2, _3, 4, 5)(i, j, k)==15); + BOOST_CHECK(bind(&sum_of_args_6, _1, _2, _3, 4, 5, 6)(i, j, k)==21); + BOOST_CHECK(bind(&sum_of_args_7, _1, _2, _3, 4, 5, 6, 7)(i, j, k)==28); + BOOST_CHECK(bind(&sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8)(i, j, k)==36); + BOOST_CHECK(bind(&sum_of_args_9, _1, _2, _3, 4, 5, 6, 7, 8, 9)(i, j, k)==45); + + // function compositions with bind + BOOST_CHECK(bind(&sum_of_args_3, bind(&sum_of_args_2, _1, 2), 2, 3)(i)==8); + BOOST_CHECK( + bind(&sum_of_args_9, + bind(&sum_of_args_0), // 0 + bind(&sum_of_args_1, _1), // 1 + bind(&sum_of_args_2, _1, _2), // 3 + bind(&sum_of_args_3, _1, _2, _3), // 6 + bind(&sum_of_args_4, _1, _2, _3, 4), // 10 + bind(&sum_of_args_5, _1, _2, _3, 4, 5), // 15 + bind(&sum_of_args_6, _1, _2, _3, 4, 5, 6), // 21 + bind(&sum_of_args_7, _1, _2, _3, 4, 5, 6, 7), // 28 + bind(&sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8) // 36 + )(i, j, k) == 120); + + // deeper nesting + result = + bind(&sum_of_args_1, // 12 + bind(&sum_of_args_4, // 12 + bind(&sum_of_args_2, // 3 + bind(&sum_of_args_1, // 1 + bind(&sum_of_args_1, _1) // 1 + ), + _2), + _2, + _3, + 4) + )(i, j, k); + BOOST_CHECK(result == 12); + + test_member_functions(); + + + return 0; +} diff --git a/libs/lambda/test/bind_tests_simple_f_refs.cpp b/libs/lambda/test/bind_tests_simple_f_refs.cpp new file mode 100644 index 000000000..df601d79e --- /dev/null +++ b/libs/lambda/test/bind_tests_simple_f_refs.cpp @@ -0,0 +1,148 @@ +// bind_tests_simple.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/bind.hpp" + +#include <iostream> + +using namespace boost::lambda; + + +int sum_of_args_0() { return 0; } +int sum_of_args_1(int a) { return a; } +int sum_of_args_2(int a, int b) { return a+b; } +int sum_of_args_3(int a, int b, int c) { return a+b+c; } +int sum_of_args_4(int a, int b, int c, int d) { return a+b+c+d; } +int sum_of_args_5(int a, int b, int c, int d, int e) { return a+b+c+d+e; } +int sum_of_args_6(int a, int b, int c, int d, int e, int f) { return a+b+c+d+e+f; } +int sum_of_args_7(int a, int b, int c, int d, int e, int f, int g) { return a+b+c+d+e+f+g; } +int sum_of_args_8(int a, int b, int c, int d, int e, int f, int g, int h) { return a+b+c+d+e+f+g+h; } +int sum_of_args_9(int a, int b, int c, int d, int e, int f, int g, int h, int i) { return a+b+c+d+e+f+g+h+i; } + + +// ---------------------------- + +class A { + int i; +public: + A(int n) : i(n) {}; + int add(const int& j) { return i + j; } +}; + +void test_member_functions() +{ + using boost::ref; + A a(10); + int i = 1; + + BOOST_CHECK(bind(&A::add, ref(a), _1)(i) == 11); + BOOST_CHECK(bind(&A::add, &a, _1)(i) == 11); + BOOST_CHECK(bind(&A::add, _1, 1)(a) == 11); + BOOST_CHECK(bind(&A::add, _1, 1)(make_const(&a)) == 11); + + // This should fail, as lambda functors store arguments as const + // bind(&A::add, a, _1); +} + +int test_main(int, char *[]) { + + int i = 1; int j = 2; int k = 3; + int result; + + + // bind all parameters + BOOST_CHECK(bind(sum_of_args_0)()==0); + BOOST_CHECK(bind(sum_of_args_1, 1)()==1); + BOOST_CHECK(bind(sum_of_args_2, 1, 2)()==3); + BOOST_CHECK(bind(sum_of_args_3, 1, 2, 3)()==6); + BOOST_CHECK(bind(sum_of_args_4, 1, 2, 3, 4)()==10); + BOOST_CHECK(bind(sum_of_args_5, 1, 2, 3, 4, 5)()==15); + BOOST_CHECK(bind(sum_of_args_6, 1, 2, 3, 4, 5, 6)()==21); + BOOST_CHECK(bind(sum_of_args_7, 1, 2, 3, 4, 5, 6, 7)()==28); + BOOST_CHECK(bind(sum_of_args_8, 1, 2, 3, 4, 5, 6, 7, 8)()==36); + BOOST_CHECK(bind(sum_of_args_9, 1, 2, 3, 4, 5, 6, 7, 8, 9)()==45); + + // first parameter open + BOOST_CHECK(bind(sum_of_args_0)()==0); + BOOST_CHECK(bind(sum_of_args_1, _1)(i)==1); + BOOST_CHECK(bind(sum_of_args_2, _1, 2)(i)==3); + BOOST_CHECK(bind(sum_of_args_3, _1, 2, 3)(i)==6); + BOOST_CHECK(bind(sum_of_args_4, _1, 2, 3, 4)(i)==10); + BOOST_CHECK(bind(sum_of_args_5, _1, 2, 3, 4, 5)(i)==15); + BOOST_CHECK(bind(sum_of_args_6, _1, 2, 3, 4, 5, 6)(i)==21); + BOOST_CHECK(bind(sum_of_args_7, _1, 2, 3, 4, 5, 6, 7)(i)==28); + BOOST_CHECK(bind(sum_of_args_8, _1, 2, 3, 4, 5, 6, 7, 8)(i)==36); + BOOST_CHECK(bind(sum_of_args_9, _1, 2, 3, 4, 5, 6, 7, 8, 9)(i)==45); + + // two open arguments + BOOST_CHECK(bind(sum_of_args_0)()==0); + BOOST_CHECK(bind(sum_of_args_1, _1)(i)==1); + BOOST_CHECK(bind(sum_of_args_2, _1, _2)(i, j)==3); + BOOST_CHECK(bind(sum_of_args_3, _1, _2, 3)(i, j)==6); + BOOST_CHECK(bind(sum_of_args_4, _1, _2, 3, 4)(i, j)==10); + BOOST_CHECK(bind(sum_of_args_5, _1, _2, 3, 4, 5)(i, j)==15); + BOOST_CHECK(bind(sum_of_args_6, _1, _2, 3, 4, 5, 6)(i, j)==21); + BOOST_CHECK(bind(sum_of_args_7, _1, _2, 3, 4, 5, 6, 7)(i, j)==28); + BOOST_CHECK(bind(sum_of_args_8, _1, _2, 3, 4, 5, 6, 7, 8)(i, j)==36); + BOOST_CHECK(bind(sum_of_args_9, _1, _2, 3, 4, 5, 6, 7, 8, 9)(i, j)==45); + + // three open arguments + BOOST_CHECK(bind(sum_of_args_0)()==0); + BOOST_CHECK(bind(sum_of_args_1, _1)(i)==1); + BOOST_CHECK(bind(sum_of_args_2, _1, _2)(i, j)==3); + BOOST_CHECK(bind(sum_of_args_3, _1, _2, _3)(i, j, k)==6); + BOOST_CHECK(bind(sum_of_args_4, _1, _2, _3, 4)(i, j, k)==10); + BOOST_CHECK(bind(sum_of_args_5, _1, _2, _3, 4, 5)(i, j, k)==15); + BOOST_CHECK(bind(sum_of_args_6, _1, _2, _3, 4, 5, 6)(i, j, k)==21); + BOOST_CHECK(bind(sum_of_args_7, _1, _2, _3, 4, 5, 6, 7)(i, j, k)==28); + BOOST_CHECK(bind(sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8)(i, j, k)==36); + BOOST_CHECK(bind(sum_of_args_9, _1, _2, _3, 4, 5, 6, 7, 8, 9)(i, j, k)==45); + + // function compositions with bind + BOOST_CHECK(bind(sum_of_args_3, bind(sum_of_args_2, _1, 2), 2, 3)(i)==8); + BOOST_CHECK( + bind(sum_of_args_9, + bind(sum_of_args_0), // 0 + bind(sum_of_args_1, _1), // 1 + bind(sum_of_args_2, _1, _2), // 3 + bind(sum_of_args_3, _1, _2, _3), // 6 + bind(sum_of_args_4, _1, _2, _3, 4), // 10 + bind(sum_of_args_5, _1, _2, _3, 4, 5), // 15 + bind(sum_of_args_6, _1, _2, _3, 4, 5, 6), // 21 + bind(sum_of_args_7, _1, _2, _3, 4, 5, 6, 7), // 28 + bind(sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8) // 36 + )(i, j, k) == 120); + + // deeper nesting + result = + bind(sum_of_args_1, // 12 + bind(sum_of_args_4, // 12 + bind(sum_of_args_2, // 3 + bind(sum_of_args_1, // 1 + bind(sum_of_args_1, _1) // 1 + ), + _2), + _2, + _3, + 4) + )(i, j, k); + BOOST_CHECK(result == 12); + + test_member_functions(); + + + return 0; +} diff --git a/libs/lambda/test/bll_and_function.cpp b/libs/lambda/test/bll_and_function.cpp new file mode 100644 index 000000000..03bcc3ec2 --- /dev/null +++ b/libs/lambda/test/bll_and_function.cpp @@ -0,0 +1,68 @@ +// bll_and_function.cpp - The Boost Lambda Library ----------------------- +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// test using BLL and boost::function + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" + +#include "boost/function.hpp" + +#include <vector> +#include <map> +#include <set> +#include <string> + + +using namespace boost::lambda; + +using namespace std; + +void test_function() { + + boost::function<int (int, int)> f; + f = _1 + _2; + + BOOST_CHECK(f(1, 2)== 3); + + int i=1; int j=2; + boost::function<int& (int&, int)> g = _1 += _2; + g(i, j); + BOOST_CHECK(i==3); + + + + int* sum = new int(); + *sum = 0; + boost::function<int& (int)> counter = *sum += _1; + counter(5); // ok, sum* = 5; + BOOST_CHECK(*sum == 5); + delete sum; + + // The next statement would lead to a dangling reference + // counter(3); // error, *sum does not exist anymore + +} + + +int test_main(int, char *[]) { + + test_function(); + + return 0; +} + + + + + + diff --git a/libs/lambda/test/cast_test.cpp b/libs/lambda/test/cast_test.cpp new file mode 100644 index 000000000..eba4300ab --- /dev/null +++ b/libs/lambda/test/cast_test.cpp @@ -0,0 +1,107 @@ +// cast_tests.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + + +#include "boost/lambda/lambda.hpp" + +#include "boost/lambda/casts.hpp" + +#include <string> + +using namespace boost::lambda; +using namespace std; + +class base { + int x; +public: + virtual std::string class_name() const { return "const base"; } + virtual std::string class_name() { return "base"; } + virtual ~base() {} +}; + +class derived : public base { + int y[100]; +public: + virtual std::string class_name() const { return "const derived"; } + virtual std::string class_name() { return "derived"; } +}; + + + + +void do_test() { + + derived *p_derived = new derived; + base *p_base = new base; + + base *b = 0; + derived *d = 0; + + (var(b) = ll_static_cast<base *>(p_derived))(); + (var(d) = ll_static_cast<derived *>(b))(); + + BOOST_CHECK(b->class_name() == "derived"); + BOOST_CHECK(d->class_name() == "derived"); + + (var(b) = ll_dynamic_cast<derived *>(b))(); + BOOST_CHECK(b != 0); + BOOST_CHECK(b->class_name() == "derived"); + + (var(d) = ll_dynamic_cast<derived *>(p_base))(); + BOOST_CHECK(d == 0); + + + + const derived* p_const_derived = p_derived; + + BOOST_CHECK(p_const_derived->class_name() == "const derived"); + (var(d) = ll_const_cast<derived *>(p_const_derived))(); + BOOST_CHECK(d->class_name() == "derived"); + + int i = 10; + char* cp = reinterpret_cast<char*>(&i); + + int* ip; + (var(ip) = ll_reinterpret_cast<int *>(cp))(); + BOOST_CHECK(*ip == 10); + + + // typeid + + BOOST_CHECK(string(ll_typeid(d)().name()) == string(typeid(d).name())); + + + // sizeof + + BOOST_CHECK(ll_sizeof(_1)(p_derived) == sizeof(p_derived)); + BOOST_CHECK(ll_sizeof(_1)(*p_derived) == sizeof(*p_derived)); + BOOST_CHECK(ll_sizeof(_1)(p_base) == sizeof(p_base)); + BOOST_CHECK(ll_sizeof(_1)(*p_base) == sizeof(*p_base)); + + int an_array[100]; + BOOST_CHECK(ll_sizeof(_1)(an_array) == 100 * sizeof(int)); + + delete p_derived; + delete p_base; + + +} + +int test_main(int, char *[]) { + + do_test(); + return 0; +} diff --git a/libs/lambda/test/constructor_tests.cpp b/libs/lambda/test/constructor_tests.cpp new file mode 100644 index 000000000..8cef0cb4e --- /dev/null +++ b/libs/lambda/test/constructor_tests.cpp @@ -0,0 +1,265 @@ +// constructor_tests.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/bind.hpp" + +#include "boost/lambda/construct.hpp" + +#include <iostream> +#include <algorithm> +#include <vector> + +#ifdef BOOST_MSVC +#pragma warning(disable:4512) +#endif + +using namespace boost::lambda; +namespace bl = boost::lambda; + +template<class T> +bool check_tuple(int n, const T& t) +{ + return (t.get_head() == n) && check_tuple(n+1, t.get_tail()); +} + +template <> +bool check_tuple(int /*n*/, const null_type& ) { return true; } + + +void constructor_all_lengths() +{ + bool ok; + ok = check_tuple( + 1, + bind(constructor<tuple<int> >(), + 1)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int> >(), + 1, 2)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int> >(), + 1, 2, 3)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int, int> >(), + 1, 2, 3, 4)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int, int, int> >(), + 1, 2, 3, 4, 5)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6, 7)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6, 7, 8)() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + bind(constructor<tuple<int, int, int, int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6, 7, 8, 9)() + ); + BOOST_CHECK(ok); + +} + +void new_ptr_all_lengths() +{ + bool ok; + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int> >(), + 1))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int> >(), + 1, 2))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int> >(), + 1, 2, 3))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int, int> >(), + 1, 2, 3, 4))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int, int, int> >(), + 1, 2, 3, 4, 5))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6, 7))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6, 7, 8))() + ); + BOOST_CHECK(ok); + + ok = check_tuple( + 1, + *(bind(new_ptr<tuple<int, int, int, int, int, int, int, int, int> >(), + 1, 2, 3, 4, 5, 6, 7, 8, 9))() + ); + BOOST_CHECK(ok); + +} + +class is_destructor_called { + bool& b; +public: + is_destructor_called(bool& bb) : b(bb) { b = false; } + ~is_destructor_called() { b = true; } +}; + +void test_destructor () +{ + char space[sizeof(is_destructor_called)]; + bool flag = false; + + is_destructor_called* idc = new(space) is_destructor_called(flag); + BOOST_CHECK(flag == false); + bind(destructor(), _1)(idc); + BOOST_CHECK(flag == true); + + idc = new(space) is_destructor_called(flag); + BOOST_CHECK(flag == false); + bind(destructor(), _1)(*idc); + BOOST_CHECK(flag == true); +} + + +class count_deletes { +public: + static int count; + ~count_deletes() { ++count; } +}; + +int count_deletes::count = 0; + +void test_news_and_deletes () +{ + int* i[10]; + std::for_each(i, i+10, _1 = bind(new_ptr<int>(), 2)); + int count_errors = 0; + + std::for_each(i, i+10, (*_1 == 2) || ++var(count_errors)); + BOOST_CHECK(count_errors == 0); + + + count_deletes* ct[10]; + std::for_each(ct, ct+10, _1 = bind(new_ptr<count_deletes>())); + count_deletes::count = 0; + std::for_each(ct, ct+10, bind(delete_ptr(), _1)); + BOOST_CHECK(count_deletes::count == 10); + +} + +void test_array_new_and_delete() +{ + count_deletes* c; + (_1 = bind(new_array<count_deletes>(), 5))(c); + count_deletes::count = 0; + + bind(delete_array(), _1)(c); + BOOST_CHECK(count_deletes::count == 5); +} + + +void delayed_construction() +{ + std::vector<int> x(3); + std::vector<int> y(3); + + std::fill(x.begin(), x.end(), 0); + std::fill(y.begin(), y.end(), 1); + + std::vector<std::pair<int, int> > v; + + std::transform(x.begin(), x.end(), y.begin(), std::back_inserter(v), + bl::bind(constructor<std::pair<int, int> >(), _1, _2) ); +} + +int test_main(int, char *[]) { + + constructor_all_lengths(); + new_ptr_all_lengths(); + delayed_construction(); + test_destructor(); + test_news_and_deletes(); + test_array_new_and_delete(); + + return 0; +} diff --git a/libs/lambda/test/control_structures.cpp b/libs/lambda/test/control_structures.cpp new file mode 100644 index 000000000..12eabf8d3 --- /dev/null +++ b/libs/lambda/test/control_structures.cpp @@ -0,0 +1,123 @@ +// -- control_structures.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/if.hpp" +#include "boost/lambda/loops.hpp" + +#include <iostream> +#include <algorithm> +#include <vector> + +using namespace boost; + +using boost::lambda::constant; +using boost::lambda::_1; +using boost::lambda::_2; +using boost::lambda::_3; +using boost::lambda::make_const; +using boost::lambda::for_loop; +using boost::lambda::while_loop; +using boost::lambda::do_while_loop; +using boost::lambda::if_then; +using boost::lambda::if_then_else; +using boost::lambda::if_then_else_return; + +// 2 container for_each +template <class InputIter1, class InputIter2, class Function> +Function for_each(InputIter1 first, InputIter1 last, + InputIter2 first2, Function f) { + for ( ; first != last; ++first, ++first2) + f(*first, *first2); + return f; +} + +void simple_loops() { + + // for loops --------------------------------------------------------- + int i; + int arithmetic_series = 0; + for_loop(_1 = 0, _1 < 10, _1++, arithmetic_series += _1)(i); + BOOST_CHECK(arithmetic_series == 45); + + // no body case + for_loop(boost::lambda::var(i) = 0, boost::lambda::var(i) < 100, ++boost::lambda::var(i))(); + BOOST_CHECK(i == 100); + + // while loops ------------------------------------------------------- + int a = 0, b = 0, c = 0; + + while_loop((_1 + _2) >= (_1 * _2), (++_1, ++_2, ++_3))(a, b, c); + BOOST_CHECK(c == 3); + + int count; + count = 0; i = 0; + while_loop(_1++ < 10, ++boost::lambda::var(count))(i); + BOOST_CHECK(count == 10); + + // note that the first parameter of do_while_loop is the condition + count = 0; i = 0; + do_while_loop(_1++ < 10, ++boost::lambda::var(count))(i); + BOOST_CHECK(count == 11); + + a = 0; + do_while_loop(constant(false), _1++)(a); + BOOST_CHECK(a == 1); + + // no body cases + a = 40; b = 30; + while_loop(--_1 > _2)(a, b); + BOOST_CHECK(a == b); + + // (the no body case for do_while_loop is pretty redundant) + a = 40; b = 30; + do_while_loop(--_1 > _2)(a, b); + BOOST_CHECK(a == b); + + +} + +void simple_ifs () { + + int value = 42; + if_then(_1 < 0, _1 = 0)(value); + BOOST_CHECK(value == 42); + + value = -42; + if_then(_1 < 0, _1 = -_1)(value); + BOOST_CHECK(value == 42); + + int min; + if_then_else(_1 < _2, boost::lambda::var(min) = _1, boost::lambda::var(min) = _2) + (make_const(1), make_const(2)); + BOOST_CHECK(min == 1); + + if_then_else(_1 < _2, boost::lambda::var(min) = _1, boost::lambda::var(min) = _2) + (make_const(5), make_const(3)); + BOOST_CHECK(min == 3); + + int x, y; + x = -1; y = 1; + BOOST_CHECK(if_then_else_return(_1 < _2, _2, _1)(x, y) == (std::max)(x ,y)); + BOOST_CHECK(if_then_else_return(_1 < _2, _2, _1)(y, x) == (std::max)(x ,y)); +} + + +int test_main(int, char *[]) +{ + simple_loops(); + simple_ifs(); + return 0; +} diff --git a/libs/lambda/test/exception_test.cpp b/libs/lambda/test/exception_test.cpp new file mode 100644 index 000000000..ee906668b --- /dev/null +++ b/libs/lambda/test/exception_test.cpp @@ -0,0 +1,621 @@ +// -- exception_test.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" + +#include "boost/lambda/exceptions.hpp" + +#include "boost/lambda/bind.hpp" + +#include<iostream> +#include<algorithm> +#include <cstdlib> + +#include <iostream> + +using namespace boost::lambda; +using namespace std; + +// to prevent unused variables warnings +template <class T> void dummy(const T&) {} + +void erroneous_exception_related_lambda_expressions() { + + int i = 0; + dummy(i); + + // Uncommenting any of the below code lines should result in a compile + // time error + + // this should fail (a rethrow binder outside of catch + // rethrow()(); + + // this should fail too for the same reason + // try_catch(rethrow(), catch_all(cout << constant("Howdy")))(); + + // this fails too (_e outside of catch_exception) + // (_1 + _2 + _e)(i, i, i); + + // and this (_e outside of catch_exception) + // try_catch( throw_exception(1), catch_all(cout << _e)); + + // and this (_3 in catch_exception + // try_catch( throw_exception(1), catch_exception<int>(cout << _3)); +} + + +class A1 {}; +class A2 {}; +class A3 {}; +class A4 {}; +class A5 {}; +class A6 {}; +class A7 {}; +class A8 {}; +class A9 {}; + +void throw_AX(int j) { + int i = j; + switch(i) { + case 1: throw A1(); + case 2: throw A2(); + case 3: throw A3(); + case 4: throw A4(); + case 5: throw A5(); + case 6: throw A6(); + case 7: throw A7(); + case 8: throw A8(); + case 9: throw A9(); + } +} + +void test_different_number_of_catch_blocks() { + + int ecount; + +// no catch(...) cases + + + ecount = 0; + for(int i=1; i<=1; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 1); + + ecount = 0; + for(int i=1; i<=2; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 2); + + ecount = 0; + for(int i=1; i<=3; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 3); + + ecount = 0; + for(int i=1; i<=4; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 4); + + ecount = 0; + for(int i=1; i<=5; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 5); + + ecount = 0; + for(int i=1; i<=6; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 6); + + ecount = 0; + for(int i=1; i<=7; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ), + catch_exception<A7>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 7); + + ecount = 0; + for(int i=1; i<=8; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ), + catch_exception<A7>( + var(ecount)++ + ), + catch_exception<A8>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 8); + + ecount = 0; + for(int i=1; i<=9; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ), + catch_exception<A7>( + var(ecount)++ + ), + catch_exception<A8>( + var(ecount)++ + ), + catch_exception<A9>( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 9); + + + // with catch(...) blocks + + ecount = 0; + for(int i=1; i<=1; i++) + { + try_catch( + bind(throw_AX, _1), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 1); + + ecount = 0; + for(int i=1; i<=2; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 2); + + ecount = 0; + for(int i=1; i<=3; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 3); + + ecount = 0; + for(int i=1; i<=4; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 4); + + ecount = 0; + for(int i=1; i<=5; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 5); + + ecount = 0; + for(int i=1; i<=6; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 6); + + ecount = 0; + for(int i=1; i<=7; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 7); + + ecount = 0; + for(int i=1; i<=8; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ), + catch_exception<A7>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 8); + + ecount = 0; + for(int i=1; i<=9; i++) + { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>( + var(ecount)++ + ), + catch_exception<A2>( + var(ecount)++ + ), + catch_exception<A3>( + var(ecount)++ + ), + catch_exception<A4>( + var(ecount)++ + ), + catch_exception<A5>( + var(ecount)++ + ), + catch_exception<A6>( + var(ecount)++ + ), + catch_exception<A7>( + var(ecount)++ + ), + catch_exception<A8>( + var(ecount)++ + ), + catch_all( + var(ecount)++ + ) + )(i); + } + BOOST_CHECK(ecount == 9); +} + +void test_empty_catch_blocks() { + try_catch( + bind(throw_AX, _1), + catch_exception<A1>() + )(make_const(1)); + + try_catch( + bind(throw_AX, _1), + catch_all() + )(make_const(1)); + +} + + +void return_type_matching() { + +// Rules for return types of the lambda functors in try and catch parts: +// 1. The try part dictates the return type of the whole +// try_catch lambda functor +// 2. If return type of try part is void, catch parts can return anything, +// but the return types are ignored +// 3. If the return type of the try part is A, then each catch return type +// must be implicitly convertible to A, or then it must throw for sure + + + int i = 1; + + BOOST_CHECK( + + try_catch( + _1 + 1, + catch_exception<int>((&_1, rethrow())), // no match, but ok since throws + catch_exception<char>(_e) // ok, char convertible to int + )(i) + + == 2 + ); + + // note that while e.g. char is convertible to int, it is not convertible + // to int&, (some lambda functors return references) + + // try_catch( + // _1 += 1, + // catch_exception<char>(_e) // NOT ok, char not convertible to int& + // )(i); + + // if you don't care about the return type, you can use make_void + try_catch( + make_void(_1 += 1), + catch_exception<char>(_e) // since try is void, catch can return anything + )(i); + BOOST_CHECK(i == 2); + + try_catch( + (_1 += 1, throw_exception('a')), + catch_exception<char>(_e) // since try throws, it is void, + // so catch can return anything + )(i); + BOOST_CHECK(i == 3); + + char a = 'a'; + try_catch( + try_catch( + throw_exception(1), + catch_exception<int>(throw_exception('b')) + ), + catch_exception<char>( _1 = _e ) + )(a); + BOOST_CHECK(a == 'b'); +} + +int test_main(int, char *[]) { + + try + { + test_different_number_of_catch_blocks(); + return_type_matching(); + test_empty_catch_blocks(); + } + catch (int) + { + BOOST_CHECK(false); + } + catch(...) + { + BOOST_CHECK(false); + } + + + return EXIT_SUCCESS; +} + + + + diff --git a/libs/lambda/test/extending_rt_traits.cpp b/libs/lambda/test/extending_rt_traits.cpp new file mode 100644 index 000000000..56916ab51 --- /dev/null +++ b/libs/lambda/test/extending_rt_traits.cpp @@ -0,0 +1,394 @@ +// extending_return_type_traits.cpp -- The Boost Lambda Library -------- +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/bind.hpp" +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/detail/suppress_unused.hpp" + +#include <iostream> + +#include <functional> + +#include <algorithm> + +using boost::lambda::detail::suppress_unused_variable_warnings; + +class A {}; +class B {}; + +using namespace boost::lambda; + + +B operator--(const A&, int) { return B(); } +B operator--(A&) { return B(); } +B operator++(const A&, int) { return B(); } +B operator++(A&) { return B(); } +B operator-(const A&) { return B(); } +B operator+(const A&) { return B(); } + +B operator!(const A&) { return B(); } + +B operator&(const A&) { return B(); } +B operator*(const A&) { return B(); } + +namespace boost { +namespace lambda { + + // unary + and - +template<class Act> +struct plain_return_type_1<unary_arithmetic_action<Act>, A > { + typedef B type; +}; + + // post incr/decr +template<class Act> +struct plain_return_type_1<post_increment_decrement_action<Act>, A > { + typedef B type; +}; + + // pre incr/decr +template<class Act> +struct plain_return_type_1<pre_increment_decrement_action<Act>, A > { + typedef B type; +}; + // ! +template<> +struct plain_return_type_1<logical_action<not_action>, A> { + typedef B type; +}; + // & +template<> +struct plain_return_type_1<other_action<addressof_action>, A> { + typedef B type; +}; + // * +template<> +struct plain_return_type_1<other_action<contentsof_action>, A> { + typedef B type; +}; + + +} // lambda +} // boost + +void ok(B /*b*/) {} + +void test_unary_operators() +{ + A a; int i = 1; + ok((++_1)(a)); + ok((--_1)(a)); + ok((_1++)(a)); + ok((_1--)(a)); + ok((+_1)(a)); + ok((-_1)(a)); + ok((!_1)(a)); + ok((&_1)(a)); + ok((*_1)(a)); + + BOOST_CHECK((*_1)(make_const(&i)) == 1); +} + +class X {}; +class Y {}; +class Z {}; + +Z operator+(const X&, const Y&) { return Z(); } +Z operator-(const X&, const Y&) { return Z(); } +X operator*(const X&, const Y&) { return X(); } + +Z operator/(const X&, const Y&) { return Z(); } +Z operator%(const X&, const Y&) { return Z(); } + +class XX {}; +class YY {}; +class ZZ {}; +class VV {}; + +// it is possible to support differently cv-qualified versions +YY operator*(XX&, YY&) { return YY(); } +ZZ operator*(const XX&, const YY&) { return ZZ(); } +XX operator*(volatile XX&, volatile YY&) { return XX(); } +VV operator*(const volatile XX&, const volatile YY&) { return VV(); } + +// the traits can be more complex: +template <class T> +class my_vector {}; + +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>(); +} + + + +// bitwise ops: +X operator<<(const X&, const Y&) { return X(); } +Z operator>>(const X&, const Y&) { return Z(); } +Z operator&(const X&, const Y&) { return Z(); } +Z operator|(const X&, const Y&) { return Z(); } +Z operator^(const X&, const Y&) { return Z(); } + +// comparison ops: + +X operator<(const X&, const Y&) { return X(); } +Z operator>(const X&, const Y&) { return Z(); } +Z operator<=(const X&, const Y&) { return Z(); } +Z operator>=(const X&, const Y&) { return Z(); } +Z operator==(const X&, const Y&) { return Z(); } +Z operator!=(const X&, const Y&) { return Z(); } + +// logical + +X operator&&(const X&, const Y&) { return X(); } +Z operator||(const X&, const Y&) { return Z(); } + +// arithh assignment + +Z operator+=( X&, const Y&) { return Z(); } +Z operator-=( X&, const Y&) { return Z(); } +Y operator*=( X&, const Y&) { return Y(); } +Z operator/=( X&, const Y&) { return Z(); } +Z operator%=( X&, const Y&) { return Z(); } + +// bitwise assignment +Z operator<<=( X&, const Y&) { return Z(); } +Z operator>>=( X&, const Y&) { return Z(); } +Y operator&=( X&, const Y&) { return Y(); } +Z operator|=( X&, const Y&) { return Z(); } +Z operator^=( X&, const Y&) { return Z(); } + +// assignment +class Assign { +public: + void operator=(const Assign& /*a*/) {} + X operator[](const int& /*i*/) { return X(); } +}; + + + +namespace boost { +namespace lambda { + + // you can do action groups +template<class Act> +struct plain_return_type_2<arithmetic_action<Act>, X, Y> { + typedef Z type; +}; + + // or specialize the exact action +template<> +struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> { + typedef X type; +}; + + // if you want to make a distinction between differently cv-qualified + // types, you need to specialize on a different level: +template<> +struct return_type_2<arithmetic_action<multiply_action>, XX, YY> { + typedef YY type; +}; +template<> +struct return_type_2<arithmetic_action<multiply_action>, const XX, const YY> { + typedef ZZ type; +}; +template<> +struct return_type_2<arithmetic_action<multiply_action>, volatile XX, volatile YY> { + typedef XX type; +}; +template<> +struct return_type_2<arithmetic_action<multiply_action>, volatile const XX, const volatile YY> { + typedef VV type; +}; + + // the mapping can be more complex: +template<class A, class B> +struct 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; + typedef my_vector<res_type> type; +}; + + // bitwise binary: + // you can do action groups +template<class Act> +struct plain_return_type_2<bitwise_action<Act>, X, Y> { + typedef Z type; +}; + + // or specialize the exact action +template<> +struct plain_return_type_2<bitwise_action<leftshift_action>, X, Y> { + typedef X type; +}; + + // comparison binary: + // you can do action groups +template<class Act> +struct plain_return_type_2<relational_action<Act>, X, Y> { + typedef Z type; +}; + + // or specialize the exact action +template<> +struct plain_return_type_2<relational_action<less_action>, X, Y> { + typedef X type; +}; + + // logical binary: + // you can do action groups +template<class Act> +struct plain_return_type_2<logical_action<Act>, X, Y> { + typedef Z type; +}; + + // or specialize the exact action +template<> +struct plain_return_type_2<logical_action<and_action>, X, Y> { + typedef X type; +}; + + // arithmetic assignment : + // you can do action groups +template<class Act> +struct plain_return_type_2<arithmetic_assignment_action<Act>, X, Y> { + typedef Z type; +}; + + // or specialize the exact action +template<> +struct plain_return_type_2<arithmetic_assignment_action<multiply_action>, X, Y> { + typedef Y type; +}; + + // arithmetic assignment : + // you can do action groups +template<class Act> +struct plain_return_type_2<bitwise_assignment_action<Act>, X, Y> { + typedef Z type; +}; + + // or specialize the exact action +template<> +struct plain_return_type_2<bitwise_assignment_action<and_action>, X, Y> { + typedef Y type; +}; + + // assignment +template<> +struct plain_return_type_2<other_action<assignment_action>, Assign, Assign> { + typedef void type; +}; + // subscript +template<> +struct plain_return_type_2<other_action<subscript_action>, Assign, int> { + typedef X type; +}; + + +} // end lambda +} // end boost + + + +void test_binary_operators() { + + X x; Y y; + (_1 + _2)(x, y); + (_1 - _2)(x, y); + (_1 * _2)(x, y); + (_1 / _2)(x, y); + (_1 % _2)(x, y); + + + // make a distinction between differently cv-qualified operators + XX xx; YY yy; + const XX& cxx = xx; + const YY& cyy = yy; + volatile XX& vxx = xx; + volatile YY& vyy = yy; + const volatile XX& cvxx = xx; + const volatile YY& cvyy = yy; + + ZZ dummy1 = (_1 * _2)(cxx, cyy); + YY dummy2 = (_1 * _2)(xx, yy); + XX dummy3 = (_1 * _2)(vxx, vyy); + VV dummy4 = (_1 * _2)(cvxx, cvyy); + + suppress_unused_variable_warnings(dummy1); + suppress_unused_variable_warnings(dummy2); + suppress_unused_variable_warnings(dummy3); + suppress_unused_variable_warnings(dummy4); + + my_vector<int> v1; my_vector<double> v2; + my_vector<double> d = (_1 + _2)(v1, v2); + + suppress_unused_variable_warnings(d); + + // bitwise + + (_1 << _2)(x, y); + (_1 >> _2)(x, y); + (_1 | _2)(x, y); + (_1 & _2)(x, y); + (_1 ^ _2)(x, y); + + // comparison + + (_1 < _2)(x, y); + (_1 > _2)(x, y); + (_1 <= _2)(x, y); + (_1 >= _2)(x, y); + (_1 == _2)(x, y); + (_1 != _2)(x, y); + + // logical + + (_1 || _2)(x, y); + (_1 && _2)(x, y); + + // arithmetic assignment + (_1 += _2)(x, y); + (_1 -= _2)(x, y); + (_1 *= _2)(x, y); + (_1 /= _2)(x, y); + (_1 %= _2)(x, y); + + // bitwise assignment + (_1 <<= _2)(x, y); + (_1 >>= _2)(x, y); + (_1 |= _2)(x, y); + (_1 &= _2)(x, y); + (_1 ^= _2)(x, y); + +} + + +int test_main(int, char *[]) { + test_unary_operators(); + test_binary_operators(); + return 0; +} + + + + + + diff --git a/libs/lambda/test/is_instance_of_test.cpp b/libs/lambda/test/is_instance_of_test.cpp new file mode 100644 index 000000000..d1c57b364 --- /dev/null +++ b/libs/lambda/test/is_instance_of_test.cpp @@ -0,0 +1,79 @@ +// is_instance_of_test.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + + +#include "boost/lambda/detail/is_instance_of.hpp" + +#include <iostream> + +template <class T1> struct A1 {}; +template <class T1, class T2> struct A2 {}; +template <class T1, class T2, class T3> struct A3 {}; +template <class T1, class T2, class T3, class T4> struct A4 {}; + +class B1 : public A1<int> {}; +class B2 : public A2<int,int> {}; +class B3 : public A3<int,int,int> {}; +class B4 : public A4<int,int,int,int> {}; + +// classes that are convertible to classes that derive from A instances +// This is not enough to make the test succeed + +class C1 { public: operator A1<int>() { return A1<int>(); } }; +class C2 { public: operator B2() { return B2(); } }; +class C3 { public: operator B3() { return B3(); } }; +class C4 { public: operator B4() { return B4(); } }; + +// test that the result is really a constant +// (in an alternative implementation, gcc 3.0.2. claimed that it was +// a non-constant) +template <bool b> class X {}; +// this should compile +X<boost::lambda::is_instance_of_2<int, A2>::value> x; + + +int test_main(int, char *[]) { + +using boost::lambda::is_instance_of_1; +using boost::lambda::is_instance_of_2; +using boost::lambda::is_instance_of_3; +using boost::lambda::is_instance_of_4; + + +BOOST_CHECK((is_instance_of_1<B1, A1>::value == true)); +BOOST_CHECK((is_instance_of_1<A1<float>, A1>::value == true)); +BOOST_CHECK((is_instance_of_1<int, A1>::value == false)); +BOOST_CHECK((is_instance_of_1<C1, A1>::value == false)); + +BOOST_CHECK((is_instance_of_2<B2, A2>::value == true)); +BOOST_CHECK((is_instance_of_2<A2<int, float>, A2>::value == true)); +BOOST_CHECK((is_instance_of_2<int, A2>::value == false)); +BOOST_CHECK((is_instance_of_2<C2, A2>::value == false)); + +BOOST_CHECK((is_instance_of_3<B3, A3>::value == true)); +BOOST_CHECK((is_instance_of_3<A3<int, float, char>, A3>::value == true)); +BOOST_CHECK((is_instance_of_3<int, A3>::value == false)); +BOOST_CHECK((is_instance_of_3<C3, A3>::value == false)); + +BOOST_CHECK((is_instance_of_4<B4, A4>::value == true)); +BOOST_CHECK((is_instance_of_4<A4<int, float, char, double>, A4>::value == true)); +BOOST_CHECK((is_instance_of_4<int, A4>::value == false)); +BOOST_CHECK((is_instance_of_4<C4, A4>::value == false)); + +return 0; + +} + diff --git a/libs/lambda/test/istreambuf_test.cpp b/libs/lambda/test/istreambuf_test.cpp new file mode 100644 index 000000000..6db0842cf --- /dev/null +++ b/libs/lambda/test/istreambuf_test.cpp @@ -0,0 +1,30 @@ +// istreambuf_test - test lambda function objects with istreambuf_iterator +// +// Copyright (c) 2007 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include <boost/lambda/lambda.hpp> +#include <boost/detail/lightweight_test.hpp> +#include <iterator> +#include <sstream> +#include <algorithm> + +int main() +{ + using namespace boost::lambda; + + std::stringstream is( "ax2" ); + + std::istreambuf_iterator<char> b2( is ); + std::istreambuf_iterator<char> e2; + + std::istreambuf_iterator<char> i = std::find_if( b2, e2, _1 == 'x' ); + + BOOST_TEST( *i == 'x' ); + BOOST_TEST( std::distance( i, e2 ) == 2 ); + + return boost::report_errors(); +} diff --git a/libs/lambda/test/member_pointer_test.cpp b/libs/lambda/test/member_pointer_test.cpp new file mode 100644 index 000000000..e8121d564 --- /dev/null +++ b/libs/lambda/test/member_pointer_test.cpp @@ -0,0 +1,192 @@ +// member_pointer_test.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/bind.hpp" + +#include <string> + +using namespace boost::lambda; +using namespace std; + + +struct my_struct { +my_struct(int x) : mem(x) {}; + + int mem; + + int fooc() const { return mem; } + int foo() { return mem; } + int foo1c(int y) const { return y + mem; } + int foo1(int y) { return y + mem; } + int foo2c(int y, int x) const { return y + x + mem; } + int foo2(int y, int x) { return y + x + mem; } + int foo3c(int y, int x, int z) const { return y + x + z + mem; } + int foo3(int y, int x, int z ){ return y + x + z + mem; } + int foo4c(int a1, int a2, int a3, int a4) const { return a1+a2+a3+a4+mem; } + int foo4(int a1, int a2, int a3, int a4){ return a1+a2+a3+a4+mem; } + + int foo3default(int y = 1, int x = 2, int z = 3) { return y + x + z + mem; } +}; + +my_struct x(3); + +void pointer_to_data_member_tests() { + + // int i = 0; + my_struct *y = &x; + + BOOST_CHECK((_1 ->* &my_struct::mem)(y) == 3); + + (_1 ->* &my_struct::mem)(y) = 4; + BOOST_CHECK(x.mem == 4); + + ((_1 ->* &my_struct::mem) = 5)(y); + BOOST_CHECK(x.mem == 5); + + // &my_struct::mem is a temporary, must be constified + ((y ->* _1) = 6)(make_const(&my_struct::mem)); + BOOST_CHECK(x.mem == 6); + + ((_1 ->* _2) = 7)(y, make_const(&my_struct::mem)); + BOOST_CHECK(x.mem == 7); + +} + +void pointer_to_member_function_tests() { + + my_struct *y = new my_struct(1); + BOOST_CHECK( (_1 ->* &my_struct::foo)(y)() == (y->mem)); + BOOST_CHECK( (_1 ->* &my_struct::fooc)(y)() == (y->mem)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo))() == (y->mem)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::fooc))() == (y->mem)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo))() == (y->mem)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::fooc))() == (y->mem)); + + BOOST_CHECK( (_1 ->* &my_struct::foo1)(y)(1) == (y->mem+1)); + BOOST_CHECK( (_1 ->* &my_struct::foo1c)(y)(1) == (y->mem+1)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo1))(1) == (y->mem+1)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo1c))(1) == (y->mem+1)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo1))(1) == (y->mem+1)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo1c))(1) == (y->mem+1)); + + BOOST_CHECK( (_1 ->* &my_struct::foo2)(y)(1,2) == (y->mem+1+2)); + BOOST_CHECK( (_1 ->* &my_struct::foo2c)(y)(1,2) == (y->mem+1+2)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo2))(1,2) == (y->mem+1+2)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo2c))(1,2) == (y->mem+1+2)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo2))(1,2) == (y->mem+1+2)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo2c))(1,2) == (y->mem+1+2)); + + BOOST_CHECK( (_1 ->* &my_struct::foo3)(y)(1,2,3) == (y->mem+1+2+3)); + BOOST_CHECK( (_1 ->* &my_struct::foo3c)(y)(1,2,3) == (y->mem+1+2+3)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo3))(1,2,3) == (y->mem+1+2+3)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo3c))(1,2,3) == (y->mem+1+2+3)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo3))(1,2,3) == (y->mem+1+2+3)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo3c))(1,2,3) == (y->mem+1+2+3)); + + BOOST_CHECK( (_1 ->* &my_struct::foo4)(y)(1,2,3,4) == (y->mem+1+2+3+4)); + BOOST_CHECK( (_1 ->* &my_struct::foo4c)(y)(1,2,3,4) == (y->mem+1+2+3+4)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo4))(1,2,3,4) == (y->mem+1+2+3+4)); + BOOST_CHECK( (y ->* _1)(make_const(&my_struct::foo4c))(1,2,3,4) == (y->mem+1+2+3+4)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo4))(1,2,3,4) == (y->mem+1+2+3+4)); + BOOST_CHECK( (_1 ->* _2)(y, make_const(&my_struct::foo4c))(1,2,3,4) == (y->mem+1+2+3+4)); + + + + // member functions with default values do not work (inherent language issue) + // BOOST_CHECK( (_1 ->* &my_struct::foo3default)(y)() == (y->mem+1+2+3)); + +} + +class A {}; +class B {}; +class C {}; +class D {}; + +// ->* can be overloaded to do anything +bool operator->*(A /*a*/, B /*b*/) { + return false; +} + +bool operator->*(B /*b*/, A /*a*/) { + return true; +} + +// let's provide specializations to take care of the return type deduction. +// Note, that you need to provide all four cases for non-const and const +// or use the plain_return_type_2 template. +namespace boost { +namespace lambda { + +template <> +struct return_type_2<other_action<member_pointer_action>, B, A> { + typedef bool type; +}; + +template<> +struct return_type_2<other_action<member_pointer_action>, const B, A> { + typedef bool type; +}; + +template<> +struct return_type_2<other_action<member_pointer_action>, B, const A> { + typedef bool type; +}; + +template<> +struct return_type_2<other_action<member_pointer_action>, const B, const A> { + typedef bool type; +}; + + + + +} // lambda +} // boost + +void test_overloaded_pointer_to_member() +{ + A a; B b; + + // this won't work, can't deduce the return type + // BOOST_CHECK((_1->*_2)(a, b) == false); + + // ret<bool> gives the return type + BOOST_CHECK(ret<bool>(_1->*_2)(a, b) == false); + BOOST_CHECK(ret<bool>(a->*_1)(b) == false); + BOOST_CHECK(ret<bool>(_1->*b)(a) == false); + BOOST_CHECK((ret<bool>((var(a))->*b))() == false); + BOOST_CHECK((ret<bool>((var(a))->*var(b)))() == false); + + + // this is ok without ret<bool> due to the return_type_2 spcialization above + BOOST_CHECK((_1->*_2)(b, a) == true); + BOOST_CHECK((b->*_1)(a) == true); + BOOST_CHECK((_1->*a)(b) == true); + BOOST_CHECK((var(b)->*a)() == true); + return; +} + + +int test_main(int, char *[]) { + + pointer_to_data_member_tests(); + pointer_to_member_function_tests(); + test_overloaded_pointer_to_member(); + return 0; +} + diff --git a/libs/lambda/test/operator_tests_simple.cpp b/libs/lambda/test/operator_tests_simple.cpp new file mode 100644 index 000000000..34711fbbc --- /dev/null +++ b/libs/lambda/test/operator_tests_simple.cpp @@ -0,0 +1,431 @@ +// operator_tests_simple.cpp -- The Boost Lambda Library --------------- +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" + +#include "boost/lambda/detail/suppress_unused.hpp" + +#include <boost/shared_ptr.hpp> + +#include <vector> +#include <map> +#include <set> +#include <string> + +#include <iostream> + +#ifndef BOOST_NO_STRINGSTREAM +#include <sstream> +#endif + +using namespace std; +using namespace boost; + +using namespace boost::lambda; + + +class unary_plus_tester {}; +unary_plus_tester operator+(const unary_plus_tester& a) { return a; } + +void cout_tests() +{ +#ifndef BOOST_NO_STRINGSTREAM + using std::cout; + ostringstream os; + int i = 10; + (os << _1)(i); + + (os << constant("FOO"))(); + + BOOST_CHECK(os.str() == std::string("10FOO")); + + + istringstream is("ABC 1"); + std::string s; + int k; + + is >> s; + is >> k; + + BOOST_CHECK(s == std::string("ABC")); + BOOST_CHECK(k == 1); + // test for constant, constant_ref and var + i = 5; + constant_type<int>::type ci(constant(i)); + var_type<int>::type vi(var(i)); + + (vi = _1)(make_const(100)); + BOOST_CHECK((ci)() == 5); + BOOST_CHECK(i == 100); + + int a; + constant_ref_type<int>::type cr(constant_ref(i)); + (++vi, var(a) = cr)(); + BOOST_CHECK(i == 101); +#endif +} + +void arithmetic_operators() { + int i = 1; int j = 2; int k = 3; + + using namespace std; + using namespace boost::lambda; + + BOOST_CHECK((_1 + 1)(i)==2); + BOOST_CHECK(((_1 + 1) * _2)(i, j)==4); + BOOST_CHECK((_1 - 1)(i)==0); + + BOOST_CHECK((_1 * 2)(j)==4); + BOOST_CHECK((_1 / 2)(j)==1); + + BOOST_CHECK((_1 % 2)(k)==1); + + BOOST_CHECK((-_1)(i) == -1); + BOOST_CHECK((+_1)(i) == 1); + + // test that unary plus really does something + unary_plus_tester u; + unary_plus_tester up = (+_1)(u); + + boost::lambda::detail::suppress_unused_variable_warnings(up); +} + +void bitwise_operators() { + unsigned int ui = 2; + + BOOST_CHECK((_1 << 1)(ui)==(2 << 1)); + BOOST_CHECK((_1 >> 1)(ui)==(2 >> 1)); + + BOOST_CHECK((_1 & 1)(ui)==(2 & 1)); + BOOST_CHECK((_1 | 1)(ui)==(2 | 1)); + BOOST_CHECK((_1 ^ 1)(ui)==(2 ^ 1)); + BOOST_CHECK((~_1)(ui)==~2u); +} + +void comparison_operators() { + int i = 0, j = 1; + + BOOST_CHECK((_1 < _2)(i, j) == true); + BOOST_CHECK((_1 <= _2)(i, j) == true); + BOOST_CHECK((_1 == _2)(i, j) == false); + BOOST_CHECK((_1 != _2)(i, j) == true); + BOOST_CHECK((_1 > _2)(i, j) == false); + BOOST_CHECK((_1 >= _2)(i, j) == false); + + BOOST_CHECK((!(_1 < _2))(i, j) == false); + BOOST_CHECK((!(_1 <= _2))(i, j) == false); + BOOST_CHECK((!(_1 == _2))(i, j) == true); + BOOST_CHECK((!(_1 != _2))(i, j) == false); + BOOST_CHECK((!(_1 > _2))(i, j) == true); + BOOST_CHECK((!(_1 >= _2))(i, j) == true); +} + +void logical_operators() { + + bool t = true, f = false; + BOOST_CHECK((_1 && _2)(t, t) == true); + BOOST_CHECK((_1 && _2)(t, f) == false); + BOOST_CHECK((_1 && _2)(f, t) == false); + BOOST_CHECK((_1 && _2)(f, f) == false); + + BOOST_CHECK((_1 || _2)(t, t) == true); + BOOST_CHECK((_1 || _2)(t, f) == true); + BOOST_CHECK((_1 || _2)(f, t) == true); + BOOST_CHECK((_1 || _2)(f, f) == false); + + BOOST_CHECK((!_1)(t) == false); + BOOST_CHECK((!_1)(f) == true); + + // test short circuiting + int i=0; + + (false && ++_1)(i); + BOOST_CHECK(i==0); + i = 0; + + (true && ++_1)(i); + BOOST_CHECK(i==1); + i = 0; + + (false || ++_1)(i); + BOOST_CHECK(i==1); + i = 0; + + (true || ++_1)(i); + BOOST_CHECK(i==0); + i = 0; +} + +void unary_incs_and_decs() { + int i = 0; + + BOOST_CHECK(_1++(i) == 0); + BOOST_CHECK(i == 1); + i = 0; + + BOOST_CHECK(_1--(i) == 0); + BOOST_CHECK(i == -1); + i = 0; + + BOOST_CHECK((++_1)(i) == 1); + BOOST_CHECK(i == 1); + i = 0; + + BOOST_CHECK((--_1)(i) == -1); + BOOST_CHECK(i == -1); + i = 0; + + // the result of prefix -- and ++ are lvalues + (++_1)(i) = 10; + BOOST_CHECK(i==10); + i = 0; + + (--_1)(i) = 10; + BOOST_CHECK(i==10); + i = 0; +} + +void compound_operators() { + + int i = 1; + + // normal variable as the left operand + (i += _1)(make_const(1)); + BOOST_CHECK(i == 2); + + (i -= _1)(make_const(1)); + BOOST_CHECK(i == 1); + + (i *= _1)(make_const(10)); + BOOST_CHECK(i == 10); + + (i /= _1)(make_const(2)); + BOOST_CHECK(i == 5); + + (i %= _1)(make_const(2)); + BOOST_CHECK(i == 1); + + // lambda expression as a left operand + (_1 += 1)(i); + BOOST_CHECK(i == 2); + + (_1 -= 1)(i); + BOOST_CHECK(i == 1); + + (_1 *= 10)(i); + BOOST_CHECK(i == 10); + + (_1 /= 2)(i); + BOOST_CHECK(i == 5); + + (_1 %= 2)(i); + BOOST_CHECK(i == 1); + + // lambda expression as a left operand with rvalue on RHS + (_1 += (0 + 1))(i); + BOOST_CHECK(i == 2); + + (_1 -= (0 + 1))(i); + BOOST_CHECK(i == 1); + + (_1 *= (0 + 10))(i); + BOOST_CHECK(i == 10); + + (_1 /= (0 + 2))(i); + BOOST_CHECK(i == 5); + + (_1 %= (0 + 2))(i); + BOOST_CHECK(i == 1); + + // shifts + unsigned int ui = 2; + (_1 <<= 1)(ui); + BOOST_CHECK(ui==(2 << 1)); + + ui = 2; + (_1 >>= 1)(ui); + BOOST_CHECK(ui==(2 >> 1)); + + ui = 2; + (ui <<= _1)(make_const(1)); + BOOST_CHECK(ui==(2 << 1)); + + ui = 2; + (ui >>= _1)(make_const(1)); + BOOST_CHECK(ui==(2 >> 1)); + + // and, or, xor + ui = 2; + (_1 &= 1)(ui); + BOOST_CHECK(ui==(2 & 1)); + + ui = 2; + (_1 |= 1)(ui); + BOOST_CHECK(ui==(2 | 1)); + + ui = 2; + (_1 ^= 1)(ui); + BOOST_CHECK(ui==(2 ^ 1)); + + ui = 2; + (ui &= _1)(make_const(1)); + BOOST_CHECK(ui==(2 & 1)); + + ui = 2; + (ui |= _1)(make_const(1)); + BOOST_CHECK(ui==(2 | 1)); + + ui = 2; + (ui ^= _1)(make_const(1)); + BOOST_CHECK(ui==(2 ^ 1)); + +} + +void assignment_and_subscript() { + + // assignment and subscript need to be defined as member functions. + // Hence, if you wish to use a normal variable as the left hand argument, + // you must wrap it with var to turn it into a lambda expression + + using std::string; + string s; + + (_1 = "one")(s); + BOOST_CHECK(s == string("one")); + + (var(s) = "two")(); + BOOST_CHECK(s == string("two")); + + BOOST_CHECK((var(s)[_1])(make_const(2)) == 'o'); + BOOST_CHECK((_1[2])(s) == 'o'); + BOOST_CHECK((_1[_2])(s, make_const(2)) == 'o'); + + // subscript returns lvalue + (var(s)[_1])(make_const(1)) = 'o'; + BOOST_CHECK(s == "too"); + + (_1[1])(s) = 'a'; + BOOST_CHECK(s == "tao"); + + (_1[_2])(s, make_const(0)) = 'm'; + BOOST_CHECK(s == "mao"); + + // TODO: tests for vector, set, map, multimap +} + +class A {}; + +void address_of_and_dereference() { + + A a; int i = 42; + + BOOST_CHECK((&_1)(a) == &a); + BOOST_CHECK((*&_1)(i) == 42); + + std::vector<int> vi; vi.push_back(1); + std::vector<int>::iterator it = vi.begin(); + + (*_1 = 7)(it); + BOOST_CHECK(vi[0] == 7); + const std::vector<int>::iterator cit(it); + (*_1 = 8)(cit); + BOOST_CHECK(vi[0] == 8); + + // TODO: Add tests for more complex iterator types + + boost::shared_ptr<int> ptr(new int(0)); + (*_1 = 7)(ptr); + BOOST_CHECK(*ptr == 7); + const boost::shared_ptr<int> cptr(ptr); + (*_1 = 8)(cptr); + BOOST_CHECK(*ptr == 8); +} + + + +void comma() { + + int i = 100; + BOOST_CHECK((_1 = 10, 2 * _1)(i) == 20); + + // TODO: that the return type is the exact type of the right argument + // (that r/l valueness is preserved) + +} + +void pointer_arithmetic() { + + int ia[4] = { 1, 2, 3, 4 }; + int* ip = ia; + int* ia_last = &ia[3]; + + const int cia[4] = { 1, 2, 3, 4 }; + const int* cip = cia; + const int* cia_last = &cia[3]; + + + // non-const array + BOOST_CHECK((*(_1 + 1))(ia) == 2); + + // non-const pointer + BOOST_CHECK((*(_1 + 1))(ip) == 2); + + BOOST_CHECK((*(_1 - 1))(ia_last) == 3); + + // const array + BOOST_CHECK((*(_1 + 1))(cia) == 2); + // const pointer + BOOST_CHECK((*(_1 + 1))(cip) == 2); + BOOST_CHECK((*(_1 - 1))(cia_last) == 3); + + // pointer arithmetic should not make non-consts const + (*(_1 + 2))(ia) = 0; + (*(_1 + 3))(ip) = 0; + + BOOST_CHECK(ia[2] == 0); + BOOST_CHECK(ia[3] == 0); + + // pointer - pointer + BOOST_CHECK((_1 - _2)(ia_last, ia) == 3); + BOOST_CHECK((_1 - _2)(cia_last, cia) == 3); + BOOST_CHECK((ia_last - _1)(ia) == 3); + BOOST_CHECK((cia_last - _1)(cia) == 3); + BOOST_CHECK((cia_last - _1)(cip) == 3); + +} + +int test_main(int, char *[]) { + + arithmetic_operators(); + bitwise_operators(); + comparison_operators(); + logical_operators(); + unary_incs_and_decs(); + compound_operators(); + assignment_and_subscript(); + address_of_and_dereference(); + comma(); + pointer_arithmetic(); + cout_tests(); + return 0; +} + + + + + + diff --git a/libs/lambda/test/phoenix_control_structures.cpp b/libs/lambda/test/phoenix_control_structures.cpp new file mode 100644 index 000000000..722a74f91 --- /dev/null +++ b/libs/lambda/test/phoenix_control_structures.cpp @@ -0,0 +1,148 @@ +// phoenix_style_control_structures.cpp -- The Boost Lambda Library ------ +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/if.hpp" +#include "boost/lambda/loops.hpp" + +#include <iostream> +#include <vector> +#include <list> +#include <algorithm> +#include <cmath> +#include <cassert> +#include <functional> + + + +using namespace boost::lambda; +using namespace std; + + + +// If-else, while, do-while, for statements + + +int test_main(int, char *[]) { + + vector<int> v; + v.clear(); + v.push_back(1); + v.push_back(2); + v.push_back(3); + v.push_back(4); + v.push_back(5); + v.push_back(6); + v.push_back(7); + v.push_back(8); + v.push_back(9); + v.push_back(10); + + int sum = 0; + ////////////////////////////////// + for_each(v.begin(), v.end(), + if_(_1 > 3 && _1 <= 8) + [ + sum += _1 + ] + ); + + BOOST_CHECK(sum == 4+5+6+7+8); + + int gt = 0, eq = 0, lt = 0; + ////////////////////////////////// + for_each(v.begin(), v.end(), + if_(_1 > 5) + [ + ++var(gt) + ] + .else_ + [ + if_(_1 == 5) + [ + ++var(eq) + ] + .else_ + [ + ++var(lt) + ] + ] + ); + + BOOST_CHECK(lt==4); + BOOST_CHECK(eq==1); + BOOST_CHECK(gt==5); + + vector<int> t = v; + + int counta = 0; + int countb = 0; + ////////////////////////////////// + for_each(v.begin(), v.end(), + ( + while_(_1--) + [ + ++var(counta) + ], + ++var(countb) + ) + ); + + BOOST_CHECK(counta == 55); + BOOST_CHECK(countb == 10); + + + v = t; + + counta = 0; countb = 0; + ////////////////////////////////// + for_each(v.begin(), v.end(), + ( + do_ + [ + ++var(counta) + ] + .while_(_1--), + ++var(countb) + ) + ); + + BOOST_CHECK(counta == (2+11)*10/2); + BOOST_CHECK(countb == 10); + + + v = t; + counta = 0; countb = 0; + ////////////////////////////////// + int iii; + for_each(v.begin(), v.end(), + ( + for_(var(iii) = 0, var(iii) < _1, ++var(iii)) + [ + ++var(counta) + ], + ++var(countb) + ) + ); + + BOOST_CHECK(counta == (1+10)*10/2); + BOOST_CHECK(countb == 10); + + v = t; + + return 0; +} + diff --git a/libs/lambda/test/result_of_tests.cpp b/libs/lambda/test/result_of_tests.cpp new file mode 100644 index 000000000..c8da3297e --- /dev/null +++ b/libs/lambda/test/result_of_tests.cpp @@ -0,0 +1,314 @@ +// result_of_tests.cpp -- The Boost Lambda Library ------------------ +// +// Copyright (C) 2010 Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" +#include <boost/lambda/bind.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> + +struct with_result_type { + typedef int result_type; + int operator()() const { return 0; } + int operator()(int) const { return 1; } + int operator()(int, int) const { return 2; } + int operator()(int, int, int) const { return 3; } + int operator()(int, int, int, int) const { return 4; } + int operator()(int, int, int, int, int) const { return 5; } + int operator()(int, int, int, int, int, int) const { return 6; } + int operator()(int, int, int, int, int, int, int) const { return 7; } + int operator()(int, int, int, int, int, int, int, int) const { return 8; } + int operator()(int, int, int, int, int, int, int, int, int) const { return 9; } +}; + +struct with_result_template_value { + template<class Sig> + struct result; + template<class This> + struct result<This()> { + typedef int type; + }; + template<class This, class A1> + struct result<This(A1)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + typedef int type; + }; + template<class This, class A1, class A2> + struct result<This(A1, A2)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3> + struct result<This(A1, A2, A3)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4> + struct result<This(A1, A2, A3, A4)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5> + struct result<This(A1, A2, A3, A4, A5)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6> + struct result<This(A1, A2, A3, A4, A5, A6)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6, class A7> + struct result<This(A1, A2, A3, A4, A5, A6, A7)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int>)); + BOOST_MPL_ASSERT((boost::is_same<A7, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> + struct result<This(A1, A2, A3, A4, A5, A6, A7, A8)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int>)); + BOOST_MPL_ASSERT((boost::is_same<A7, int>)); + BOOST_MPL_ASSERT((boost::is_same<A8, int>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> + struct result<This(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int>)); + BOOST_MPL_ASSERT((boost::is_same<A7, int>)); + BOOST_MPL_ASSERT((boost::is_same<A8, int>)); + BOOST_MPL_ASSERT((boost::is_same<A9, int>)); + typedef int type; + }; + + int operator()() const { return 0; } + int operator()(int) const { return 1; } + int operator()(int, int) const { return 2; } + int operator()(int, int, int) const { return 3; } + int operator()(int, int, int, int) const { return 4; } + int operator()(int, int, int, int, int) const { return 5; } + int operator()(int, int, int, int, int, int) const { return 6; } + int operator()(int, int, int, int, int, int, int) const { return 7; } + int operator()(int, int, int, int, int, int, int, int) const { return 8; } + int operator()(int, int, int, int, int, int, int, int, int) const { return 9; } +}; + +struct with_result_template_reference { + template<class Sig> + struct result; + template<class This> + struct result<This()> { + typedef int type; + }; + template<class This, class A1> + struct result<This(A1)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + typedef int type; + }; + template<class This, class A1, class A2> + struct result<This(A1, A2)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3> + struct result<This(A1, A2, A3)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4> + struct result<This(A1, A2, A3, A4)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5> + struct result<This(A1, A2, A3, A4, A5)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6> + struct result<This(A1, A2, A3, A4, A5, A6)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6, class A7> + struct result<This(A1, A2, A3, A4, A5, A6, A7)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A7, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> + struct result<This(A1, A2, A3, A4, A5, A6, A7, A8)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A7, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A8, int&>)); + typedef int type; + }; + template<class This, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> + struct result<This(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { + BOOST_MPL_ASSERT((boost::is_same<A1, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A2, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A3, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A4, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A5, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A6, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A7, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A8, int&>)); + BOOST_MPL_ASSERT((boost::is_same<A9, int&>)); + typedef int type; + }; + + int operator()() const { return 0; } + int operator()(int) const { return 1; } + int operator()(int, int) const { return 2; } + int operator()(int, int, int) const { return 3; } + int operator()(int, int, int, int) const { return 4; } + int operator()(int, int, int, int, int) const { return 5; } + int operator()(int, int, int, int, int, int) const { return 6; } + int operator()(int, int, int, int, int, int, int) const { return 7; } + int operator()(int, int, int, int, int, int, int, int) const { return 8; } + int operator()(int, int, int, int, int, int, int, int, int) const { return 9; } +}; + +template<class F> +typename boost::result_of<F()>::type apply0(F f) { + return f(); +} +template<class A, class F> +typename boost::result_of<F(A)>::type apply1(F f, A a) { + return f(a); +} +template<class A, class B, class F> +typename boost::result_of<F(A, B)>::type apply2(F f, A a, B b) { + return f(a, b); +} +template<class A, class B, class C, class F> +typename boost::result_of<F(A, B, C)>::type apply3(F f, A a, B b, C c) { + return f(a, b, c); +} + +using namespace boost::lambda; + +int test_main(int, char *[]) { + BOOST_CHECK(boost::lambda::bind(with_result_type())() == 0); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1)() == 1); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2)() == 2); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3)() == 3); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4)() == 4); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5)() == 5); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6)() == 6); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6, 7)() == 7); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6, 7, 8)() == 8); + BOOST_CHECK(boost::lambda::bind(with_result_type(), 1, 2, 3, 4, 5, 6, 7, 8, 9)() == 9); + + // Nullary result_of fails + //BOOST_CHECK(boost::lambda::bind(with_result_template_value())() == 0); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1)() == 1); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2)() == 2); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3)() == 3); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4)() == 4); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5)() == 5); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6)() == 6); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6, 7)() == 7); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6, 7, 8)() == 8); + BOOST_CHECK(boost::lambda::bind(with_result_template_value(), 1, 2, 3, 4, 5, 6, 7, 8, 9)() == 9); + + int one = 1, + two = 2, + three = 3, + four = 4, + five = 5, + six = 6, + seven = 7, + eight = 8, + nine = 9; + + // Nullary result_of fails + //BOOST_CHECK(boost::lambda::bind(with_result_template_reference())() == 0); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one))() == 1); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two))() == 2); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three))() == 3); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four))() == 4); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five))() == 5); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six))() == 6); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six), var(seven))() == 7); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six), var(seven), var(eight))() == 8); + BOOST_CHECK(boost::lambda::bind(with_result_template_reference(), var(one), var(two), var(three), var(four), var(five), var(six), var(seven), var(eight), var(nine))() == 9); + + // Check using result_of with lambda functors + BOOST_CHECK(apply0(constant(0)) == 0); + BOOST_CHECK(apply1<int>(_1, one) == 1); + BOOST_CHECK(apply1<int&>(_1, one) == 1); + BOOST_CHECK(apply1<const int&>(_1, one) == 1); + BOOST_CHECK((apply2<int, int>(_1 + _2, one, two) == 3)); + BOOST_CHECK((apply2<int&, int&>(_1 + _2, one, two) == 3)); + BOOST_CHECK((apply2<const int&, const int&>(_1 + _2, one, two) == 3)); + BOOST_CHECK((apply3<int, int, int>(_1 + _2 + _3, one, two, three) == 6)); + BOOST_CHECK((apply3<int&, int&, int&>(_1 + _2 + _3, one, two, three) == 6)); + BOOST_CHECK((apply3<const int&, const int&, const int&>(_1 + _2 + _3, one, two, three) == 6)); + + return 0; +} diff --git a/libs/lambda/test/ret_test.cpp b/libs/lambda/test/ret_test.cpp new file mode 100644 index 000000000..82c947f04 --- /dev/null +++ b/libs/lambda/test/ret_test.cpp @@ -0,0 +1,53 @@ +// ret_test.cpp - The Boost Lambda Library ----------------------- +// +// Copyright (C) 2009 Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +#include <boost/test/minimal.hpp> + +#include <boost/lambda/lambda.hpp> + +#include <boost/mpl/assert.hpp> +#include <boost/type_traits/is_same.hpp> + +template<class R, class F> +void test_ret(R r, F f) { + typename F::result_type x = f(); + BOOST_MPL_ASSERT((boost::is_same<R, typename F::result_type>)); + BOOST_CHECK(x == r); +} + +template<class R, class F, class T1> +void test_ret(R r, F f, T1& t1) { + typename F::result_type x = f(t1); + BOOST_MPL_ASSERT((boost::is_same<R, typename F::result_type>)); + BOOST_CHECK(x == r); +} + +class add_result { +public: + add_result(int i = 0) : value(i) {} + friend bool operator==(const add_result& lhs, const add_result& rhs) { + return(lhs.value == rhs.value); + } +private: + int value; +}; + +class addable {}; +add_result operator+(addable, addable) { + return add_result(7); +} + +int test_main(int, char*[]) { + addable test; + test_ret(add_result(7), boost::lambda::ret<add_result>(boost::lambda::_1 + test), test); + test_ret(8.0, boost::lambda::ret<double>(boost::lambda::constant(7) + 1)); + + return 0; +} diff --git a/libs/lambda/test/rvalue_test.cpp b/libs/lambda/test/rvalue_test.cpp new file mode 100644 index 000000000..37351855d --- /dev/null +++ b/libs/lambda/test/rvalue_test.cpp @@ -0,0 +1,57 @@ +// rvalue_test - test lambda function objects with rvalue arguments +// +// Copyright (c) 2007 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include <boost/lambda/lambda.hpp> +#include <boost/detail/lightweight_test.hpp> + +int main() +{ + using namespace boost::lambda; + + int x = 0; + int const y = 1; + int const z = 2; + + BOOST_TEST( _1( x ) == 0 ); + BOOST_TEST( _1( y ) == 1 ); + BOOST_TEST( _1( 2 ) == 2 ); + + BOOST_TEST( _2( x, x ) == 0 ); + BOOST_TEST( _2( x, y ) == 1 ); + BOOST_TEST( _2( x, 2 ) == 2 ); + + BOOST_TEST( _2( 4, x ) == 0 ); + BOOST_TEST( _2( 4, y ) == 1 ); + BOOST_TEST( _2( 4, 2 ) == 2 ); + + (_1 = _2)( x, y ); + BOOST_TEST( x == y ); + + (_1 = _2)( x, 3 ); + BOOST_TEST( x == 3 ); + + (_2 = _1)( z, x ); + BOOST_TEST( x == z ); + + (_2 = _1)( 4, x ); + BOOST_TEST( x == 4 ); + + BOOST_TEST( _3( x, x, x ) == x ); + BOOST_TEST( _3( x, x, y ) == y ); + BOOST_TEST( _3( x, x, 2 ) == 2 ); + + BOOST_TEST( _3( x, 5, x ) == x ); + BOOST_TEST( _3( x, 5, y ) == y ); + BOOST_TEST( _3( x, 5, 2 ) == 2 ); + + BOOST_TEST( _3( 9, 5, x ) == x ); + BOOST_TEST( _3( 9, 5, y ) == y ); + BOOST_TEST( _3( 9, 5, 2 ) == 2 ); + + return boost::report_errors(); +} diff --git a/libs/lambda/test/switch_construct.cpp b/libs/lambda/test/switch_construct.cpp new file mode 100644 index 000000000..a0599fe12 --- /dev/null +++ b/libs/lambda/test/switch_construct.cpp @@ -0,0 +1,392 @@ +// switch_test.cpp -- The Boost Lambda Library -------------------------- +// +// Copyright (C) 2000-2003 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// Copyright (C) 2000-2003 Gary Powell (powellg@amazon.com) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org + +// ----------------------------------------------------------------------- + + +#include <boost/test/minimal.hpp> // see "Header Implementation Option" + + +#include "boost/lambda/lambda.hpp" +#include "boost/lambda/if.hpp" +#include "boost/lambda/switch.hpp" + +#include <iostream> +#include <algorithm> +#include <vector> +#include <string> + + + +// Check that elements 0 -- index are 1, and the rest are 0 +bool check(const std::vector<int>& v, int index) { + using namespace boost::lambda; + int counter = 0; + std::vector<int>::const_iterator + result = std::find_if(v.begin(), v.end(), + ! if_then_else_return( + var(counter)++ <= index, + _1 == 1, + _1 == 0) + ); + return result == v.end(); +} + + + +void do_switch_no_defaults_tests() { + + using namespace boost::lambda; + + int i = 0; + std::vector<int> v,w; + + // elements from 0 to 9 + std::generate_n(std::back_inserter(v), + 10, + var(i)++); + std::fill_n(std::back_inserter(w), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])) + ) + ); + + BOOST_CHECK(check(w, 0)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])) + ) + ); + + BOOST_CHECK(check(w, 1)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])) + ) + ); + + BOOST_CHECK(check(w, 2)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])) + ) + ); + + BOOST_CHECK(check(w, 3)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])) + ) + ); + + BOOST_CHECK(check(w, 4)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])) + ) + ); + + BOOST_CHECK(check(w, 5)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])), + case_statement<6>(++var(w[6])) + ) + ); + + BOOST_CHECK(check(w, 6)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])), + case_statement<6>(++var(w[6])), + case_statement<7>(++var(w[7])) + ) + ); + + BOOST_CHECK(check(w, 7)); + std::fill_n(w.begin(), 10, 0); + + // --- + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])), + case_statement<6>(++var(w[6])), + case_statement<7>(++var(w[7])), + case_statement<8>(++var(w[8])) + ) + ); + + BOOST_CHECK(check(w, 8)); + std::fill_n(w.begin(), 10, 0); + +} + + +void do_switch_yes_defaults_tests() { + + using namespace boost::lambda; + + int i = 0; + std::vector<int> v,w; + + // elements from 0 to 9 + std::generate_n(std::back_inserter(v), + 10, + var(i)++); + std::fill_n(std::back_inserter(w), 10, 0); + + int default_count; + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, -1)); + BOOST_CHECK(default_count == 10); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 0)); + BOOST_CHECK(default_count == 9); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 1)); + BOOST_CHECK(default_count == 8); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 2)); + BOOST_CHECK(default_count == 7); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 3)); + BOOST_CHECK(default_count == 6); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 4)); + BOOST_CHECK(default_count == 5); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 5)); + BOOST_CHECK(default_count == 4); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])), + case_statement<6>(++var(w[6])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 6)); + BOOST_CHECK(default_count == 3); + std::fill_n(w.begin(), 10, 0); + + // --- + default_count = 0; + std::for_each(v.begin(), v.end(), + switch_statement( + _1, + case_statement<0>(++var(w[0])), + case_statement<1>(++var(w[1])), + case_statement<2>(++var(w[2])), + case_statement<3>(++var(w[3])), + case_statement<4>(++var(w[4])), + case_statement<5>(++var(w[5])), + case_statement<6>(++var(w[6])), + case_statement<7>(++var(w[7])), + default_statement(++var(default_count)) + ) + ); + + BOOST_CHECK(check(w, 7)); + BOOST_CHECK(default_count == 2); + std::fill_n(w.begin(), 10, 0); + +} + +void test_empty_cases() { + + using namespace boost::lambda; + + // --- + switch_statement( + _1, + default_statement() + )(make_const(1)); + + switch_statement( + _1, + case_statement<1>() + )(make_const(1)); + +} + +int test_main(int, char* []) { + + do_switch_no_defaults_tests(); + do_switch_yes_defaults_tests(); + + test_empty_cases(); + + return EXIT_SUCCESS; + +} + |
