mirror of
https://github.com/boostorg/lambda.git
synced 2026-01-21 04:52:25 +00:00
Compare commits
38 Commits
svn-branch
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c7987260a | ||
|
|
95b82465e0 | ||
|
|
c5dafd3db8 | ||
|
|
fefd81ede1 | ||
|
|
a120795474 | ||
|
|
94292237b4 | ||
|
|
fbe72097b4 | ||
|
|
2f24d3f261 | ||
|
|
e057f63a54 | ||
|
|
6f32c54b5d | ||
|
|
3d659d2c3b | ||
|
|
e9721da0d0 | ||
|
|
f329a3bf68 | ||
|
|
a396be0bf6 | ||
|
|
eeb2c53b56 | ||
|
|
fcf0d30c4e | ||
|
|
d65bfa94ca | ||
|
|
2942562072 | ||
|
|
01031ccddd | ||
|
|
efdcc46d3a | ||
|
|
d60ae200a6 | ||
|
|
ff11fbb20e | ||
|
|
705c230963 | ||
|
|
cd444c824a | ||
|
|
50d9654200 | ||
|
|
937816e76e | ||
|
|
bc350d53bf | ||
|
|
34133ee940 | ||
|
|
38ffca82c9 | ||
|
|
1a2fb78541 | ||
|
|
b6d1367cec | ||
|
|
ec9ba2becf | ||
|
|
2bdf3738c1 | ||
|
|
c11fb1fe36 | ||
|
|
59ad507d3f | ||
|
|
10c4216ddc | ||
|
|
15baf78a58 | ||
|
|
f2b02864f9 |
61
doc/apa.html
Normal file
61
doc/apa.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>A. Rationale for some of the design decisions</title><meta name="generator" content="DocBook XSL Stylesheets V1.48"><link rel="home" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s09.html" title="9. Contributors"><link rel="next" href="bi01.html" title="Bibliography"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">A. Rationale for some of the design decisions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s09.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="bi01.html">Next</a></td></tr></table><hr></div><div class="appendix"><h2 class="title" style="clear: both"><a name="id2808832"></a>A. Rationale for some of the design decisions</h2><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:why_weak_arity"></a>1.
|
||||
Lambda functor arity
|
||||
</h3></div></div><p>
|
||||
The highest placeholder index in a lambda expression determines the arity of the resulting function object.
|
||||
However, this is just the minimal arity, as the function object can take arbitrarily many arguments; those not needed are discarded.
|
||||
Consider the two bind expressions and their invocations below:
|
||||
|
||||
<pre class="programlisting">
|
||||
bind(g, _3, _3, _3)(x, y, z);
|
||||
bind(g, _1, _1, _1)(x, y, z);
|
||||
</pre>
|
||||
|
||||
This first line discards arguments <tt>x</tt> and
|
||||
<tt>y</tt>, and makes the call:
|
||||
<pre class="programlisting">
|
||||
g(z, z, z)
|
||||
</pre>
|
||||
whereas the second line discards arguments <tt>y</tt> and
|
||||
<tt>z</tt>, and calls:
|
||||
<pre class="programlisting">
|
||||
g(x, x, x)
|
||||
</pre>
|
||||
In earlier versions of the library, the latter line resulted in a compile
|
||||
time error.
|
||||
|
||||
This is basically a tradeoff between safety and flexibility, and the issue
|
||||
was extensively discussed during the Boost review period of the library.
|
||||
The main points for the <span class="emphasis"><i>strict arity</i></span> checking
|
||||
was that it might
|
||||
catch a programming error at an earlier time and that a lambda expression that
|
||||
explicitly discards its arguments is easy to write:
|
||||
<pre class="programlisting">
|
||||
(_3, bind(g, _1, _1, _1))(x, y, z);
|
||||
</pre>
|
||||
This lambda expression takes three arguments.
|
||||
The left-hand argument of the comma operator does nothing, and as comma
|
||||
returns the result of evaluating the right-hand argument we end up with
|
||||
the call
|
||||
<tt>g(x, x, x)</tt>
|
||||
even with the strict arity.
|
||||
</p><p>
|
||||
The main points against the strict arity checking were that the need to
|
||||
discard arguments is commonplace, and should therefore be straightforward,
|
||||
and that strict arity checking does not really buy that much more safety,
|
||||
particularly as it is not symmetric.
|
||||
For example, if the programmer wanted to write the expression
|
||||
<tt>_1 + _2</tt> but mistakenly wrote <tt>_1 + 2</tt>,
|
||||
with strict arity checking, the complier would spot the error.
|
||||
However, if the erroneous expression was <tt>1 + _2</tt> instead,
|
||||
the error would go unnoticed.
|
||||
Furthermore, weak arity checking simplifies the implementation a bit.
|
||||
Following the recommendation of the Boost review, strict arity checking
|
||||
was dropped.
|
||||
</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s09.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="bi01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">9. Contributors </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Bibliography</td></tr></table></div></body></html>
|
||||
@@ -8,7 +8,7 @@
|
||||
The Boost Lambda Library"><link rel="previous" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="next" href="ar01s03.html" title="3. Introduction"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2. Getting Started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:getting_started"></a>2. Getting Started</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2790112"></a>2.1. Installing the library</h3></div></div><p>
|
||||
The Boost Lambda Library"><link rel="next" href="ar01s03.html" title="3. Introduction"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2. Getting Started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:getting_started"></a>2. Getting Started</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2790109"></a>2.1. Installing the library</h3></div></div><p>
|
||||
The library consists of include files only, hence there is no
|
||||
installation procedure. The <tt>boost</tt> include directory
|
||||
must be on the include path.
|
||||
@@ -20,7 +20,11 @@
|
||||
operators, see <a href="ar01s05.html#sect:operator_expressions" title="5.2. Operator expressions">Section 5.2</a>.
|
||||
</p></li><li><p>
|
||||
<tt>lambda/bind.hpp</tt> defines <tt>bind</tt> functions for up to 9 arguments, see <a href="ar01s05.html#sect:bind_expressions" title="5.3. Bind expressions">Section 5.3</a>.</p></li><li><p>
|
||||
<tt>lambda/control_constructs.hpp</tt> defines lambda function equivalents for the control constructs in C++, see <a href="ar01s05.html#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a> (includes <tt>lambda.hpp</tt>).
|
||||
<tt>lambda/if.hpp</tt> defines lambda function equivalents for if statements and the conditional operator, see <a href="ar01s05.html#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a> (includes <tt>lambda.hpp</tt>).
|
||||
</p></li><li><p>
|
||||
<tt>lambda/loops.hpp</tt> defines lambda function equivalent for looping constructs, see <a href="ar01s05.html#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a>.
|
||||
</p></li><li><p>
|
||||
<tt>lambda/switch.hpp</tt> defines lambda function equivalent for the switch statement, see <a href="ar01s05.html#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a>.
|
||||
</p></li><li><p>
|
||||
<tt>lambda/construct.hpp</tt> provides tools for writing lambda expressions with constructor, destructor, new and delete invocations, see <a href="ar01s05.html#sect:construction_and_destruction" title="5.8. Construction and destruction">Section 5.8</a> (includes <tt>lambda.hpp</tt>).
|
||||
</p></li><li><p>
|
||||
@@ -32,7 +36,7 @@ Cast expressions
|
||||
exceptions within lambda functions, <a href="ar01s05.html#sect:exceptions" title="5.7. Exceptions">Section 5.7</a> (includes
|
||||
<tt>lambda.hpp</tt>).
|
||||
</p></li><li><p>
|
||||
<tt>lambda/algorithm.hpp</tt> allows nested STL algorithm invocations, see <a href="ar01s05.html#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>.
|
||||
<tt>lambda/algorithm.hpp</tt> and <tt>lambda/numeric.hpp</tt> (cf. standard <tt>algortihm</tt> and <tt>numeric</tt> headers) allow nested STL algorithm invocations, see <a href="ar01s05.html#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>.
|
||||
</p></li></ul></div>
|
||||
|
||||
Any other header files in the package are for internal use.
|
||||
@@ -40,7 +44,7 @@ Cast expressions
|
||||
<span class="emphasis"><i>Tuple</i></span> [<a href="bi01.html#cit:boost::tuple" title="[tuple]">tuple</a>] and the <span class="emphasis"><i>type_traits</i></span> [<a href="bi01.html#cit:boost::type_traits" title="[type_traits]">type_traits</a>] libraries, and on the <tt>boost/ref.hpp</tt> header.
|
||||
</p><p>
|
||||
All definitions are placed in the namespace <tt>boost::lambda</tt> and its subnamespaces.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2742926"></a>2.2. Conventions used in this document</h3></div></div><p>In most code examples, we omit the namespace prefixes for names in the <tt>std</tt> and <tt>boost::lambda</tt> namespaces.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2741935"></a>2.2. Conventions used in this document</h3></div></div><p>In most code examples, we omit the namespace prefixes for names in the <tt>std</tt> and <tt>boost::lambda</tt> namespaces.
|
||||
Implicit using declarations
|
||||
<pre class="programlisting">
|
||||
using namespace std;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s02.html" title="2. Getting Started"><link rel="next" href="ar01s04.html" title="4. Using the library"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2742973"></a>3. Introduction</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2742980"></a>3.1. Motivation</h3></div></div><p>The Standard Template Library (STL)
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s02.html" title="2. Getting Started"><link rel="next" href="ar01s04.html" title="4. Using the library"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">3. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2741982"></a>3. Introduction</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2741989"></a>3.1. Motivation</h3></div></div><p>The Standard Template Library (STL)
|
||||
[<a href="bi01.html#cit:stepanov:94" title="[STL94]">STL94</a>], now part of the C++ Standard Library [<a href="bi01.html#cit:c++:98" title="[C++98]">C++98</a>], is a generic container and algorithm library.
|
||||
Typically STL algorithms operate on container elements via <span class="emphasis"><i>function objects</i></span>. These function objects are passed as arguments to the algorithms.
|
||||
</p><p>
|
||||
@@ -34,7 +34,7 @@ class plus_1 {
|
||||
int _i;
|
||||
public:
|
||||
plus_1(const int& i) : _i(i) {}
|
||||
int operator(const int& j) { return i + j; }
|
||||
int operator()(const int& j) { return _i + j; }
|
||||
};
|
||||
</pre>
|
||||
|
||||
@@ -105,7 +105,7 @@ as function composition is supported implicitly.
|
||||
|
||||
</p></li></ul></div>
|
||||
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2741408"></a>3.2. Introduction to lambda expressions</h3></div></div><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2742784"></a>3.2. Introduction to lambda expressions</h3></div></div><p>
|
||||
Lambda expression are common in functional programming languages.
|
||||
Their syntax varies between languages (and between different forms of lambda calculus), but the basic form of a lambda expressions is:
|
||||
|
||||
@@ -133,15 +133,19 @@ Applying the lambda function means substituting the formal parameters with the a
|
||||
|
||||
|
||||
</p><p>
|
||||
In the C++ version of lambda expressions the <tt>lambda x<sub>1</sub> ... x<sub>n</sub></tt> part is missing and the formal parameters have predefined names.
|
||||
There are three such predefined formal parameters, called <span class="emphasis"><i>placeholders</i></span>: <tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
|
||||
They refer to the first, second and third argument of the function defined by the lambda expression.
|
||||
For example, the C++ version of the definition
|
||||
<pre class="programlisting">lambda x y.x+y</pre>
|
||||
is
|
||||
|
||||
<pre class="programlisting">_1 + _2</pre>
|
||||
</p><p>
|
||||
In the C++ version of lambda expressions the <tt>lambda x<sub>1</sub> ... x<sub>n</sub></tt> part is missing and the formal parameters have predefined names.
|
||||
In the current version of the library,
|
||||
there are three such predefined formal parameters,
|
||||
called <span class="emphasis"><i>placeholders</i></span>:
|
||||
<tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
|
||||
They refer to the first, second and third argument of the function defined
|
||||
by the lambda expression.
|
||||
|
||||
For example, the C++ version of the definition
|
||||
<pre class="programlisting">lambda x y.x+y</pre>
|
||||
is
|
||||
<pre class="programlisting">_1 + _2</pre>
|
||||
</p><p>
|
||||
Hence, there is no syntactic keyword for C++ lambda expressions.
|
||||
The use of a placeholder as an operand implies that the operator invocation is a lambda expression.
|
||||
However, this is true only for operator invocations.
|
||||
@@ -165,16 +169,7 @@ A bind expression is in effect a <span class="emphasis"><i>partial function appl
|
||||
In partial function application, some of the arguments of a function are bound to fixed values.
|
||||
The result is another function, with possibly fewer arguments.
|
||||
When called with the unbound arguments, this new function invokes the original function with the merged argument list of bound and unbound arguments.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:currying_intro"></a>3.2.2. Currying</h4></div></div><p>
|
||||
A related concept to partial function application is <span class="emphasis"><i>currying</i></span>.
|
||||
Any function of n arguments can be considered
|
||||
as a function of one argument which returns another function of n-1 arguments.
|
||||
Taking the above function application example, and considering the lambda expression as a curried function, the application sequence becomes:
|
||||
<pre class="programlisting">
|
||||
(lambda x y.x+y) 2 3 = (lambda y.2+y) 3 = 2 + 3 = 5
|
||||
</pre>
|
||||
The <a href="ar01s05.html#sect:currying" title="5.1.1. Currying">Section 5.1.1</a> describes how currying is supported in BLL.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:terminology"></a>3.2.3. Terminology</h4></div></div><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:terminology"></a>3.2.2. Terminology</h4></div></div><p>
|
||||
A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, <span class="emphasis"><i>a functor</i></span>, when evaluated. We use the name <span class="emphasis"><i>lambda functor</i></span> to refer to such a function object.
|
||||
Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor.
|
||||
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">2. Getting Started </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4. Using the library</td></tr></table></div></body></html>
|
||||
|
||||
@@ -20,7 +20,7 @@ There are quite a lot of exceptions and special cases, but discussion of them is
|
||||
list<int> v(10);
|
||||
for_each(v.begin(), v.end(), _1 = 1);</pre>
|
||||
|
||||
The expression <tt>_1 = 1</tt> creates a lambda functor which assigns the value <tt>1</tt> to every element in <tt>v</tt>.<sup>[<a name="id2739690" href="#ftn.id2739690">1</a>]</sup>
|
||||
The expression <tt>_1 = 1</tt> creates a lambda functor which assigns the value <tt>1</tt> to every element in <tt>v</tt>.<sup>[<a name="id2739587" href="#ftn.id2739587">1</a>]</sup>
|
||||
</p><p>
|
||||
Next, we create a container of pointers and make them point to the elements in the first container <tt>v</tt>:
|
||||
|
||||
@@ -60,7 +60,7 @@ For instance, if the previous example is rewritten as
|
||||
for_each(vp.begin(), vp.end(), cout << '\n' << *_1);
|
||||
</pre>
|
||||
the subexpression <tt>cout << '\n'</tt> is evaluated immediately and the effect is to output a single line break, followed by the elements of <tt>vp</tt>.
|
||||
The BLL provides functions <tt>constant</tt> and <tt>var</tt> to turn constants and, resepectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions:
|
||||
The BLL provides functions <tt>constant</tt> and <tt>var</tt> to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions:
|
||||
<pre class="programlisting">
|
||||
for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);
|
||||
</pre>
|
||||
@@ -115,37 +115,86 @@ int i = 1; int j = 2;
|
||||
|
||||
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:storing_bound_arguments"></a>4.4. Storing bound arguments in lambda functions</h3></div></div><p>
|
||||
The lambda function stores the bound arguments in a tuple object [<a href="bi01.html#cit:boost::tuple" title="[tuple]">tuple</a>].
|
||||
By default, temporary const copies of the arguments are stored.
|
||||
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:
|
||||
|
||||
By default, temporary const copies of the bound arguments are stored
|
||||
in the lambda functor.
|
||||
|
||||
This means that the value of a bound argument is fixed at the time of the
|
||||
creation of the lambda function and remains constant during the lifetime
|
||||
of the lambda function object.
|
||||
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int i = 1;
|
||||
(_1 + i)(i = 2);
|
||||
</pre>
|
||||
|
||||
The value of the expression in the last line is 3, not 4.
|
||||
In other words, the lambda expression <tt>_1 + i</tt> creates a lambda function <tt>lambda x.x+1</tt> rather than <tt>lambda x.x+i</tt>.
|
||||
</p><p>As said, this is the default behavior for which there are exceptions.
|
||||
The exact rules are as follows:
|
||||
The value of the expression in the last line is 3, not 4.
|
||||
|
||||
In other words, the lambda expression <tt>_1 + i</tt> creates
|
||||
a lambda function <tt>lambda x.x+1</tt> rather than
|
||||
<tt>lambda x.x+i</tt>.
|
||||
|
||||
</p><p>
|
||||
|
||||
As said, this is the default behavior for which there are exceptions.
|
||||
The exact rules are as follows:
|
||||
|
||||
<div class="itemizedlist"><ul type="disc"><li><p>
|
||||
The programmer can control the storing mechanism with <tt>ref</tt> and <tt>cref</tt> wrappers [<a href="bi01.html#cit:boost::ref" title="[ref]">ref</a>].
|
||||
Wrapping an argument with <tt>ref</tt>, or <tt>cref</tt>, instructs the library to store the argument as a reference, or as a reference to const respectively.
|
||||
|
||||
For example, if we rewrite the previous example and wrap the variable <tt>i</tt> with <tt>ref</tt>, we are creating the lambda expression <tt>lambda x.x+i</tt> and the value of the expression in the last line will be 4:
|
||||
The programmer can control the storing mechanism with <tt>ref</tt>
|
||||
and <tt>cref</tt> wrappers [<a href="bi01.html#cit:boost::ref" title="[ref]">ref</a>].
|
||||
|
||||
Wrapping an argument with <tt>ref</tt>, or <tt>cref</tt>,
|
||||
instructs the library to store the argument as a reference,
|
||||
or as a reference to const respectively.
|
||||
|
||||
For example, if we rewrite the previous example and wrap the variable
|
||||
<tt>i</tt> with <tt>ref</tt>,
|
||||
we are creating the lambda expression <tt>lambda x.x+i</tt>
|
||||
and the value of the expression in the last line will be 4:
|
||||
|
||||
<pre class="programlisting">
|
||||
i = 1;
|
||||
(_1 + ref(i))(i = 2);
|
||||
</pre>
|
||||
|
||||
Note that <tt>ref</tt> and <tt>cref</tt> are different
|
||||
from <tt>var</tt> and <tt>constant</tt>.
|
||||
|
||||
While the latter ones create lambda functors, the former do not.
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int i;
|
||||
var(i) = 1; // ok
|
||||
ref(i) = 1; // not ok, ref(i) is not a lambda functor
|
||||
</pre>
|
||||
|
||||
The functions <tt>ref</tt> and <tt>cref</tt> mostly
|
||||
exist for historical reasons,
|
||||
and <tt>ref</tt> can always
|
||||
be replaced with <tt>var</tt>, and <tt>cref</tt> with
|
||||
<tt>constant_ref</tt>.
|
||||
See <a href="ar01s05.html#sect:delaying_constants_and_variables" title="5.5. Delaying constants and variables">Section 5.5</a> for details.
|
||||
The <tt>ref</tt> and <tt>cref</tt> functions are
|
||||
general purpose utility functions in Boost, and hence defined directly
|
||||
in the <tt>boost</tt> namespace.
|
||||
|
||||
</p></li><li><p>
|
||||
Array types cannot be copied, they are thus stored as const reference by default.
|
||||
</p></li><li><p>
|
||||
For some expressions, it makes more sense to store the arguments as references.
|
||||
For example, the obvious intention of the lambda expression <tt>i += _1</tt> is that calls to the lambda functor affect the value of the variable <tt>i</tt>, rather than some temporary copy of it.
|
||||
As another example, the streaming operators take their leftmost argument as non-const references.
|
||||
For some expressions it makes more sense to store the arguments as references.
|
||||
|
||||
For example, the obvious intention of the lambda expression
|
||||
<tt>i += _1</tt> is that calls to the lambda functor affect the
|
||||
value of the variable <tt>i</tt>,
|
||||
rather than some temporary copy of it.
|
||||
|
||||
As another example, the streaming operators take their leftmost argument
|
||||
as non-const references.
|
||||
|
||||
The exact rules are:
|
||||
|
||||
<div class="itemizedlist"><ul type="round"><li><p>The left argument of compound assignment operators (<tt>+=</tt>, <tt>*=</tt>, etc.) are stored as references to non-const.</p></li><li><p>If the left argument of <tt><<</tt> or <tt>>></tt> operator is derived from an instantiation of <tt>basic_ostream</tt> or respectively from <tt>basic_istream</tt>, the argument is stored as a reference to non-const.
|
||||
@@ -157,7 +206,7 @@ This is to prevent pointer arithmetic making non-const arrays const.
|
||||
</p></li></ul></div>
|
||||
|
||||
</p></li></ul></div>
|
||||
</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id2739690" href="#id2739690">1</a>] </sup>
|
||||
</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id2739587" href="#id2739587">1</a>] </sup>
|
||||
Strictly taken, the C++ standard defines <tt>for_each</tt> as a <span class="emphasis"><i>non-modifying sequence operation</i></span>, and the function object passed to <tt>for_each</tt> should not modify its argument.
|
||||
The requirements for the arguments of <tt>for_each</tt> are unnecessary strict, since as long as the iterators are <span class="emphasis"><i>mutable</i></span>, <tt>for_each</tt> accepts a function object that can have side-effects on their argument.
|
||||
Nevertheless, it is straightforward to provide another function template with the functionality of<tt>std::for_each</tt> but more fine-grained requirements for its arguments.
|
||||
|
||||
620
doc/ar01s05.html
620
doc/ar01s05.html
@@ -10,7 +10,6 @@ This section describes different categories of lambda expressions in details.
|
||||
We devote a separate section for each of the possible forms of a lambda expression.
|
||||
|
||||
|
||||
|
||||
</p><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:placeholders"></a>5.1. Placeholders</h3></div></div><p>
|
||||
The BLL defines three placeholder types: <tt>placeholder1_type</tt>, <tt>placeholder2_type</tt> and <tt>placeholder3_type</tt>.
|
||||
BLL has a predefined placeholder variable for each placeholder type: <tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
|
||||
@@ -39,6 +38,24 @@ _3 + 10 // 3-ary
|
||||
|
||||
Note that the last line creates a 3-ary function, which adds <tt>10</tt> to its <span class="emphasis"><i>third</i></span> argument.
|
||||
The first two arguments are discarded.
|
||||
Furthermore, lambda functors only have a minimum arity.
|
||||
One can always provide more arguments (up the number of supported placeholders)
|
||||
that is really needed.
|
||||
The remaining arguments are just discarded.
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int i, j, k;
|
||||
_1(i, j, k) // returns i, discards j and k
|
||||
(_2 + _2)(i, j, k) // returns j+j, discards i and k
|
||||
</pre>
|
||||
|
||||
See
|
||||
<a href="apa.html#sect:why_weak_arity" title="1.
|
||||
Lambda functor arity
|
||||
">Section 1</a> for the design rationale behind this
|
||||
functionality.
|
||||
|
||||
</p><p>
|
||||
In addition to these three placeholder types, there is also a fourth placeholder type <tt>placeholderE_type</tt>.
|
||||
The use of this placeholder is defined in <a href="ar01s05.html#sect:exceptions" title="5.7. Exceptions">Section 5.7</a> describing exception handling in lambda expressions.
|
||||
@@ -52,27 +69,7 @@ int i = 1;
|
||||
(_1 += 2)(i); // i is now 3
|
||||
(++_1, cout << _1)(i) // i is now 4, outputs 4
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that placeholder objects do not define the function call operator.
|
||||
So strictly speaking, they are not lambda expressions, as evaluating a placeholder does not create a callable lambda functor.
|
||||
Creating an identity functor is however straightforward, for example: <tt>0, _1</tt> serves for this purpose.
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:currying"></a>5.1.1. Currying</h4></div></div><p>Lambda functors support currying, that is, calling functions with one argument at a time.
|
||||
If too few arguments are provided for a lambda functor, another lambda functor with a lower arity results.
|
||||
When all arguments are provided, the original lambda functor is called.
|
||||
For example, the last four lines below all have the same functionality; each of them ends up calling <tt>i + j + k</tt>:
|
||||
|
||||
<pre class="programlisting">
|
||||
int i, j, k;
|
||||
(_1 + _2 + _3)(i, j, k);
|
||||
(_1 + _2 + _3)(i)(j)(k);
|
||||
(_1 + _2 + _3)(i, j)(k);
|
||||
(_1 + _2 + _3)(i)(j, k);
|
||||
</pre>
|
||||
</p><p>
|
||||
A curried lambda functor just stores the arguments that are provided.
|
||||
No subexpressions of the original lambda expression are evaluated, even though this might seem possible.
|
||||
E.g., in the expression <tt>(_1 * _1 + _2)(i)</tt>, the subexpression <tt>i * i</tt> is not evaluated, rather its evaluation is postponed until the actual argument for <tt>_2</tt> is available too.
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:operator_expressions"></a>5.2. Operator expressions</h3></div></div><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:operator_expressions"></a>5.2. Operator expressions</h3></div></div><p>
|
||||
The basic rule is that any C++ operator invocation with at least one argument being a lambda expression is itself a lambda expression.
|
||||
Almost all overloadable operators are supported.
|
||||
For example, the following is a valid lambda expression:
|
||||
@@ -80,8 +77,9 @@ For example, the following is a valid lambda expression:
|
||||
<pre class="programlisting">cout << _1, _2[_3] = _1 && false</pre>
|
||||
</p><p>
|
||||
However, there are some restrictions that originate from the C++ operator overloading rules, and some special cases.
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2740698"></a>5.2.1. Operators that cannot be overloaded</h4></div></div><p>
|
||||
Some operators cannot be overloaded at all, or their overloading rules prevent them to be overloaded to create lambda functors.
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2740636"></a>5.2.1. Operators that cannot be overloaded</h4></div></div><p>
|
||||
Some operators cannot be overloaded at all (<tt>::</tt>, <tt>.</tt>, <tt>.*</tt>).
|
||||
For some operators, the requirements on return types prevent them to be overloaded to create lambda functors.
|
||||
These operators are <tt>->.</tt>, <tt>-></tt>, <tt>new</tt>, <tt>new[]</tt>, <tt>delete</tt>, <tt>delete[]</tt> and <tt>?:</tt> (the conditional operator).
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:assignment_and_subscript"></a>5.2.2. Assignment and subscript operators</h4></div></div><p>
|
||||
These operators must be implemented as class members.
|
||||
@@ -119,14 +117,14 @@ Without the extra parenthesis around <tt>++_1, cout << _1</tt>, the code w
|
||||
The lambda functor created by the comma operator adheres to the C++ rule of always evaluating the left operand before the right one.
|
||||
In the above example, each element of <tt>a</tt> is first incremented, then written to the stream.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_call_operator"></a>5.2.5. Function call operator</h4></div></div><p>
|
||||
A lambda functor of arity n defines the n-ary function call operator, which evaluates the functor.
|
||||
Function call operators of arities between 1 and n-1 are defined to support curried calls (see currying, <a href="ar01s05.html#sect:currying" title="5.1.1. Currying">Section 5.1.1</a>).
|
||||
Note that placeholders do not define the function call operator.
|
||||
The function call operators have the effect of evaluating the lambda
|
||||
functor.
|
||||
Calls with too few arguments lead to a compile time error.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:member_pointer_operator"></a>5.2.6. Member pointer operator</h4></div></div><p>
|
||||
The member pointer operator <tt>operator->*</tt> can be overloaded freely.
|
||||
Hence, for user defined types, member pointer operator is no special case.
|
||||
The built-in meaning, however, is a somewhat more complicated case.
|
||||
The built-in member pointer operator is applied, if the left argument is a pointer to an object of some class <tt>A</tt>, and the right hand argument is a pointer to a member of <tt>A</tt>, or a pointer to a member of a class from which <tt>A</tt> derives.
|
||||
The built-in member pointer operator is applied if the left argument is a pointer to an object of some class <tt>A</tt>, and the right hand argument is a pointer to a member of <tt>A</tt>, or a pointer to a member of a class from which <tt>A</tt> derives.
|
||||
We must separate two cases:
|
||||
|
||||
<div class="itemizedlist"><ul type="disc"><li><p>The right hand argument is a pointer to a data member.
|
||||
@@ -181,7 +179,7 @@ The return type of the lambda functor created by the bind expression can be give
|
||||
<pre class="programlisting">
|
||||
bind<<span class="emphasis"><i>RET</i></span>>(<span class="emphasis"><i>target-function</i></span>, <span class="emphasis"><i>bind-argument-list</i></span>)
|
||||
</pre>
|
||||
This is only necessary, if the return type of the target function cannot be deduced.
|
||||
This is only necessary if the return type of the target function cannot be deduced.
|
||||
</p><p>
|
||||
The following sections describe the different types of bind expressions.
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_pointers_as_targets"></a>5.3.1. Function pointers or references as targets</h4></div></div><p>The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example:
|
||||
@@ -195,7 +193,7 @@ bind(_1, a, b, c)(foo);
|
||||
The return type deduction always succeeds with this type of bind expressions.
|
||||
</p><p>
|
||||
Note, that in C++ it is possible to take the address of an overloaded function only if the address is assigned to, or used as an initializer of, a variable, the type of which solves the amibiguity, or if an explicit cast expression is used.
|
||||
This means, that overloaded functions cannot be used in bind expressions directly, e.g.:
|
||||
This means that overloaded functions cannot be used in bind expressions directly, e.g.:
|
||||
<pre class="programlisting">
|
||||
void foo(int);
|
||||
void foo(float);
|
||||
@@ -224,7 +222,7 @@ find_if(ints.begin(), ints.end(), bind(&A::foo, a, _1));
|
||||
find_if(ints.begin(), ints.end(), bind(&A::foo, &a, _1));
|
||||
</pre>
|
||||
|
||||
Similarly, if the object argument is unbound, the resulting binder object can be called both via a pointer or a reference:
|
||||
Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference:
|
||||
|
||||
<pre class="programlisting">
|
||||
bool A::foo(int);
|
||||
@@ -238,15 +236,16 @@ find_if(pointers.begin(), pointers.end(), bind(&A::foo, _1, 1));
|
||||
</p><p>
|
||||
Even though the interfaces are the same, there are important semantic differences between using a pointer or a reference as the object argument.
|
||||
The differences stem from the way <tt>bind</tt>-functions take their parameters, and how the bound parameters are stored within the lambda functor.
|
||||
The object argument has the same parameter passing and storing mechanism than any other bind argument slot (see <a href="ar01s04.html#sect:storing_bound_arguments" title="4.4. Storing bound arguments in lambda functions">Section 4.4</a>); it is passed as a const reference and stored as a const copy in the lambda functor.
|
||||
The object argument has the same parameter passing and storing mechanism as any other bind argument slot (see <a href="ar01s04.html#sect:storing_bound_arguments" title="4.4. Storing bound arguments in lambda functions">Section 4.4</a>); it is passed as a const reference and stored as a const copy in the lambda functor.
|
||||
This creates some asymmetry between the lambda functor and the original member function, and between seemingly similar lambda functors. For example:
|
||||
<pre class="programlisting">
|
||||
class A {
|
||||
int i; mutable int j;
|
||||
public:
|
||||
|
||||
A(int ii, int jj) : i(ii), j(jj) {};
|
||||
void set_i(int x) { i = x; };
|
||||
void set_j(int x) { j = x; };
|
||||
void set_j(int x) const { j = x; };
|
||||
};
|
||||
</pre>
|
||||
|
||||
@@ -269,62 +268,90 @@ bind(&A::set_i, a, _1)(k); // error; a const copy of a is stored.
|
||||
bind(&A::set_j, a, _1)(k); // a.j == 0, as a copy of a is modified
|
||||
</pre>
|
||||
</p><p>
|
||||
To prevent the copying from taking place, one can use the <tt>ref</tt> or <tt>cref</tt> wrappers:
|
||||
To prevent the copying from taking place, one can use the <tt>ref</tt> or <tt>cref</tt> wrappers (<tt>var</tt> and <tt>constant_ref</tt> would do as well):
|
||||
<pre class="programlisting">
|
||||
bind(&A::set_i, ref(a), _1)(k); // a.j == 1
|
||||
bind(&A::set_j, cref(a), _1)(k); // a.j == 1
|
||||
</pre>
|
||||
</p><p>Note that the preceding discussion is relevant only for bound arguments.
|
||||
If the object argument is unbound, the parameter passing mode is always by reference.
|
||||
Hence, no copying occurs for the actual arguments of the lambda functor:
|
||||
Hence, the argument <tt>a</tt> is not copied in the calls to the two lambda functors below:
|
||||
<pre class="programlisting">
|
||||
A a(0,0);
|
||||
bind(&A::set_i, _1, 1)(a); // a.i == 1
|
||||
bind(&A::set_j, _1, 1)(a); // a.j == 1
|
||||
</pre>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_objects_as_targets"></a>5.3.3. Function objects as targets</h4></div></div><p>Function objects, that is, class objects which have the function call operator defined, can be used as target functions.
|
||||
In general, BLL cannot deduce the return type of an arbitrary function object.
|
||||
However, there are two ways to give BLL this capability for a certain function object class.
|
||||
</p><div class="simplesect"><div class="titlepage"><div><h5 class="title"><a name="id2803148"></a>The result_type typedef</h5></div></div><p>
|
||||
The BLL recognizes the typedef <tt>result_type</tt> in the function object, and uses that as the return type of the function call operator.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:members_variables_as_targets"></a>5.3.3. Member variables as targets</h4></div></div><p>
|
||||
A pointer to a member variable is not really a function, but
|
||||
the first argument to the <tt>bind</tt> function can nevertheless
|
||||
be a pointer to a member variable.
|
||||
Invoking such a bind expression returns a reference to the data member.
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
struct A { int data; };
|
||||
A a;
|
||||
bind(&A::data, _1)(a) = 1; // a.data == 1
|
||||
</pre>
|
||||
|
||||
The cv-qualifiers of the object whose member is accessed are respected.
|
||||
For example, the following tries to write into a const location:
|
||||
<pre class="programlisting">
|
||||
const A ca = a;
|
||||
bind(&A::data, _1)(ca) = 1; // error
|
||||
</pre>
|
||||
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_objects_as_targets"></a>5.3.4. Function objects as targets</h4></div></div><p>
|
||||
|
||||
Function objects, that is, class objects which have the function call
|
||||
operator defined, can be used as target functions.
|
||||
|
||||
In general, BLL cannot deduce the return type of an arbitrary function object.
|
||||
|
||||
However, there is a method for giving BLL this capability for a certain
|
||||
function object class.
|
||||
|
||||
</p><div class="simplesect"><div class="titlepage"><div><h5 class="title"><a name="id2803238"></a>The sig template</h5></div></div><p>
|
||||
To make BLL aware of the return type(s) of a function object one needs to
|
||||
provide a member template struct
|
||||
<tt>sig<Args></tt> with a typedef
|
||||
<tt>type</tt> that specifies the return type.
|
||||
|
||||
Here is a simple example:
|
||||
<pre class="programlisting">
|
||||
struct A {
|
||||
typedef B result_type;
|
||||
template <class Args> struct sig { typedef B type; }
|
||||
B operator()(X, Y, Z);
|
||||
};
|
||||
</pre>
|
||||
|
||||
Function objects in the standard library adhere to this convention.
|
||||
</p><p>
|
||||
There are two significant restrictions with this scheme:
|
||||
The template argument <tt>Args</tt> is a
|
||||
<tt>tuple</tt> (or more precisely a <tt>cons</tt> list)
|
||||
type [<a href="bi01.html#cit:boost::tuple" title="[tuple]">tuple</a>], where the first element
|
||||
is the function
|
||||
object type itself, and the remaining elements are the types of
|
||||
the arguments, with which the function object is being called.
|
||||
|
||||
This may seem overly complex compared to the Standard Library
|
||||
convention for defining the return type of a function
|
||||
object with the <tt>return_type</tt> typedef.
|
||||
Howver, there are two significant restrictions with using just a simple
|
||||
typedef to express the return type:
|
||||
<div class="orderedlist"><ol type="1"><li><p>
|
||||
If the function object defines several function call operators, there is no way to specify different result types for them.
|
||||
</p></li><li><p>
|
||||
If the function call operator is a template, the result type may depend on the template parameters.
|
||||
Hence, the typedef ought to be a template too, which the C++ language does not support.
|
||||
</p></li></ol></div>
|
||||
</p></div><div class="simplesect"><div class="titlepage"><div><h5 class="title"><a name="id2803217"></a>The sig template</h5></div></div><p>
|
||||
The second method is slightly more complex, but also more flexible.
|
||||
The steps that need to be taken to make BLL aware of the return type(s) of a function object are:
|
||||
|
||||
<div class="orderedlist"><ol type="1"><li><p>
|
||||
Make the function object class derive from <tt>has_sig</tt> class.
|
||||
(This is a technical requirement that is needed to let the two mechanisms for specifying the return type coexist.)
|
||||
</p></li><li><p>Provide a member template struct <tt>sig<Args></tt> with a typedef <tt>type</tt> that specifies the result type of the function call operator of the function object class.
|
||||
The template argument <tt>Args</tt> is a <tt>tuple</tt> (or more precisely a <tt>cons</tt> list) type, 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.
|
||||
Note that the elements of the <tt>Args</tt> tuple are always reference types.
|
||||
Moreover, the types referenced can have a const or volatile qualifier, or both.
|
||||
Also, there is no distinction between rvalues and const lvalues, that is, if the actual argument to the function call operator is an rvalue of type <tt>T</tt>, the corresponding argument in the <tt>Args</tt> tuple is <tt>const T&</tt>.
|
||||
|
||||
If the function call operator is a template, the result type may
|
||||
depend on the template parameters.
|
||||
Hence, the typedef ought to be a template too, which the C++ language
|
||||
does not support.
|
||||
</p></li></ol></div>
|
||||
|
||||
This convention does not suffer from the same restrictions than using a plain typedef:
|
||||
return types for templated and/or overloaded function call operators can be specified.
|
||||
For example:
|
||||
The following code shows an example, where the return type depends on the type
|
||||
of one of the arguments, and how that dependency can be expressed with the
|
||||
<tt>sig</tt> template:
|
||||
|
||||
<pre class="programlisting">
|
||||
struct A : public has_sig {
|
||||
struct A {
|
||||
|
||||
// the return type equals the third argument type:
|
||||
template<class T1, T2, T3>
|
||||
@@ -334,21 +361,60 @@ struct A : public has_sig {
|
||||
class sig {
|
||||
// get the third argument type (4th element)
|
||||
typedef typename
|
||||
boost::tuples::get<3, Args>::type T3;
|
||||
typedef typename
|
||||
boost::remove_reference<T3>::type T3_non_ref;
|
||||
boost::tuples::element<3, Args>::type T3;
|
||||
public:
|
||||
typedef typename
|
||||
boost::remove_const<T3_non_ref>::type type;
|
||||
boost::remove_cv<T3>::type type;
|
||||
}
|
||||
};
|
||||
</pre>
|
||||
|
||||
The <tt>sig</tt> template is a <span class="emphasis"><i>meta-function</i></span> that maps the argument type tuple to the result type.
|
||||
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, removing references etc.
|
||||
See the Boost type_traits Library for tools that can aid in these tasks.
|
||||
</p></div></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:overriding_deduced_return_type"></a>5.4. Overriding the deduced return type</h3></div></div><p>
|
||||
|
||||
The elements of the <tt>Args</tt> tuple are always
|
||||
non-reference types.
|
||||
|
||||
Moreover, the element types can have a const or volatile qualifier
|
||||
(jointly referred to as <span class="emphasis"><i>cv-qualifiers</i></span>), or both.
|
||||
This is since the cv-qualifiers in the arguments can affect the return type.
|
||||
The reason for including the potentially cv-qualified function object
|
||||
type itself into the <tt>Args</tt> tuple, is that the function
|
||||
object class can contain both const and non-const (or volatile, even
|
||||
const volatile) function call operators, and they can each have a different
|
||||
return type.
|
||||
</p><p>
|
||||
The <tt>sig</tt> template can be seen as a
|
||||
<span class="emphasis"><i>meta-function</i></span> that maps the argument type tuple to
|
||||
the result type of the call made with arguments of the types in the tuple.
|
||||
|
||||
As the example above demonstrates, the template can end up being somewhat
|
||||
complex.
|
||||
Typical tasks to be performed are the extraction of the relevant types
|
||||
from the tuple, removing cv-qualifiers etc.
|
||||
See the Boost type_traits [<a href="bi01.html#cit:boost::type_traits" title="[type_traits]">type_traits</a>] and
|
||||
Tuple [<a href="bi01.html#cit:boost::type_traits" title="[type_traits]">type_traits</a>] libraries
|
||||
for tools that can aid in these tasks.
|
||||
The <tt>sig</tt> templates are a refined version of a similar
|
||||
mechanism first introduced in the FC++ library
|
||||
[<a href="bi01.html#cit:fc++" title="[fc++]">fc++</a>].
|
||||
</p></div><p>
|
||||
Earlier versions of the library supported the Standard Library convention
|
||||
as the default, and required special actions to make the library recognize
|
||||
the <tt>sig</tt> template.
|
||||
Now the BLL has that reversed.
|
||||
|
||||
If one needs to use a functor that adheres to the Standard Library
|
||||
convention in a bind expression, we provide the <tt>std_functor</tt>
|
||||
wrapper, that gives the function object a <tt>sig</tt>
|
||||
template based on the <tt>result_type</tt> typedef.
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int i = 1;
|
||||
bind(plus<int>(), _1, 1)(i); // error, no sig template
|
||||
bind(std_functor(plus<int>()), _1, 1)(i); // ok
|
||||
</pre>
|
||||
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:overriding_deduced_return_type"></a>5.4. Overriding the deduced return type</h3></div></div><p>
|
||||
The return type deduction system may not be able to deduce the return types of some user defined operators or bind expressions with class objects.
|
||||
|
||||
A special lambda expression type is provided for stating the return type explicitly and overriding the deduction system.
|
||||
@@ -370,21 +436,22 @@ ret<C>(_1 + _2)(a, b); // ok
|
||||
ret<float>(_1 * _2)(a, b); // ok (int can be converted to float)
|
||||
...
|
||||
struct X {
|
||||
typedef Y result_type;
|
||||
Y operator()(); // #1
|
||||
Z operator(int)(); // #2
|
||||
Y operator(int)();
|
||||
};
|
||||
...
|
||||
X x; int i;
|
||||
bind(x)(); // ok, call #1
|
||||
bind(x, _1)(i); // try to call #2: error, deduction gives Y
|
||||
ret<Z>(bind(x, _1))(i); // ok, call #2
|
||||
bind(x, _1)(i); // error, return type cannot be deduced
|
||||
ret<Y>(bind(x, _1))(i); // ok
|
||||
</pre>
|
||||
For bind expressions, there is a short-hand notation that can be used instead of <tt>ret</tt>.
|
||||
The last line could alternatively be written as:
|
||||
|
||||
<pre class="programlisting">bind<Z>(x, _1)(i);</pre>
|
||||
</p><p>Note that within nested lambda expressions, the <tt>ret</tt> must be used at each invocation where the deduction would otherwise fail.
|
||||
This feature is modeled after the Boost Bind library [<a href="bi01.html#cit:boost::bind" title="[bind]">bind</a>].
|
||||
|
||||
</p><p>Note that within nested lambda expressions,
|
||||
the <tt>ret</tt> must be used at each subexpression where
|
||||
the deduction would otherwise fail.
|
||||
For example:
|
||||
<pre class="programlisting">
|
||||
A a; B b;
|
||||
@@ -423,8 +490,9 @@ The lambda functors created with
|
||||
<tt>bind<<i><tt>T</tt></i>>(<i><tt>arg-list</tt></i>)</tt> have the exact same functionality —
|
||||
apart from the fact that for some nullary lambda functors the former does not work while the latter does.
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:delaying_constants_and_variables"></a>5.5. Delaying constants and variables</h3></div></div><p>
|
||||
The unary functions <tt>constant</tt> and <tt>var</tt> turn their argument into a lambda functor, that implements an identity mapping.
|
||||
The former is for constants, the latter for variables.
|
||||
The unary functions <tt>constant</tt>,
|
||||
<tt>constant_ref</tt> and <tt>var</tt> turn their argument into a lambda functor, that implements an identity mapping.
|
||||
The former two are for constants, the latter for variables.
|
||||
The use of these <span class="emphasis"><i>delayed</i></span> constants and variables is sometimes necessary due to the lack of explicit syntax for lambda expressions.
|
||||
For example:
|
||||
<pre class="programlisting">
|
||||
@@ -441,8 +509,13 @@ This is accomplished with the <tt>constant</tt> function:
|
||||
for_each(a.begin(), a.end(), cout << constant(' ') << _1);
|
||||
</pre>
|
||||
|
||||
The call <tt>constant(' ')</tt> creates a nullary lambda functor which stores the character constant <tt>' '</tt> and returns a reference to it when invoked.
|
||||
The <tt>constant</tt> is only needed when the operator call has side effects, like in the above example.
|
||||
The call <tt>constant(' ')</tt> creates a nullary lambda functor which stores the character constant <tt>' '</tt>
|
||||
and returns a reference to it when invoked.
|
||||
The function <tt>constant_ref</tt> is similar, except that it
|
||||
stores a constant reference to its argument.
|
||||
|
||||
The <tt>constant</tt> and <tt>consant_ref</tt> are only
|
||||
needed when the operator call has side effects, like in the above example.
|
||||
</p><p>
|
||||
Sometimes we need to delay the evaluation of a variable.
|
||||
Suppose we wanted to output the elements of a container in a numbered list:
|
||||
@@ -455,13 +528,15 @@ for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1
|
||||
|
||||
The first <tt>for_each</tt> invocation does not do what we want; <tt>index</tt> is incremented only once, and its value is written into the output stream only once.
|
||||
By using <tt>var</tt> to make <tt>index</tt> a lambda expression, we get the desired effect.
|
||||
|
||||
</p><p>
|
||||
In sum, <tt>var(x)</tt> creates a nullary lambda functor,
|
||||
which stores a reference to the variable <tt>x</tt>.
|
||||
When the lambda functor is invoked, a reference to <tt>x</tt> is returned.
|
||||
</p><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2803927"></a>Naming delayed constants and variables</h4></div></div><p>
|
||||
</p><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2804083"></a>Naming delayed constants and variables</h4></div></div><p>
|
||||
It is possible to predefine and name a delayed variable or constant outside a lambda expression.
|
||||
The templates <tt>var_type</tt> and <tt>constant_type</tt> serve for this purpose.
|
||||
The templates <tt>var_type</tt>, <tt>constant_type</tt>
|
||||
and <tt>constant_ref_type</tt> serve for this purpose.
|
||||
They are used as:
|
||||
<pre class="programlisting">
|
||||
var_type<T>::type delayed_i(var(i));
|
||||
@@ -487,7 +562,7 @@ Here is an example of naming a delayed constant:
|
||||
constant_type<char>::type space(constant(' '));
|
||||
for_each(a.begin(),a.end(), cout << space << _1);
|
||||
</pre>
|
||||
</p></div><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2804044"></a>About assignment and subscript operators</h4></div></div><p>
|
||||
</p></div><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2804207"></a>About assignment and subscript operators</h4></div></div><p>
|
||||
As described in <a href="ar01s05.html#sect:assignment_and_subscript" title="5.2.2. Assignment and subscript operators">Section 5.2.2</a>, assignment and subscripting operators are always defined as member functions.
|
||||
This means, that for expressions of the form
|
||||
<tt>x = y</tt> or <tt>x[y]</tt> to be interpreted as lambda expressions, the left-hand operand <tt>x</tt> must be a lambda expression.
|
||||
@@ -519,6 +594,7 @@ The BLL supports the following function templates for control structures:
|
||||
<pre class="programlisting">
|
||||
if_then(condition, then_part)
|
||||
if_then_else(condition, then_part, else_part)
|
||||
if_then_else_return(condition, then_part, else_part)
|
||||
while_loop(condition, body)
|
||||
while_loop(condition) // no body case
|
||||
do_while_loop(condition, body)
|
||||
@@ -527,6 +603,21 @@ for_loop(init, condition, increment, body)
|
||||
for_loop(init, condition, increment) // no body case
|
||||
switch_statement(...)
|
||||
</pre>
|
||||
|
||||
The return types of all control construct lambda functor is
|
||||
<tt>void</tt>, except for <tt>if_then_else_return</tt>,
|
||||
which wraps a call to the conditional operator
|
||||
<pre class="programlisting">
|
||||
condition ? then_part : else_part
|
||||
</pre>
|
||||
The return type rules for this operator are somewhat complex.
|
||||
Basically, if the branches have the same type, this type is the return type.
|
||||
If the type of the branches differ, one branch, say of type
|
||||
<tt>A</tt>, must be convertible to the other branch,
|
||||
say of type <tt>B</tt>.
|
||||
In this situation, the result type is <tt>B</tt>.
|
||||
Further, if the common type is an lvalue, the return type will be an lvalue
|
||||
too.
|
||||
</p><p>
|
||||
Delayed variables tend to be commonplace in control structure lambda expressions.
|
||||
For instance, here we use the <tt>var</tt> function to turn the arguments of <tt>for_loop</tt> into lambda expressions.
|
||||
@@ -540,6 +631,29 @@ for_each(a, a+5,
|
||||
</pre>
|
||||
|
||||
|
||||
</p><p>
|
||||
The BLL supports an alternative syntax for control expressions, suggested
|
||||
by Joel de Guzmann.
|
||||
By overloading the <tt>operator[]</tt> we can
|
||||
get a closer resemblance with the built-in control structures.
|
||||
For example, using this syntax the <tt>if_then</tt> example above
|
||||
can be written as:
|
||||
<pre class="programlisting">
|
||||
for_each(a.begin(), a.end(),
|
||||
if(_1 % 2 == 0)[ cout << _1 ])
|
||||
</pre>
|
||||
|
||||
<pre class="programlisting">
|
||||
if_(condition)[then_part]
|
||||
if_(condition)[then_part].else_[else_part]
|
||||
while_(condition)[body]
|
||||
do_[body].while_(condition)
|
||||
for_(init, condition, increment)[body]
|
||||
</pre>
|
||||
|
||||
As more experience is gained, we may end up deprecating one or the other
|
||||
of these syntaces.
|
||||
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:switch_statement"></a>5.6.1. Switch statement</h4></div></div></div><p>
|
||||
The lambda expressions for <tt>switch</tt> control structures are more complex since the number of cases may vary.
|
||||
The general form of a switch lambda expression is:
|
||||
@@ -603,10 +717,16 @@ try_catch(
|
||||
</pre>
|
||||
|
||||
The first lambda expression is the try block.
|
||||
Each <tt>catch_exception</tt> defines a catch block where the explicitly specified template argument defines the type of the exception to catch.
|
||||
The lambda expression within the <tt>catch_exception</tt> defines the actions to take if the exception is caught.
|
||||
Note that the resulting exception handlers catch the exceptions as references, i.e.,
|
||||
<tt>catch_exception<T>(...)</tt> results in the catch block:
|
||||
Each <tt>catch_exception</tt> defines a catch block where the
|
||||
explicitly specified template argument defines the type of the exception
|
||||
to catch.
|
||||
|
||||
The lambda expression within the <tt>catch_exception</tt> defines
|
||||
the actions to take if the exception is caught.
|
||||
|
||||
Note that the resulting exception handlers catch the exceptions as
|
||||
references, i.e., <tt>catch_exception<T>(...)</tt>
|
||||
results in the catch block:
|
||||
|
||||
<pre class="programlisting">
|
||||
catch(T& e) { ... }
|
||||
@@ -620,24 +740,38 @@ or to
|
||||
|
||||
</p><p>
|
||||
|
||||
The <a href="ar01s05.html#ex:exceptions" title="Example 1. Throwing and handling exceptions in lambda expressions.">Example 1</a>. demonstrates the use of the BLL exception handling tools.
|
||||
The <a href="ar01s05.html#ex:exceptions" title="Example 1. Throwing and handling exceptions in lambda expressions.">Example 1</a> demonstrates the use of the BLL
|
||||
exception handling tools.
|
||||
The first handler catches exceptions of type <tt>foo_exception</tt>.
|
||||
Note the use of <tt>_1</tt> placeholder in the body of the handler.
|
||||
</p><p>
|
||||
The second handler shows how to throw exceptions, and demonstrates the use of the <span class="emphasis"><i>exception placeholder</i></span> <tt>_E</tt>.
|
||||
It is a special placeholder, which refers to the caught exception object within the handler body.
|
||||
Here we are handling an exception of type <tt>std::exception</tt>, which carries a string explaining the cause of the exception.
|
||||
This explanation can be queried with the zero-argument member function <tt>what</tt>.
|
||||
The second handler shows how to throw exceptions, and demonstrates the
|
||||
use of the <span class="emphasis"><i>exception placeholder</i></span> <tt>_e</tt>.
|
||||
|
||||
It is a special placeholder, which refers to the caught exception object
|
||||
within the handler body.
|
||||
|
||||
Here we are handling an exception of type <tt>std::exception</tt>,
|
||||
which carries a string explaining the cause of the exception.
|
||||
|
||||
This explanation can be queried with the zero-argument member
|
||||
function <tt>what</tt>.
|
||||
|
||||
The expression
|
||||
<tt>bind(&std::exception::what, _E)</tt> creates the lambda function for making that call.
|
||||
<tt>bind(&std::exception::what, _e)</tt> creates the lambda
|
||||
function for making that call.
|
||||
|
||||
Note that <tt>_E</tt> is not a full-fledged placeholder, but rather a special case of <tt>_3</tt>.
|
||||
As a consequence, <tt>_E</tt> cannot be used outside of an exception handler lambda expression, and <tt>_3</tt> cannot be used inside of an exception handler lambda expression.
|
||||
Violating this rule is caught by the compiler.
|
||||
Note that <tt>_e</tt> cannot be used outside of an exception handler lambda expression.
|
||||
|
||||
The last line of the second handler constructs a new exception object and throws that with <tt>throw exception</tt>. Constructing and destructing objects within lambda expressions is explained in <a href="ar01s05.html#sect:construction_and_destruction" title="5.8. Construction and destruction">Section 5.8</a>
|
||||
|
||||
The last line of the second handler constructs a new exception object and
|
||||
throws that with <tt>throw exception</tt>.
|
||||
|
||||
Constructing and destructing objects within lambda expressions is
|
||||
explained in <a href="ar01s05.html#sect:construction_and_destruction" title="5.8. Construction and destruction">Section 5.8</a>
|
||||
</p><p>
|
||||
Finally, the third handler (<tt>catch_all</tt>) demonstrates rethrowing exceptions.
|
||||
Finally, the third handler (<tt>catch_all</tt>) demonstrates
|
||||
rethrowing exceptions.
|
||||
</p><div class="example"><p><a name="ex:exceptions"></a><b>Example 1. Throwing and handling exceptions in lambda expressions.</b></p><pre class="programlisting">
|
||||
for_each(
|
||||
a.begin(), a.end(),
|
||||
@@ -649,7 +783,7 @@ for_each(
|
||||
),
|
||||
catch_exception<std::exception>(
|
||||
cout << constant("Caught std::exception: ")
|
||||
<< bind(&std::exception::what, _E),
|
||||
<< bind(&std::exception::what, _e),
|
||||
throw_exception(bind(constructor<bar_exception>(), _1)))
|
||||
),
|
||||
catch_all(
|
||||
@@ -657,13 +791,25 @@ for_each(
|
||||
)
|
||||
)
|
||||
);
|
||||
</pre></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:construction_and_destruction"></a>5.8. Construction and destruction</h3></div></div></div><p>
|
||||
Operators <tt>new</tt> and <tt>delete</tt> can be overloaded, but their return types are fixed.
|
||||
Particularly, the return types cannot be lambda functors, which prevents them to be overloaded for lambda expressions.
|
||||
It is not possible to take the address of a constructor, hence constructors cannot be used as target functions in bind expressions.
|
||||
</pre></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:construction_and_destruction"></a>5.8. Construction and destruction</h3></div></div><p>
|
||||
Operators <tt>new</tt> and <tt>delete</tt> can be
|
||||
overloaded, but their return types are fixed.
|
||||
|
||||
Particularly, the return types cannot be lambda functors,
|
||||
which prevents them to be overloaded for lambda expressions.
|
||||
|
||||
It is not possible to take the address of a constructor,
|
||||
hence constructors cannot be used as target functions in bind expressions.
|
||||
|
||||
The same is true for destructors.
|
||||
As a way around these constraints, BLL defines wrapper classes for <tt>new</tt> and <tt>delete</tt> calls, as well as for constructors and destructors.
|
||||
Instances of these classes are function objects, that can be used as target functions of bind expressions.
|
||||
|
||||
As a way around these constraints, BLL defines wrapper classes for
|
||||
<tt>new</tt> and <tt>delete</tt> calls,
|
||||
as well as for constructors and destructors.
|
||||
|
||||
Instances of these classes are function objects, that can be used as
|
||||
target functions of bind expressions.
|
||||
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
@@ -672,12 +818,25 @@ for_each(a, a+10, _1 = bind(new_ptr<int>()));
|
||||
for_each(a, a+10, bind(delete_ptr(), _1));
|
||||
</pre>
|
||||
|
||||
The <tt>new_ptr<int>()</tt> expression creates a function object that calls <tt>new int()</tt> when invoked, and wrapping that inside <tt>bind</tt> makes it a lambda functor.
|
||||
In the same way, the expression <tt>delete_ptr()</tt> creates a function object that invokes <tt>delete</tt> on its argument.
|
||||
Note that <tt>new_ptr<<i><tt>T</tt></i>>()</tt> can take arguments as well.
|
||||
They are passed directly to the constructor invocation and thus allow calls to constructors which take arguments.
|
||||
The <tt>new_ptr<int>()</tt> expression creates
|
||||
a function object that calls <tt>new int()</tt> when invoked,
|
||||
and wrapping that inside <tt>bind</tt> makes it a lambda functor.
|
||||
|
||||
In the same way, the expression <tt>delete_ptr()</tt> creates
|
||||
a function object that invokes <tt>delete</tt> on its argument.
|
||||
|
||||
Note that <tt>new_ptr<<i><tt>T</tt></i>>()</tt>
|
||||
can take arguments as well.
|
||||
|
||||
They are passed directly to the constructor invocation and thus allow
|
||||
calls to constructors which take arguments.
|
||||
|
||||
</p><p>
|
||||
As an example of constructor calls in lambda expressions, the following code reads integers from two containers <tt>x</tt> and <tt>y</tt>, constructs pairs out of them and inserts them into a third container:
|
||||
|
||||
As an example of constructor calls in lambda expressions,
|
||||
the following code reads integers from two containers <tt>x</tt>
|
||||
and <tt>y</tt>,
|
||||
constructs pairs out of them and inserts them into a third container:
|
||||
|
||||
<pre class="programlisting">
|
||||
vector<pair<int, int> > v;
|
||||
@@ -685,15 +844,21 @@ transform(x.begin(), x.end(), y.begin(), back_inserter(v),
|
||||
bind(constructor<pair<int, int> >(), _1, _2));
|
||||
</pre>
|
||||
|
||||
<a href="ar01s05.html#table:constructor_destructor_fos" title="Table 1. Construction and destruction related function objects.">Table 1</a>. lists all the function objects related to creating and destroying objects, showing the expression to create and call the function object, and the effect of evaluating that expression.
|
||||
<a href="ar01s05.html#table:constructor_destructor_fos" title="Table 1. Construction and destruction related function objects.">Table 1</a> lists all the function
|
||||
objects related to creating and destroying objects,
|
||||
showing the expression to create and call the function object,
|
||||
and the effect of evaluating that expression.
|
||||
|
||||
</p><div class="table"><p><a name="table:constructor_destructor_fos"></a><b>Table 1. Construction and destruction related function objects.</b></p><table summary="Construction and destruction related function objects." border="1"><colgroup><col><col></colgroup><thead><tr><th>Function object call</th><th>Wrapped expression</th></tr></thead><tbody><tr><td><tt>constructor<T>()(<i><tt>arg_list</tt></i>)</tt></td><td>T(<i><tt>arg_list</tt></i>)</td></tr><tr><td><tt>destructor()(a)</tt></td><td><tt>a.~A()</tt>, where <tt>a</tt> is of type <tt>A</tt></td></tr><tr><td><tt>destructor()(pa)</tt></td><td><tt>pa.->A()</tt>, where <tt>pa</tt> is of type <tt>A*</tt></td></tr><tr><td><tt>new_ptr<T>()(<i><tt>arg_list</tt></i>)</tt></td><td><tt>new T(<i><tt>arg_list</tt></i>)</tt></td></tr><tr><td><tt>new_array<T>()(sz)</tt></td><td><tt>new T[sz]</tt></td></tr><tr><td><tt>delete_ptr()(p)</tt></td><td><tt>delete p</tt></td></tr><tr><td><tt>delete_array()(p)</tt></td><td><tt>delete p[]</tt></td></tr></tbody></table></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2805476"></a>5.9. Special lambda expressions</h3></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2805483"></a>5.9.1. Preventing argument substitution</h4></div></div><p>
|
||||
When a lambda functor is called, the default behavior is to substitute
|
||||
the actual arguments for the placeholders within all subexpressions.
|
||||
|
||||
|
||||
</p><div class="table"><p><a name="table:constructor_destructor_fos"></a><b>Table 1. Construction and destruction related function objects.</b></p><table summary="Construction and destruction related function objects." border="1"><colgroup><col><col></colgroup><thead><tr><th>Function object call</th><th>Wrapped expression</th></tr></thead><tbody><tr><td><tt>constructor<T>()(<i><tt>arg_list</tt></i>)</tt></td><td>T(<i><tt>arg_list</tt></i>)</td></tr><tr><td><tt>destructor()(a)</tt></td><td><tt>a.~A()</tt>, where <tt>a</tt> is of type <tt>A</tt></td></tr><tr><td><tt>destructor()(pa)</tt></td><td><tt>pa.->A()</tt>, where <tt>pa</tt> is of type <tt>A*</tt></td></tr><tr><td><tt>new_ptr<T>()(<i><tt>arg_list</tt></i>)</tt></td><td><tt>new T(<i><tt>arg_list</tt></i>)</tt></td></tr><tr><td><tt>new_array<T>()(sz)</tt></td><td><tt>new T[sz]</tt></td></tr><tr><td><tt>delete_ptr()(p)</tt></td><td><tt>delete p</tt></td></tr><tr><td><tt>delete_array()(p)</tt></td><td><tt>delete p[]</tt></td></tr></tbody></table></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2805233"></a>5.9. Special lambda expressions</h3></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2805240"></a>5.9.1. Preventing argument substitution</h4></div></div><p>
|
||||
When a lambda functor is called, the default behavior is to substitute the actual arguments for the placeholders within all subexpressions.
|
||||
This section describes the tools to prevent the substitution and evaluation of a subexpression, and explains when these tools should be used.
|
||||
This section describes the tools to prevent the substitution and
|
||||
evaluation of a subexpression, and explains when these tools should be used.
|
||||
</p><p>
|
||||
The arguments to a bind expression can be arbitrary lambda expressions, e.g., other bind expressions.
|
||||
The arguments to a bind expression can be arbitrary lambda expressions,
|
||||
e.g., other bind expressions.
|
||||
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
@@ -705,9 +870,15 @@ bind(foo, bind(bar, _1)(i);
|
||||
|
||||
The last line makes the call <tt>foo(bar(i));</tt>
|
||||
|
||||
Note that the first argument in a bind expression, the target function, is no exception, and can thus be a bind expression too.
|
||||
The innermost lambda functor just has to return something that can be used as a target function: another lambda functor, function pointer, pointer to member function etc.
|
||||
For example, in the following code the innermost lambda functor makes a selection between two functions, and returns a pointer to one of them:
|
||||
Note that the first argument in a bind expression, the target function,
|
||||
is no exception, and can thus be a bind expression too.
|
||||
|
||||
The innermost lambda functor just has to return something that can be used
|
||||
as a target function: another lambda functor, function pointer,
|
||||
pointer to member function etc.
|
||||
|
||||
For example, in the following code the innermost lambda functor makes
|
||||
a selection between two functions, and returns a pointer to one of them:
|
||||
|
||||
<pre class="programlisting">
|
||||
int add(int a, int b) { return a+b; }
|
||||
@@ -722,8 +893,13 @@ bool condition; int i; int j;
|
||||
bind(bind(&add_or_mul, _1), _2, _3)(condition, i, j);
|
||||
</pre>
|
||||
|
||||
</p><div class="section"><div class="titlepage"><div><h5 class="title"><a name="sect:unlambda"></a>5.9.1.1. Unlambda</h5></div></div><p>A nested bind expression may occur inadvertently, if the target function is a variable with a type that depends on a template parameter.
|
||||
Typically the target function could be a formal parameter of a function template.
|
||||
</p><div class="section"><div class="titlepage"><div><h5 class="title"><a name="sect:unlambda"></a>5.9.1.1. Unlambda</h5></div></div><p>A nested bind expression may occur inadvertently,
|
||||
if the target function is a variable with a type that depends on a
|
||||
template parameter.
|
||||
|
||||
Typically the target function could be a formal parameter of a
|
||||
function template.
|
||||
|
||||
In such a case, the programmer may not know whether the target function is a lambda functor or not.
|
||||
</p><p>Consider the following function template:
|
||||
|
||||
@@ -739,31 +915,56 @@ int nested(const F& f) {
|
||||
|
||||
Somewhere inside the function the formal parameter
|
||||
<tt>f</tt> is used as a target function in a bind expression.
|
||||
In order for this <tt>bind</tt> call to be valid, <tt>f</tt> must be a unary function.
|
||||
|
||||
In order for this <tt>bind</tt> call to be valid,
|
||||
<tt>f</tt> must be a unary function.
|
||||
|
||||
Suppose the following two calls to <tt>nested</tt> are made:
|
||||
|
||||
<pre class="programlisting">
|
||||
int foo(int);
|
||||
int bar(int, int);
|
||||
nested(&foo);
|
||||
nested(bind(bar, 1, _1));
|
||||
</pre>
|
||||
Both are unary functions, or function objects, with appropriate argument and return types, but the latter will not compile.
|
||||
In the latter call, the bind expression inside <tt>nested</tt> will become:
|
||||
|
||||
Both are unary functions, or function objects, with appropriate argument
|
||||
and return types, but the latter will not compile.
|
||||
|
||||
In the latter call, the bind expression inside <tt>nested</tt>
|
||||
will become:
|
||||
|
||||
<pre class="programlisting">
|
||||
bind(bind(bar, 1, _1), _1)
|
||||
</pre>
|
||||
When this is invoked with <tt>x</tt>, after substituitions we end up trying to call
|
||||
|
||||
When this is invoked with <tt>x</tt>,
|
||||
after substituitions we end up trying to call
|
||||
|
||||
<pre class="programlisting">
|
||||
bar(1, x)(x)
|
||||
</pre>
|
||||
|
||||
which is an error.
|
||||
The call to <tt>bar</tt> returns int, not a unary function or function object.
|
||||
|
||||
The call to <tt>bar</tt> returns int,
|
||||
not a unary function or function object.
|
||||
</p><p>
|
||||
In the example above, the intent of the bind expression in the <tt>nested</tt> function is to treat <tt>f</tt> as an ordinary function object, instead of a lambda functor.
|
||||
The BLL provides the function template <tt>unlambda</tt> to express this: a lambda functor wrapped inside <tt>unlambda</tt> is not a lambda functor anymore, and does not take part into the argument substitution process.
|
||||
Note that for all other argument types <tt>unlambda</tt> is an identity operation, except for making non-const objects const.
|
||||
In the example above, the intent of the bind expression in the
|
||||
<tt>nested</tt> function is to treat <tt>f</tt>
|
||||
as an ordinary function object, instead of a lambda functor.
|
||||
|
||||
The BLL provides the function template <tt>unlambda</tt> to
|
||||
express this: a lambda functor wrapped inside <tt>unlambda</tt>
|
||||
is not a lambda functor anymore, and does not take part into the
|
||||
argument substitution process.
|
||||
|
||||
Note that for all other argument types <tt>unlambda</tt> is
|
||||
an identity operation, except for making non-const objects const.
|
||||
</p><p>
|
||||
Using <tt>unlambda</tt>, the <tt>nested</tt> function is written as:
|
||||
Using <tt>unlambda</tt>, the <tt>nested</tt>
|
||||
function is written as:
|
||||
|
||||
<pre class="programlisting">
|
||||
template<class F>
|
||||
int nested(const F& f) {
|
||||
@@ -774,24 +975,40 @@ int nested(const F& f) {
|
||||
}
|
||||
</pre>
|
||||
|
||||
</p></div><div class="section"><div class="titlepage"><div><h5 class="title"><a name="id2805499"></a>5.9.1.2. Protect</h5></div></div><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h5 class="title"><a name="id2805743"></a>5.9.1.2. Protect</h5></div></div><p>
|
||||
The <tt>protect</tt> function is related to unlambda.
|
||||
It is also used to prevent the argument substitution taking place, but whereas <tt>unlambda</tt> turns a lambda functor into an ordinary function object for good, <tt>protect</tt> does this temporarily, for just one evaluation round.
|
||||
|
||||
It is also used to prevent the argument substitution taking place,
|
||||
but whereas <tt>unlambda</tt> turns a lambda functor into
|
||||
an ordinary function object for good, <tt>protect</tt> does
|
||||
this temporarily, for just one evaluation round.
|
||||
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int x = 1, y = 10;
|
||||
(_1 + protect(_1 + 2))(x)(y);
|
||||
</pre>
|
||||
|
||||
The first call substitutes <tt>x</tt> for the leftmost <tt>_1</tt>, and results in another lambda functor <tt>x + (_1 + 2)</tt>, which after the call with <tt>y</tt> becomes <tt>x + (y + 2)</tt>, and thus finally 13.
|
||||
|
||||
The first call substitutes <tt>x</tt> for the leftmost
|
||||
<tt>_1</tt>, and results in another lambda functor
|
||||
<tt>x + (_1 + 2)</tt>, which after the call with
|
||||
<tt>y</tt> becomes <tt>x + (y + 2)</tt>,
|
||||
and thus finally 13.
|
||||
</p><p>
|
||||
Primary motivation for including <tt>protect</tt> into the library, was to allow nested STL algorithm invocations (<a href="ar01s05.html#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>).
|
||||
Primary motivation for including <tt>protect</tt> into the library,
|
||||
was to allow nested STL algorithm invocations
|
||||
(<a href="ar01s05.html#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>).
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:rvalues_as_actual_arguments"></a>5.9.2. Rvalues as actual arguments to lambda functors</h4></div></div><p>
|
||||
Actual arguments to the lambda functors cannot be non-const rvalues.
|
||||
This is due to a deliberate design decision: either we have this restriction, or there can be no side-effects to the actual arguments.
|
||||
This is due to a deliberate design decision: either we have this restriction,
|
||||
or there can be no side-effects to the actual arguments.
|
||||
|
||||
There are ways around this limitation.
|
||||
We repeat the example from section <a href="ar01s04.html#sect:actual_arguments_to_lambda_functors" title="4.3. About actual arguments to lambda functors">Section 4.3</a> and list the different solutions:
|
||||
|
||||
We repeat the example from section
|
||||
<a href="ar01s04.html#sect:actual_arguments_to_lambda_functors" title="4.3. About actual arguments to lambda functors">Section 4.3</a> and list the
|
||||
different solutions:
|
||||
|
||||
<pre class="programlisting">
|
||||
int i = 1; int j = 2;
|
||||
@@ -800,27 +1017,46 @@ int i = 1; int j = 2;
|
||||
</pre>
|
||||
|
||||
<div class="orderedlist"><ol type="1"><li><p>
|
||||
If the rvalue is of a class type, the return type of the function that creates the rvalue should be defined as const. Due to an unfortunate language restriction this does not work for built-in types, as built-in rvalues cannot be const qualified. </p></li><li><p>
|
||||
If the lambda function call is accessible, the <tt>make_const</tt> function can be used to <span class="emphasis"><i>constify</i></span> the rvalue. E.g.:
|
||||
If the rvalue is of a class type, the return type of the function that
|
||||
creates the rvalue should be defined as const.
|
||||
Due to an unfortunate language restriction this does not work for
|
||||
built-in types, as built-in rvalues cannot be const qualified.
|
||||
</p></li><li><p>
|
||||
If the lambda function call is accessible, the <tt>make_const</tt>
|
||||
function can be used to <span class="emphasis"><i>constify</i></span> the rvalue. E.g.:
|
||||
|
||||
<pre class="programlisting">
|
||||
(_1 + _2)(make_const(1), make_const(2)); // ok</pre>
|
||||
<pre class="programlisting">
|
||||
(_1 + _2)(make_const(1), make_const(2)); // ok
|
||||
</pre>
|
||||
|
||||
Commonly the lambda function call site is inside a standard algorithm function template, preventing this solution to be used.
|
||||
Commonly the lambda function call site is inside a standard algorithm
|
||||
function template, preventing this solution to be used.
|
||||
|
||||
</p></li><li><p>
|
||||
If neither of the above is possible, the lambda expression can be wrapped in a <tt>const_parameters</tt> function.
|
||||
It creates another type of lambda functor, which takes its arguments as const references. For example:
|
||||
</p></li><li><p>
|
||||
If neither of the above is possible, the lambda expression can be wrapped
|
||||
in a <tt>const_parameters</tt> function.
|
||||
It creates another type of lambda functor, which takes its arguments as
|
||||
const references. For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
const_parameters(_1 + _2)(1, 2); // ok
|
||||
</pre>
|
||||
|
||||
Note that <tt>const_parameters</tt> makes all arguments const.
|
||||
Hence, in the case were one of the arguments is a non-const rvalue, and another argument needs to be passed as a non-const reference, this approach cannot be used.
|
||||
</p></li><li><p>If none of the above is possible, there is still one solution, which unfortunately can break const correctness.
|
||||
The solution is yet another lambda functor wrapper, which we have named <tt>break_const</tt> to alert the user of the potential dangers of this function.
|
||||
The <tt>break_const</tt> function creates a lambda functor that takes its arguments as const, and casts away constness prior to the call to the original wrapped lambda functor.
|
||||
Hence, in the case were one of the arguments is a non-const rvalue,
|
||||
and another argument needs to be passed as a non-const reference,
|
||||
this approach cannot be used.
|
||||
</p></li><li><p>If none of the above is possible, there is still one solution,
|
||||
which unfortunately can break const correctness.
|
||||
|
||||
The solution is yet another lambda functor wrapper, which we have named
|
||||
<tt>break_const</tt> to alert the user of the potential dangers
|
||||
of this function.
|
||||
|
||||
The <tt>break_const</tt> function creates a lambda functor that
|
||||
takes its arguments as const, and casts away constness prior to the call
|
||||
to the original wrapped lambda functor.
|
||||
|
||||
For example:
|
||||
<pre class="programlisting">
|
||||
int i;
|
||||
@@ -830,25 +1066,38 @@ const_parameters(_1 += _2)(i, 2); // error, i becomes const
|
||||
break_const(_1 += _2)(i, 2); // ok, but dangerous
|
||||
</pre>
|
||||
|
||||
Note, that the results of
|
||||
<tt> break_const</tt> or <tt>const_parameters</tt> are not lambda functors, so they cannot be used as subexpressions of lambda expressions. For instance:
|
||||
Note, that the results of <tt> break_const</tt> or
|
||||
<tt>const_parameters</tt> are not lambda functors,
|
||||
so they cannot be used as subexpressions of lambda expressions. For instance:
|
||||
|
||||
<pre class="programlisting">
|
||||
break_const(_1 + _2) + _3; // fails.
|
||||
const_parameters(_1 + _2) + _3; // fails.
|
||||
</pre>
|
||||
|
||||
However, this kind of code should never be necessary, since calls to sub lambda functors are made inside the BLL, and are not affected by the non-const rvalue problem.
|
||||
</p></li></ol></div>
|
||||
However, this kind of code should never be necessary,
|
||||
since calls to sub lambda functors are made inside the BLL,
|
||||
and are not affected by the non-const rvalue problem.
|
||||
</p></li></ol></div>
|
||||
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2805803"></a>5.10. Casts, sizeof and typeid</h3></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:cast_expressions"></a>5.10.1.
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2806049"></a>5.10. Casts, sizeof and typeid</h3></div></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:cast_expressions"></a>5.10.1.
|
||||
Cast expressions
|
||||
</h4></div></div><p>
|
||||
The BLL defines its counterparts for the four cast expressions <tt>static_cast</tt>, <tt>dynamic_cast</tt>, <tt>const_cast</tt> and <tt>reinterpret_cast</tt>.
|
||||
The BLL versions of the cast expressions have the prefix <tt>ll_</tt>.
|
||||
The type to cast to is given as an explicitly specified template argument, and the sole argument is the expression from which to perform the cast.
|
||||
The BLL defines its counterparts for the four cast expressions
|
||||
<tt>static_cast</tt>, <tt>dynamic_cast</tt>,
|
||||
<tt>const_cast</tt> and <tt>reinterpret_cast</tt>.
|
||||
|
||||
The BLL versions of the cast expressions have the prefix
|
||||
<tt>ll_</tt>.
|
||||
|
||||
The type to cast to is given as an explicitly specified template argument,
|
||||
and the sole argument is the expression from which to perform the cast.
|
||||
|
||||
If the argument is a lambda functor, the lambda functor is evaluated first.
|
||||
For example, the following code uses <tt>ll_dynamic_cast</tt> to count the number of <tt>derived</tt> instances in the container <tt>a</tt>:
|
||||
|
||||
For example, the following code uses <tt>ll_dynamic_cast</tt>
|
||||
to count the number of <tt>derived</tt> instances in the container
|
||||
<tt>a</tt>:
|
||||
|
||||
<pre class="programlisting">
|
||||
class base {};
|
||||
@@ -860,10 +1109,15 @@ int count = 0;
|
||||
for_each(a.begin(), a.end(),
|
||||
if_then(ll_dynamic_cast<derived*>(_1), ++var(count)));
|
||||
</pre>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2805904"></a>5.10.2. Sizeof and typeid</h4></div></div><p>
|
||||
The BLL counterparts for these expressions are named <tt>ll_sizeof</tt> and <tt>ll_typeid</tt>.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2806151"></a>5.10.2. Sizeof and typeid</h4></div></div><p>
|
||||
The BLL counterparts for these expressions are named
|
||||
<tt>ll_sizeof</tt> and <tt>ll_typeid</tt>.
|
||||
|
||||
Both take one argument, which can be a lambda expression.
|
||||
The lambda functor created wraps the <tt>sizeof</tt> or <tt>typeid</tt> call, and when the lambda functor is called the wrapped operation is performed.
|
||||
The lambda functor created wraps the <tt>sizeof</tt> or
|
||||
<tt>typeid</tt> call, and when the lambda functor is called
|
||||
the wrapped operation is performed.
|
||||
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
@@ -873,12 +1127,19 @@ for_each(a.begin(), a.end(),
|
||||
cout << bind(&type_info::name, ll_typeid(*_1)));
|
||||
</pre>
|
||||
|
||||
Here <tt>ll_typeid</tt> creates a lambda functor for calling <tt>typeid</tt> for each element.
|
||||
The result of a <tt>typeid</tt> call is an instance of the <tt>type_info</tt> class, and the bind expression creates a lambda functor for calling the <tt>name</tt> member function of that class.
|
||||
Here <tt>ll_typeid</tt> creates a lambda functor for
|
||||
calling <tt>typeid</tt> for each element.
|
||||
|
||||
The result of a <tt>typeid</tt> call is an instance of
|
||||
the <tt>type_info</tt> class, and the bind expression creates
|
||||
a lambda functor for calling the <tt>name</tt> member
|
||||
function of that class.
|
||||
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:nested_stl_algorithms"></a>5.11. Nesting STL algorithm invocations</h3></div></div><p>
|
||||
The BLL defines common STL algorithms as function object classes, instances of which can be used as target functions in bind expressions.
|
||||
For example, the following code iterates over the elements of a two-dimensional array, and computes their sum.
|
||||
The BLL defines common STL algorithms as function object classes,
|
||||
instances of which can be used as target functions in bind expressions.
|
||||
For example, the following code iterates over the elements of a
|
||||
two-dimensional array, and computes their sum.
|
||||
|
||||
<pre class="programlisting">
|
||||
int a[100][200];
|
||||
@@ -890,10 +1151,15 @@ std::for_each(a, a + 100,
|
||||
|
||||
The BLL versions of the STL algorithms are classes, which define the function call operator (or several overloaded ones) to call the corresponding function templates in the <tt>std</tt> namespace.
|
||||
All these structs are placed in the subnamespace <tt>boost::lambda:ll</tt>.
|
||||
The supported algorithms are listed in <a href="ar01s05.html#table:nested_algorithms" title="Table 2. The nested STL algorithms.">Table 2</a>.
|
||||
|
||||
</p><p>
|
||||
Note that there is no easy way to express an overloaded member function call in a lambda expression.
|
||||
This limits the usefulness of nested STL algorithms, as for instance the <tt>begin</tt> function has more than one overloaded definitions in container templates.
|
||||
Note that there is no easy way to express an overloaded member function
|
||||
call in a lambda expression.
|
||||
|
||||
This limits the usefulness of nested STL algorithms, as for instance
|
||||
the <tt>begin</tt> function has more than one overloaded
|
||||
definitions in container templates.
|
||||
|
||||
In general, something analogous to the pseudo-code below cannot be written:
|
||||
|
||||
<pre class="programlisting">
|
||||
@@ -902,7 +1168,13 @@ std::for_each(a.begin(), a.end(),
|
||||
</pre>
|
||||
|
||||
Some aid for common special cases can be provided though.
|
||||
The BLL defines two helper function object classes, <tt>call_begin</tt> and <tt>call_end</tt>, which wrap a call to the <tt>begin</tt> and, respectively, <tt>end</tt> functions of a container, and return the <tt>const_iterator</tt> type of the container.
|
||||
|
||||
The BLL defines two helper function object classes,
|
||||
<tt>call_begin</tt> and <tt>call_end</tt>,
|
||||
which wrap a call to the <tt>begin</tt> and, respectively,
|
||||
<tt>end</tt> functions of a container, and return the
|
||||
<tt>const_iterator</tt> type of the container.
|
||||
|
||||
With these helper templates, the above code becomes:
|
||||
<pre class="programlisting">
|
||||
std::for_each(a.begin(), a.end(),
|
||||
@@ -911,4 +1183,4 @@ std::for_each(a.begin(), a.end(),
|
||||
protect(sum += _1)));
|
||||
</pre>
|
||||
|
||||
</p><div class="table"><p><a name="table:nested_algorithms"></a><b>Table 2. The nested STL algorithms.</b></p><table summary="The nested STL algorithms." border="1"><colgroup><col></colgroup><thead></thead><tbody><tr><td><tt>for_each</tt></td></tr><tr><td><tt>find</tt></td></tr><tr><td><tt>find_if</tt></td></tr><tr><td><tt>find_end</tt></td></tr><tr><td><tt>find_first_of</tt></td></tr><tr><td><tt>transform</tt></td></tr></tbody></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4. Using the library </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 6. Extending return type deduction system</td></tr></table></div></body></html>
|
||||
</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4. Using the library </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 6. Extending return type deduction system</td></tr></table></div></body></html>
|
||||
|
||||
155
doc/ar01s06.html
155
doc/ar01s06.html
@@ -7,52 +7,108 @@
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s05.html" title="5. Lambda expressions in details"><link rel="next" href="ar01s07.html" title="7. Practical considerations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6. Extending return type deduction system</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:extending_return_type_system"></a>6. Extending return type deduction system</h2></div></div><p>
|
||||
|
||||
In this section, we explain how to extend the return type deduction system to cover user defined operators.
|
||||
In many cases this is not necessary, as the BLL defines default return types for operators.
|
||||
For example, the default return type for all comparison operators is <tt>bool</tt>, and as long as the user defined comparison operators have a bool return type, there is no need to write new specializations for the return type deduction classes.
|
||||
|
||||
In this section, we explain how to extend the return type deduction system
|
||||
to cover user defined operators.
|
||||
|
||||
In many cases this is not necessary,
|
||||
as the BLL defines default return types for operators.
|
||||
|
||||
For example, the default return type for all comparison operators is
|
||||
<tt>bool</tt>, and as long as the user defined comparison operators
|
||||
have a bool return type, there is no need to write new specializations
|
||||
for the return type deduction classes.
|
||||
|
||||
Sometimes this cannot be avoided, though.
|
||||
|
||||
</p><p>
|
||||
The overloadable user defined operators are either unary or binary.
|
||||
For each arity, there are two traits templates that define the return types of the different operators.
|
||||
Hence, the return type system can be extended by providing more specializations for these templates.
|
||||
|
||||
For each arity, there are two traits templates that define the
|
||||
return types of the different operators.
|
||||
|
||||
Hence, the return type system can be extended by providing more
|
||||
specializations for these templates.
|
||||
|
||||
The templates for unary functors are
|
||||
|
||||
<tt>
|
||||
plain_return_type_1<Action, A>
|
||||
</tt>
|
||||
|
||||
and
|
||||
|
||||
<tt>
|
||||
return_type_1<Action, A>
|
||||
</tt>, and
|
||||
|
||||
<tt>
|
||||
plain_return_type_2<Action, A, B>
|
||||
</tt>
|
||||
|
||||
and
|
||||
|
||||
<tt>
|
||||
return_type_2<Action, A, B>
|
||||
</tt>
|
||||
|
||||
respectively for binary functors.
|
||||
</p><p>The first parameter (<tt>Action</tt>) to all these templates is the <span class="emphasis"><i>action</i></span> class, which specifies the operator.
|
||||
Operators with similar return type rules are grouped together into <span class="emphasis"><i>action groups</i></span>, and only the action class and action group together define the operator unambiguously.
|
||||
As an example, the action type <tt>arithmetic_action<plus_action></tt> stands for <tt>operator+</tt>.
|
||||
The complete listing of different action types is shown in <a href="ar01s06.html#table:actions" title="Table 3. Action types">Table 3</a>.
|
||||
|
||||
</p><p>
|
||||
The latter parameters,
|
||||
<tt>A</tt> in the unary case, or A and B in the binary case, stand for the argument types of the operator call.
|
||||
The two sets of templates, <tt>plain_return_type_<i><tt>n</tt></i></tt> and <tt>return_type_<i><tt>n</tt></i></tt> (<i><tt>n</tt></i> is 1 or 2) differ in the way how parameter types are presented to them.
|
||||
For the former templates, the parameter types are always provided as non-reference types, and do not have const or volatile qualifiers.
|
||||
This makes specializing easy, as commonly one specialization for each user defined operator, or operator group, is enough.
|
||||
On the other hand, if a particular operator is overloaded for different cv-qualifications of the same argument types, and the return types of these overloaded versions differ, a more fine-grained control is needed.
|
||||
Hence, for the latter templates, the parameter types are always reference types, and const and volatile qualifiers are preserved.
|
||||
The downside is, that for an overloaded set of operators of the kind described above, one may end up needing up to 16 <tt>return_type_2</tt> specializations.
|
||||
The first parameter (<tt>Action</tt>) to all these templates
|
||||
is the <span class="emphasis"><i>action</i></span> class, which specifies the operator.
|
||||
|
||||
Operators with similar return type rules are grouped together into
|
||||
<span class="emphasis"><i>action groups</i></span>,
|
||||
and only the action class and action group together define the operator
|
||||
unambiguously.
|
||||
|
||||
As an example, the action type
|
||||
<tt>arithmetic_action<plus_action></tt> stands for
|
||||
<tt>operator+</tt>.
|
||||
|
||||
The complete listing of different action types is shown in
|
||||
<a href="ar01s06.html#table:actions" title="Table 2. Action types">Table 2</a>.
|
||||
</p><p>
|
||||
Suppose the user has overloaded the following operators for some user defined types <tt>X</tt>, <tt>Y</tt> and <tt>Z</tt>:
|
||||
The latter parameters, <tt>A</tt> in the unary case,
|
||||
or <tt>A</tt> and <tt>B</tt> in the binary case,
|
||||
stand for the argument types of the operator call.
|
||||
|
||||
The two sets of templates,
|
||||
<tt>plain_return_type_<i><tt>n</tt></i></tt> and
|
||||
<tt>return_type_<i><tt>n</tt></i></tt>
|
||||
(<i><tt>n</tt></i> is 1 or 2) differ in the way how parameter types
|
||||
are presented to them.
|
||||
|
||||
For the former templates, the parameter types are always provided as
|
||||
non-reference types, and do not have const or volatile qualifiers.
|
||||
|
||||
This makes specializing easy, as commonly one specialization for each
|
||||
user defined operator, or operator group, is enough.
|
||||
|
||||
On the other hand, if a particular operator is overloaded for different
|
||||
cv-qualifications of the same argument types,
|
||||
and the return types of these overloaded versions differ, a more fine-grained control is needed.
|
||||
|
||||
Hence, for the latter templates, the parameter types preserve the
|
||||
cv-qualifiers, and are non-reference types as well.
|
||||
|
||||
The downside is, that for an overloaded set of operators of the
|
||||
kind described above, one may end up needing up to
|
||||
16 <tt>return_type_2</tt> specializations.
|
||||
</p><p>
|
||||
Suppose the user has overloaded the following operators for some user defined
|
||||
types <tt>X</tt>, <tt>Y</tt> and <tt>Z</tt>:
|
||||
|
||||
<pre class="programlisting">
|
||||
Z operator+(const X&, const Y&);
|
||||
Z operator-(const X&, const Y&);
|
||||
</pre>
|
||||
|
||||
Now, one can add a specialization stating, that if the left hand argument is of type <tt>X</tt>, and the right hand one of type <tt>Y</tt>, the return type of all such binary arithmetic operators is <tt>Z</tt>:
|
||||
Now, one can add a specialization stating, that if the left hand argument
|
||||
is of type <tt>X</tt>, and the right hand one of type
|
||||
<tt>Y</tt>, the return type of all such binary arithmetic
|
||||
operators is <tt>Z</tt>:
|
||||
|
||||
<pre class="programlisting">
|
||||
namespace boost {
|
||||
@@ -67,17 +123,26 @@ struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
|
||||
}
|
||||
</pre>
|
||||
|
||||
Having this specialization defined, BLL is capable of correctly deducing the return type of the above two operators.
|
||||
Note, that the specializations must be in the same namespace, <tt>::boost::lambda</tt>, with the primary template.
|
||||
Having this specialization defined, BLL is capable of correctly
|
||||
deducing the return type of the above two operators.
|
||||
|
||||
Note, that the specializations must be in the same namespace,
|
||||
<tt>::boost::lambda</tt>, with the primary template.
|
||||
|
||||
For brevity, we do not show the namespace definitions in the examples below.
|
||||
</p><p>
|
||||
It is possible to specialize on the level of an individual operator as well, in addition to providing a specialization for a group of operators. Say, we add a new arithmetic operator for argument types <tt>X</tt> and <tt>Y</tt>:
|
||||
It is possible to specialize on the level of an individual operator as well,
|
||||
in addition to providing a specialization for a group of operators.
|
||||
Say, we add a new arithmetic operator for argument types <tt>X</tt>
|
||||
and <tt>Y</tt>:
|
||||
|
||||
<pre class="programlisting">
|
||||
X operator*(const X&, const Y&);
|
||||
</pre>
|
||||
|
||||
Our first rule for all arithmetic operators specifies that the return type of this operator is <tt>Z</tt>, which obviously is not the case.
|
||||
Our first rule for all arithmetic operators specifies that the return
|
||||
type of this operator is <tt>Z</tt>,
|
||||
which obviously is not the case.
|
||||
Hence, we provide a new rule for the multiplication operator:
|
||||
|
||||
<pre class="programlisting">
|
||||
@@ -87,38 +152,56 @@ struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y>
|
||||
};
|
||||
</pre>
|
||||
</p><p>
|
||||
The specializations can define arbitrary mappings from the argument types to the return type.
|
||||
Suppose we have some mathematical vector type, templated on the element type:
|
||||
<pre class="programlisting">template <class T> class my_vector;</pre>
|
||||
The specializations can define arbitrary mappings from the argument types
|
||||
to the return type.
|
||||
|
||||
Suppose we have some mathematical vector type, templated on the element type:
|
||||
|
||||
<pre class="programlisting">
|
||||
template <class T> class my_vector;
|
||||
</pre>
|
||||
|
||||
Suppose the addition operator is defined between any two
|
||||
<tt>my_vector</tt> instantiations,
|
||||
as long as the addition operator is defined between their element types.
|
||||
|
||||
Furthermore, the element type of the resulting <tt>my_vector</tt>
|
||||
is the same as the result type of the addition between the element types.
|
||||
|
||||
E.g., adding <tt>my_vector<int></tt> and
|
||||
<tt>my_vector<double></tt> results in
|
||||
<tt>my_vector<double></tt>.
|
||||
|
||||
The BLL has traits classes to perform the implicit built-in and standard
|
||||
type conversions between integral, floating point, and complex classes.
|
||||
|
||||
Suppose the addition operator is defined between any two <tt>my_vector</tt> instantiations, as long as the addition operator is defined between their element types.
|
||||
Furthermore, the element type of the resulting <tt>my_vector</tt> is the same as the result type of the addition between the element types.
|
||||
E.g., adding <tt>my_vector<int></tt> and <tt>my_vector<double></tt> results in <tt>my_vector<double></tt>.
|
||||
The BLL has traits classes to perform the implicit built-in and standard type conversions between integral, floating point, and complex classes.
|
||||
Using BLL tools, the addition operator described above can be defined as:
|
||||
|
||||
<pre class="programlisting">
|
||||
template<class A, class B>
|
||||
my_vector<typename return_type_2<arithmetic_action<plus_action>, A&, B&>::type>
|
||||
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_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
|
||||
return my_vector<res_type>();
|
||||
}
|
||||
</pre>
|
||||
</p><p>
|
||||
To allow BLL to deduce the type of <tt>my_vector</tt> additions correctly, we can define:
|
||||
To allow BLL to deduce the type of <tt>my_vector</tt>
|
||||
additions correctly, we can define:
|
||||
|
||||
<pre class="programlisting">
|
||||
template<class A, class B>
|
||||
class plain_return_type_2<arithmetic_action<plus_action>,
|
||||
my_vector<A>, my_vector<B> > {
|
||||
typedef typename
|
||||
return_type_2<arithmetic_action<plus_action>, A&, B&>::type res_type;
|
||||
return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
|
||||
public:
|
||||
typedef my_vector<res_type> type;
|
||||
};
|
||||
</pre>
|
||||
Note, that we are reusing the existing specializations for the BLL <tt>return_type_2</tt> template, which require that the argument types are references.
|
||||
</p><div class="table"><p><a name="table:actions"></a><b>Table 3. Action types</b></p><table summary="Action types" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt>+</tt></td><td><tt>arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>arithmetic_action<minus_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>arithmetic_action<multiply_action></tt></td></tr><tr><td><tt>/</tt></td><td><tt>arithmetic_action<divide_action></tt></td></tr><tr><td><tt>%</tt></td><td><tt>arithmetic_action<remainder_action></tt></td></tr><tr><td><tt>+</tt></td><td><tt>unary_arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>unary_arithmetic_action<minus_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>bitwise_action<and_action></tt></td></tr><tr><td><tt>|</tt></td><td><tt>bitwise_action<or_action></tt></td></tr><tr><td><tt>~</tt></td><td><tt>bitwise_action<not_action></tt></td></tr><tr><td><tt>^</tt></td><td><tt>bitwise_action<xor_action></tt></td></tr><tr><td><tt><<</tt></td><td><tt>bitwise_action<leftshift_action_no_stream></tt></td></tr><tr><td><tt>>></tt></td><td><tt>bitwise_action<rightshift_action_no_stream></tt></td></tr><tr><td><tt>&&</tt></td><td><tt>logical_action<and_action></tt></td></tr><tr><td><tt>||</tt></td><td><tt>logical_action<or_action></tt></td></tr><tr><td><tt>!</tt></td><td><tt>logical_action<not_action></tt></td></tr><tr><td><tt><</tt></td><td><tt>relational_action<less_action></tt></td></tr><tr><td><tt>></tt></td><td><tt>relational_action<greater_action></tt></td></tr><tr><td><tt><=</tt></td><td><tt>relational_action<lessorequal_action></tt></td></tr><tr><td><tt>>=</tt></td><td><tt>relational_action<greaterorequal_action></tt></td></tr><tr><td><tt>==</tt></td><td><tt>relational_action<equal_action></tt></td></tr><tr><td><tt>!=</tt></td><td><tt>relational_action<notequal_action></tt></td></tr><tr><td><tt>+=</tt></td><td><tt>arithmetic_assignment_action<plus_action></tt></td></tr><tr><td><tt>-=</tt></td><td><tt>arithmetic_assignment_action<minus_action></tt></td></tr><tr><td><tt>*=</tt></td><td><tt>arithmetic_assignment_action<multiply_action></tt></td></tr><tr><td><tt>/=</tt></td><td><tt>arithmetic_assignment_action<divide_action></tt></td></tr><tr><td><tt>%=</tt></td><td><tt>arithmetic_assignment_action<remainder_action></tt></td></tr><tr><td><tt>&=</tt></td><td><tt>bitwise_assignment_action<and_action></tt></td></tr><tr><td><tt>=|</tt></td><td><tt>bitwise_assignment_action<or_action></tt></td></tr><tr><td><tt>^=</tt></td><td><tt>bitwise_assignment_action<xor_action></tt></td></tr><tr><td><tt><<=</tt></td><td><tt>bitwise_assignment_action<leftshift_action></tt></td></tr><tr><td><tt>>>=</tt></td><td><tt>bitwise_assignment_action<rightshift_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>pre_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>pre_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>post_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>post_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>other_action<address_of_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>other_action<contents_of_action></tt></td></tr><tr><td><tt>,</tt></td><td><tt>other_action<comma_action></tt></td></tr></tbody></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. Lambda expressions in details </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 7. Practical considerations</td></tr></table></div></body></html>
|
||||
Note, that we are reusing the existing specializations for the
|
||||
BLL <tt>return_type_2</tt> template,
|
||||
which require that the argument types are references.
|
||||
</p><div class="table"><p><a name="table:actions"></a><b>Table 2. Action types</b></p><table summary="Action types" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt>+</tt></td><td><tt>arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>arithmetic_action<minus_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>arithmetic_action<multiply_action></tt></td></tr><tr><td><tt>/</tt></td><td><tt>arithmetic_action<divide_action></tt></td></tr><tr><td><tt>%</tt></td><td><tt>arithmetic_action<remainder_action></tt></td></tr><tr><td><tt>+</tt></td><td><tt>unary_arithmetic_action<plus_action></tt></td></tr><tr><td><tt>-</tt></td><td><tt>unary_arithmetic_action<minus_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>bitwise_action<and_action></tt></td></tr><tr><td><tt>|</tt></td><td><tt>bitwise_action<or_action></tt></td></tr><tr><td><tt>~</tt></td><td><tt>bitwise_action<not_action></tt></td></tr><tr><td><tt>^</tt></td><td><tt>bitwise_action<xor_action></tt></td></tr><tr><td><tt><<</tt></td><td><tt>bitwise_action<leftshift_action_no_stream></tt></td></tr><tr><td><tt>>></tt></td><td><tt>bitwise_action<rightshift_action_no_stream></tt></td></tr><tr><td><tt>&&</tt></td><td><tt>logical_action<and_action></tt></td></tr><tr><td><tt>||</tt></td><td><tt>logical_action<or_action></tt></td></tr><tr><td><tt>!</tt></td><td><tt>logical_action<not_action></tt></td></tr><tr><td><tt><</tt></td><td><tt>relational_action<less_action></tt></td></tr><tr><td><tt>></tt></td><td><tt>relational_action<greater_action></tt></td></tr><tr><td><tt><=</tt></td><td><tt>relational_action<lessorequal_action></tt></td></tr><tr><td><tt>>=</tt></td><td><tt>relational_action<greaterorequal_action></tt></td></tr><tr><td><tt>==</tt></td><td><tt>relational_action<equal_action></tt></td></tr><tr><td><tt>!=</tt></td><td><tt>relational_action<notequal_action></tt></td></tr><tr><td><tt>+=</tt></td><td><tt>arithmetic_assignment_action<plus_action></tt></td></tr><tr><td><tt>-=</tt></td><td><tt>arithmetic_assignment_action<minus_action></tt></td></tr><tr><td><tt>*=</tt></td><td><tt>arithmetic_assignment_action<multiply_action></tt></td></tr><tr><td><tt>/=</tt></td><td><tt>arithmetic_assignment_action<divide_action></tt></td></tr><tr><td><tt>%=</tt></td><td><tt>arithmetic_assignment_action<remainder_action></tt></td></tr><tr><td><tt>&=</tt></td><td><tt>bitwise_assignment_action<and_action></tt></td></tr><tr><td><tt>=|</tt></td><td><tt>bitwise_assignment_action<or_action></tt></td></tr><tr><td><tt>^=</tt></td><td><tt>bitwise_assignment_action<xor_action></tt></td></tr><tr><td><tt><<=</tt></td><td><tt>bitwise_assignment_action<leftshift_action></tt></td></tr><tr><td><tt>>>=</tt></td><td><tt>bitwise_assignment_action<rightshift_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>pre_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>pre_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>++</tt></td><td><tt>post_increment_decrement_action<increment_action></tt></td></tr><tr><td><tt>--</tt></td><td><tt>post_increment_decrement_action<decrement_action></tt></td></tr><tr><td><tt>&</tt></td><td><tt>other_action<address_of_action></tt></td></tr><tr><td><tt>*</tt></td><td><tt>other_action<contents_of_action></tt></td></tr><tr><td><tt>,</tt></td><td><tt>other_action<comma_action></tt></td></tr></tbody></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">5. Lambda expressions in details </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 7. Practical considerations</td></tr></table></div></body></html>
|
||||
|
||||
104
doc/ar01s07.html
104
doc/ar01s07.html
@@ -5,15 +5,99 @@
|
||||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s06.html" title="6. Extending return type deduction system"><link rel="next" href="ar01s08.html" title="8. Relation to other Boost libraries"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7. Practical considerations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s06.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s08.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2807377"></a>7. Practical considerations</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2807383"></a>7.1. Performance</h3></div></div><p>In theory, all overhead of using STL algorithms and lambda functors compared to hand written loops can be optimized away, just as the overhead from standard STL function objects and binders can.
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s06.html" title="6. Extending return type deduction system"><link rel="next" href="ar01s08.html" title="8. Relation to other Boost libraries"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">7. Practical considerations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s06.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s08.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2807558"></a>7. Practical considerations</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2807564"></a>7.1. Performance</h3></div></div><p>In theory, all overhead of using STL algorithms and lambda functors
|
||||
compared to hand written loops can be optimized away, just as the overhead
|
||||
from standard STL function objects and binders can.
|
||||
|
||||
Depending on the compiler, this can also be true in practice.
|
||||
</p><p>We have only performed limited performance testing described in [<a href="bi01.html#cit:jarvi:00" title="[Jär00]">Jär00</a>], and
|
||||
our tests suggest that the BLL does not introduce a loss of performance compared to STL function objects.
|
||||
Hence, with a reasonable optimizing compiler, one should expect the performance characteristics be comparable to using classic STL.
|
||||
Moreover, with a great optimizing compiler there may be no performance penalty at all.
|
||||
We ran two tests with the GCC 3.0.4 compiler on 1.5 GHz Intel Pentium 4.
|
||||
The optimization flag -03 was used.
|
||||
</p><p>
|
||||
In the first test we compared lambda functors against explicitly written
|
||||
function objects.
|
||||
We used both of these styles to define unary functions which multiply the
|
||||
argument repeatedly by itself.
|
||||
We started with the identity function, going up to
|
||||
x<sup>5</sup>.
|
||||
The expressions were called inside a <tt>std::transform</tt> loop,
|
||||
reading the argument from one <tt>std::vector<int></tt>
|
||||
and placing the result into another.
|
||||
The length of the vectors was 100 elements.
|
||||
The running times are listed in
|
||||
<a href="ar01s07.html#table:increasing_arithmetic_test" title="Table 3. Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
|
||||
The running times are expressed in arbitrary units.">Table 3</a>.
|
||||
|
||||
We can observe that there is no significant difference between the
|
||||
two approaches.
|
||||
</p><p>
|
||||
In the second test we again used <tt>std::transform</tt> to
|
||||
perform an operation to each element in a 100-element long vector.
|
||||
This time the element type of the vectors was <tt>double</tt>
|
||||
and we started with very simple arithmetic expressions and moved to
|
||||
more complex ones.
|
||||
The running times are listed in <a href="ar01s07.html#table:ll_vs_stl_test" title="Table 4. Test 2. CPU time of arithmetic expressions written as lambda
|
||||
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
|
||||
Using BLL terminology,
|
||||
a and b are bound arguments in the expressions, and x is open.
|
||||
All variables were of types double.
|
||||
The running times are expressed in arbitrary units.">Table 4</a>.
|
||||
|
||||
Here, we also included classic STL style unnamed functions into tests.
|
||||
We do not show these expressions, as they get rather complex.
|
||||
For example, the
|
||||
last expression in <a href="ar01s07.html#table:ll_vs_stl_test" title="Table 4. Test 2. CPU time of arithmetic expressions written as lambda
|
||||
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
|
||||
Using BLL terminology,
|
||||
a and b are bound arguments in the expressions, and x is open.
|
||||
All variables were of types double.
|
||||
The running times are expressed in arbitrary units.">Table 4</a> written with
|
||||
classic STL tools contains 7 calls to <tt>compose2</tt>,
|
||||
8 calls to <tt>bind1st</tt>
|
||||
and altogether 14 constructor invocations for creating
|
||||
<tt>multiplies</tt>, <tt>minus</tt>
|
||||
and <tt>plus</tt> objects.
|
||||
|
||||
In this test the BLL expressions are a little slower (roughly 10% on average,
|
||||
less than 14% in all cases)
|
||||
than the corresponding hand-written function objects.
|
||||
The performance hit is a bit greater with classic STL expressions,
|
||||
up to 27% for the simplest expressios.
|
||||
</p><p>
|
||||
The tests suggest that the BLL does not introduce a loss of performance
|
||||
compared to STL function objects.
|
||||
With a reasonable optimizing compiler, one should expect the performance characteristics be comparable to using classic STL.
|
||||
Moreover, with simple expressions the performance can be expected to be close
|
||||
to that of explicitly written function objects.
|
||||
|
||||
|
||||
|
||||
Note however, that evaluating a lambda functor consist of a sequence of calls to small functions that are declared inline.
|
||||
If the compiler fails to actually expand these functions inline, the performance, compared to hand written loops, can suffer.
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2807426"></a>7.2. About compiling</h3></div></div><p>The BLL uses templates rather heavily, performing numerous recursive instantiations of the same templates.
|
||||
If the compiler fails to actually expand these functions inline,
|
||||
the performance can suffer.
|
||||
The running time can more than double if this happens.
|
||||
Although the above tests do not include such an expression, we have experiensed
|
||||
this for some seemingly simple expressions.
|
||||
|
||||
|
||||
<div class="table"><p><a name="table:increasing_arithmetic_test"></a><b>Table 3. Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
|
||||
The running times are expressed in arbitrary units.</b></p><table summary="Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
|
||||
The running times are expressed in arbitrary units." border="1"><colgroup><col><col><col></colgroup><thead><tr><th>expression</th><th>lambda expression</th><th>hand-coded function object</th></tr></thead><tbody><tr><td>x</td><td>240</td><td>230</td></tr><tr><td>x*x</td><td>340</td><td>350</td></tr><tr><td>x*x*x</td><td>770</td><td>760</td></tr><tr><td>x*x*x*x</td><td>1180</td><td>1210</td></tr><tr><td>x*x*x*x*x</td><td>1950</td><td>1910</td></tr></tbody></table></div>
|
||||
</p><p>
|
||||
<div class="table"><p><a name="table:ll_vs_stl_test"></a><b>Table 4. Test 2. CPU time of arithmetic expressions written as lambda
|
||||
expressions, as classic STL unnamed functions (using <tt>compose2</tt>, <tt>bind1st</tt> etc.) and as traditional hand-coded function object classes.
|
||||
Using BLL terminology,
|
||||
<tt>a</tt> and <tt>b</tt> are bound arguments in the expressions, and <tt>x</tt> is open.
|
||||
All variables were of types <tt>double</tt>.
|
||||
The running times are expressed in arbitrary units.</b></p><table summary="Test 2. CPU time of arithmetic expressions written as lambda
|
||||
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
|
||||
Using BLL terminology,
|
||||
a and b are bound arguments in the expressions, and x is open.
|
||||
All variables were of types double.
|
||||
The running times are expressed in arbitrary units." border="1"><colgroup><col><col><col><col></colgroup><thead><tr><th>expression</th><th>lambda expression</th><th>classic STL expression</th><th>hand-coded function object</th></tr></thead><tbody><tr><td>ax</td><td>330</td><td>370</td><td>290</td></tr><tr><td>-ax</td><td>350</td><td>370</td><td>310</td></tr><tr><td>ax-(a+x)</td><td>470</td><td>500</td><td>420</td></tr><tr><td>(ax-(a+x))(a+x)</td><td>620</td><td>670</td><td>600</td></tr><tr><td>((ax) - (a+x))(bx - (b+x))(ax - (b+x))(bx - (a+x))</td><td>1660</td><td>1660</td><td>1460</td></tr></tbody></table></div>
|
||||
</p><p>Some additional performance testing with an earlier version of the
|
||||
library is described
|
||||
[<a href="bi01.html#cit:jarvi:00" title="[Jär00]">Jär00</a>].
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2808057"></a>7.2. About compiling</h3></div></div><p>The BLL uses templates rather heavily, performing numerous recursive instantiations of the same templates.
|
||||
This has (at least) three implications:
|
||||
<div class="itemizedlist"><ul type="disc"><li><p>
|
||||
While it is possible to write incredibly complex lambda expressions, it probably isn't a good idea.
|
||||
@@ -27,16 +111,16 @@ This can make the error messages very long and difficult to interpret, particula
|
||||
The C++ Standard suggests a template nesting level of 17 to help detect infinite recursion.
|
||||
Complex lambda templates can easily exceed this limit.
|
||||
Most compilers allow a greater number of nested templates, but commonly require the limit explicitly increased with a command line argument.
|
||||
</p></li></ul></div></p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2807495"></a>7.3. Portability</h3></div></div><p>
|
||||
</p></li></ul></div></p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2808118"></a>7.3. Portability</h3></div></div><p>
|
||||
The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL:
|
||||
|
||||
<div class="itemizedlist"><ul type="disc"><li>GCC 3.0.2
|
||||
<div class="itemizedlist"><ul type="disc"><li>GCC 3.0.4
|
||||
</li><li>KCC 4.0f with EDG 2.43.1
|
||||
</li><li>GCC 2.96 (fails with one test case, the <tt>exception_test.cpp</tt> results in an internal compiler error.
|
||||
)
|
||||
|
||||
</li></ul></div>
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2807535"></a>7.3.1. Test coverage</h4></div></div><p>The following list describes the test files included and the features that each file covers:
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2808157"></a>7.3.1. Test coverage</h4></div></div><p>The following list describes the test files included and the features that each file covers:
|
||||
|
||||
<div class="itemizedlist"><ul type="disc"><li><p>
|
||||
<tt>bind_tests_simple.cpp</tt> : Bind expressions of different arities and types of target functions: function pointers, function objects and member functions.
|
||||
|
||||
117
doc/ar01s08.html
117
doc/ar01s08.html
@@ -5,71 +5,68 @@
|
||||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s07.html" title="7. Practical considerations"><link rel="next" href="ar01s09.html" title="9. Contributors"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8. Relation to other Boost libraries</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2807880"></a>8. Relation to other Boost libraries</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2807887"></a>8.1. Boost Function</h3></div></div><p>Sometimes it is convenient to store lambda functors in variables.
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s07.html" title="7. Practical considerations"><link rel="next" href="ar01s09.html" title="9. Contributors"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8. Relation to other Boost libraries</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2808502"></a>8. Relation to other Boost libraries</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2808510"></a>8.1. Boost Function</h3></div></div><p>Sometimes it is convenient to store lambda functors in variables.
|
||||
However, the types of even the simplest lambda functors are long and unwieldy, and it is in general unfeasible to declare variables with lambda functor types.
|
||||
<span class="emphasis"><i>The Boost Function library</i></span> [<a href="bi01.html#cit:boost::function" title="[function]">function</a>] defines wrappers for (almost) arbitrary function objects; and these wrappers have types that are easy to type out.
|
||||
<span class="emphasis"><i>The Boost Function library</i></span> [<a href="bi01.html#cit:boost::function" title="[function]">function</a>] defines wrappers for arbitrary function objects, for example
|
||||
lambda functors; and these wrappers have types that are easy to type out.
|
||||
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int foo(float, char);
|
||||
boost::function<int, float, char> f = foo;
|
||||
boost::function<int, int, int> g = std::plus<int>();
|
||||
boost::function<int, int, int> f = _1 + _2;
|
||||
boost::function<int&, int&> g = unlambda(_1 += 10);
|
||||
int i = 1, j = 2;
|
||||
f(i); // returns 3
|
||||
g(i); // sets i to = 11;
|
||||
</pre>
|
||||
|
||||
The return and parameter types of the wrapped function object must be written explicilty as template arguments to the wrapper template <tt>boost::function</tt>; even when lambda functors, which otherwise have generic parameters, are wrapped.
|
||||
Wrapping a function object with <tt>boost::function</tt> introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used.
|
||||
|
||||
|
||||
</p><p>
|
||||
Due to a technical conflict between the two libraries, lambda functors cannot be directly wrapped with <tt>boost::function</tt> (this may be resolved in the future).
|
||||
However, applying the <tt>unlambda</tt> (see <a href="ar01s05.html#sect:unlambda" title="5.9.1.1. Unlambda">Section 5.9.1.1</a>) function to a lambda functor gives a function object that is compatible with <tt>boost::function</tt>.
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
boost::function<int, int, int> f = unlambda(_1 + _2);
|
||||
f(1, 2); // returns 3
|
||||
</pre>
|
||||
|
||||
<pre class="programlisting">
|
||||
|
||||
int i = 1;
|
||||
boost::function<int&, int&> g = unlambda(_1 += 10);
|
||||
g(i); // i == 11;
|
||||
</pre>
|
||||
|
||||
Note that storing lambda functors inside <tt>boost::function</tt> introduces a danger.
|
||||
Certain types of lambda functors may store references to the bound arguments, instead as taking copies of the arguments of the lambda expression.
|
||||
Note that storing lambda functors inside <tt>boost::function</tt>
|
||||
introduces a danger.
|
||||
Certain types of lambda functors may store references to the bound
|
||||
arguments, instead as taking copies of the arguments of the lambda expression.
|
||||
When temporary lambda functor objects are used
|
||||
in STL algorithm invocations this is always safe, as the lambda functor gets destructed immediately after the STL algortihm invocation is completed.
|
||||
in STL algorithm invocations this is always safe, as the lambda functor gets
|
||||
destructed immediately after the STL algortihm invocation is completed.
|
||||
|
||||
However, a lambda functor wrapped inside <tt>boost::function</tt> may continue to exist longer, creating the possibility of dangling references.
|
||||
However, a lambda functor wrapped inside <tt>boost::function</tt>
|
||||
may continue to exist longer, creating the possibility of dangling references.
|
||||
For example:
|
||||
|
||||
<pre class="programlisting">
|
||||
int* sum = new int();
|
||||
*sum = 0;
|
||||
boost::function<int&, int> counter = unlambda(*sum += _1);
|
||||
boost::function<int&, int> counter = *sum += _1;
|
||||
counter(5); // ok, *sum = 5;
|
||||
delete sum;
|
||||
counter(3); // error, *sum does not exist anymore
|
||||
</pre>
|
||||
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2808050"></a>8.2. Boost Bind</h3></div></div><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2808614"></a>8.2. Boost Bind</h3></div></div><p>
|
||||
<span class="emphasis"><i>The Boost Bind</i></span> [<a href="bi01.html#cit:boost::bind" title="[bind]">bind</a>] library has partially overlapping functionality with the BLL.
|
||||
Basically, the Boost Bind library (BB in the sequel) implements the bind expression part of BLL.
|
||||
There are, however, some semantical differerences.
|
||||
</p><p>
|
||||
The BLL and BB evolved separately, and have different implementations.
|
||||
This means that the bind expressions from the BB cannot be used within bind expressions, or within other type of lambda expressions, of the BLL.
|
||||
This means that the bind expressions from the BB cannot be used within
|
||||
bind expressions, or within other type of lambda expressions, of the BLL.
|
||||
The same holds for using BLL bind expressions in the BB.
|
||||
The libraries can coexist, however, as
|
||||
the names of the BB library are in <tt>boost</tt> namespace, whereas the BLL names are in <tt>boost::lambda</tt> namespace.
|
||||
the names of the BB library are in <tt>boost</tt> namespace,
|
||||
whereas the BLL names are in <tt>boost::lambda</tt> namespace.
|
||||
</p><p>
|
||||
The BLL requires a compiler that is reasonably conformant to the C++ standard, whereas the BB library is more portable, and works witha a larger set of compilers.
|
||||
The BLL requires a compiler that is reasonably conformant to the
|
||||
C++ standard, whereas the BB library is more portable, and works with
|
||||
a larger set of compilers.
|
||||
</p><p>
|
||||
The following two sections describe what are the semantic differences between the bind expressions in BB and BLL.
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2808116"></a>8.2.1. First argument of bind expression</h4></div></div>
|
||||
In BB the first argument of the bind expression, the target function, is treated differently from the other arguments,
|
||||
The following two sections describe what are the semantic differences
|
||||
between the bind expressions in BB and BLL.
|
||||
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2808678"></a>8.2.1. First argument of bind expression</h4></div></div>
|
||||
|
||||
In BB the first argument of the bind expression, the target function,
|
||||
is treated differently from the other arguments,
|
||||
as no argument substitution takes place within that argument.
|
||||
In BLL the first argument is not a special case in this respect.
|
||||
|
||||
@@ -108,36 +105,20 @@ bind(unlambda(f), _1)(x);
|
||||
</pre>
|
||||
as explained in <a href="ar01s05.html#sect:unlambda" title="5.9.1.1. Unlambda">Section 5.9.1.1</a>.
|
||||
|
||||
</div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2808206"></a>8.2.2.
|
||||
Arity of function objects
|
||||
</h4></div></div><p>
|
||||
In both libraries, the highest placeholder index in a bind expression determines the arity of the resulting function object.
|
||||
However, in the BB library, this is kind of a minimal arity, as the function object can take arbitrarily many arguments; those not needed are discarded.
|
||||
Consider the two bind expressions and their invocations below:
|
||||
|
||||
<pre class="programlisting">
|
||||
bind(g, _3, _3, _3)(x, y, z);
|
||||
bind(g, _1, _1, _1)(x, y, z);
|
||||
</pre>
|
||||
This first line ends up making the call:
|
||||
<pre class="programlisting">
|
||||
g(z, z, z)
|
||||
</pre>
|
||||
in both libraries.
|
||||
The second line is treated differently.
|
||||
In BLL a compile time error will result, whereas BB will silently ignore the superfluous arguments and invoke:
|
||||
<pre class="programlisting">
|
||||
g(x, x, x)
|
||||
</pre>
|
||||
In this tradeoff between safety and flexibility, BLL takes the safer route.
|
||||
Note however, that it is easy to write a lambda functor that would make the above call to
|
||||
<tt>g(x, x, x)</tt> discarding all but the first argument:
|
||||
<pre class="programlisting">
|
||||
(_3, bind(g, _1, _1, _1))(x, y, z);
|
||||
</pre>
|
||||
This lambda expression takes three arguments.
|
||||
The left-hand argument of the comma operator does nothing, and as comma returns the result of evaluating the right-hand argument we end up with the call
|
||||
<tt>g(x, x, x)</tt>.
|
||||
|
||||
|
||||
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7. Practical considerations </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9. Contributors</td></tr></table></div></body></html>
|
||||
</div><p>
|
||||
The BB library supports up to nine placeholders, while the BLL
|
||||
defines only three placeholders.
|
||||
The rationale for not providing more, is that the highest arity of the
|
||||
function objects accepted by any STL algorithm is two.
|
||||
The placeholder count is easy to increase in the BB library.
|
||||
In BLL it is possible, but more laborous.
|
||||
The BLL currently passes the actual arguments to the lambda functors
|
||||
internally just as they are and does not wrap them inside a tuple object.
|
||||
The reason for this is that some widely used compilers are not capable
|
||||
of optimizing the intermediate tuple objects away.
|
||||
The creation of the intermediate tuples would cause a significant
|
||||
performance hit, particularly for the simplest (and thus the most common)
|
||||
lambda functors.
|
||||
We are working on a hybrid approach, which will allow more placeholders
|
||||
but not compromise the performance of simple lambda functors.
|
||||
</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7. Practical considerations </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9. Contributors</td></tr></table></div></body></html>
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s08.html" title="8. Relation to other Boost libraries"><link rel="next" href="bi01.html" title="Bibliography"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9. Contributors</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s08.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="bi01.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2808282"></a>9. Contributors</h2></div></div>
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s08.html" title="8. Relation to other Boost libraries"><link rel="next" href="apa.html" title="A. Rationale for some of the design decisions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9. Contributors</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s08.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="apa.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="id2808810"></a>9. Contributors</h2></div></div>
|
||||
|
||||
The main body of the library was written by Jaakko Järvi and Gary Powell.
|
||||
We've got outside help, suggestions and ideas from Jeremy Siek, Peter Higley, Peter Dimov, Valentin Bonnard, William Kempf.
|
||||
We would particularly like to mention Joel de Guzmann and his work with
|
||||
Phoenix which has influenced BLL significantly, making it considerably simpler
|
||||
to extend the library with new features.
|
||||
|
||||
</div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s08.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="bi01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8. Relation to other Boost libraries </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Bibliography</td></tr></table></div></body></html>
|
||||
</div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s08.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="apa.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8. Relation to other Boost libraries </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> A. Rationale for some of the design decisions</td></tr></table></div></body></html>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
The Boost Lambda Library"><link rel="up" href="index.html" title="
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library"><link rel="previous" href="ar01s09.html" title="9. Contributors"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Bibliography</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s09.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div id="id2808299" class="bibliography"><div class="titlepage"><div><h2 class="title"><a name="id2808299"></a>Bibliography</h2></div></div><div class="biblioentry"><a name="cit:stepanov:94"></a><p>[STL94] <span class="authorgroup">A. A. Stepanov and M. Lee. </span><span class="title"><I>The Standard Template Library</I>. </span><span class="orgname">Hewlett-Packard Laboratories. </span><span class="pubdate">1994. </span><span class="bibliomisc">
|
||||
The Boost Lambda Library"><link rel="previous" href="apa.html" title="A. Rationale for some of the design decisions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Bibliography</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="apa.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div id="id2808984" class="bibliography"><div class="titlepage"><div><h2 class="title"><a name="id2808984"></a>Bibliography</h2></div></div><div class="biblioentry"><a name="cit:stepanov:94"></a><p>[STL94] <span class="authorgroup">A. A. Stepanov and M. Lee. </span><span class="title"><I>The Standard Template Library</I>. </span><span class="orgname">Hewlett-Packard Laboratories. </span><span class="pubdate">1994. </span><span class="bibliomisc">
|
||||
<a href="http://www.hpl.hp.com/techreports" target="_top">www.hpl.hp.com/techreports</a>
|
||||
. </span></p></div><div class="biblioentry"><a name="cit:sgi:02"></a><p>[SGI02] <span class="title"><I>The SGI Standard Template Library</I>. </span><span class="pubdate">2002. </span><span class="bibliomisc"><a href="http://www.sgi.com/tech/stl/" target="_top">www.sgi.com/tech/stl/</a>. </span></p></div><div class="biblioentry"><a name="cit:c++:98"></a><p>[C++98] <span class="title"><I>International Standard, Programming Languages – C++</I>. </span><span class="subtitle">ISO/IEC:14882. </span><span class="pubdate">1998. </span></p></div><div class="biblioentry"><a name="cit:jarvi:99"></a><p>[Jär99] <span class="articleinfo">
|
||||
<span class="author">Jaakko Järvi. </span>
|
||||
@@ -15,4 +15,5 @@
|
||||
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::ref"></a><p>[ref] <span class="title"><I>Boost ref</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/ref.html" target="_top">www.boost.org/libs/bind/ref.html</a>
|
||||
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::bind"></a><p>[bind] <span class="title"><I>Boost Bind Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/bind.html" target="_top">www.boost.org/libs/bind/bind.html</a>
|
||||
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::function"></a><p>[function] <span class="title"><I>Boost Function Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/function/" target="_top">www.boost.org/libs/function/</a>
|
||||
. </span><span class="pubdate">2002. </span></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s09.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">9. Contributors </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
|
||||
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:fc++"></a><p>[fc++] <span class="title"><I>The FC++ library: Functional Programming in C++</I>. </span><span class="author">Yannis Smaragdakis. </span><span class="author">Brian McNamara. </span><span class="bibliomisc"><a href="http://www.cc.gatech.edu/~yannis/fc++/" target="_top">www.cc.gatech.edu/~yannis/fc++/</a>
|
||||
. </span><span class="pubdate">2002. </span></p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="apa.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">A. Rationale for some of the design decisions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
|
||||
|
||||
7
doc/detail/README
Normal file
7
doc/detail/README
Normal file
@@ -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.html loads stylesheets that generate one big html-file
|
||||
(you need to edit the paths in these files to make them work)
|
||||
|
||||
3420
doc/detail/lambda_doc.xml
Executable file
3420
doc/detail/lambda_doc.xml
Executable file
File diff suppressed because it is too large
Load Diff
19
doc/detail/lambda_doc.xsl
Normal file
19
doc/detail/lambda_doc.xsl
Normal file
@@ -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>
|
||||
19
doc/detail/lambda_doc_chunks.xsl
Normal file
19
doc/detail/lambda_doc_chunks.xsl
Normal file
@@ -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>
|
||||
@@ -8,14 +8,16 @@
|
||||
The Boost Lambda Library"><link rel="next" href="ar01s02.html" title="2. Getting Started"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">
|
||||
C++ BOOST
|
||||
|
||||
The Boost Lambda Library</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s02.html">Next</a></td></tr></table><hr></div><div class="article"><div class="titlepage"><div><h1 class="title"><a name="id2733458"></a>
|
||||
The Boost Lambda Library</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s02.html">Next</a></td></tr></table><hr></div><div class="article"><div class="titlepage"><div><h1 class="title"><a name="id2733457"></a>
|
||||
<span class="inlinemediaobject"><img src="../../../c++boost.gif" alt="C++ BOOST"></span>
|
||||
|
||||
The Boost Lambda Library</h1></div><div><p class="copyright">Copyright © 1999-2002 Jaakko Järvi, Gary Powell</p></div><div><div class="legalnotice"><p>
|
||||
The Boost Lambda Library is free software; Permission to copy,
|
||||
use, modify and distribute this software and its documentation is granted, provided this copyright
|
||||
notice appears in all copies.
|
||||
</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt>1. <a href="index.html#introduction">In a nutshell</a></dt><dt>2. <a href="ar01s02.html">Getting Started</a></dt><dd><dl><dt>2.1. <a href="ar01s02.html#id2790112">Installing the library</a></dt><dt>2.2. <a href="ar01s02.html#id2742926">Conventions used in this document</a></dt></dl></dd><dt>3. <a href="ar01s03.html">Introduction</a></dt><dd><dl><dt>3.1. <a href="ar01s03.html#id2742980">Motivation</a></dt><dt>3.2. <a href="ar01s03.html#id2741408">Introduction to lambda expressions</a></dt></dl></dd><dt>4. <a href="ar01s04.html">Using the library</a></dt><dd><dl><dt>4.1. <a href="ar01s04.html#sect:introductory_examples">Introductory Examples</a></dt><dt>4.2. <a href="ar01s04.html#sect:parameter_and_return_types">Parameter and return types of lambda functors</a></dt><dt>4.3. <a href="ar01s04.html#sect:actual_arguments_to_lambda_functors">About actual arguments to lambda functors</a></dt><dt>4.4. <a href="ar01s04.html#sect:storing_bound_arguments">Storing bound arguments in lambda functions</a></dt></dl></dd><dt>5. <a href="ar01s05.html">Lambda expressions in details</a></dt><dd><dl><dt>5.1. <a href="ar01s05.html#sect:placeholders">Placeholders</a></dt><dt>5.2. <a href="ar01s05.html#sect:operator_expressions">Operator expressions</a></dt><dt>5.3. <a href="ar01s05.html#sect:bind_expressions">Bind expressions</a></dt><dt>5.4. <a href="ar01s05.html#sect:overriding_deduced_return_type">Overriding the deduced return type</a></dt><dt>5.5. <a href="ar01s05.html#sect:delaying_constants_and_variables">Delaying constants and variables</a></dt><dt>5.6. <a href="ar01s05.html#sect:lambda_expressions_for_control_structures">Lambda expressions for control structures</a></dt><dt>5.7. <a href="ar01s05.html#sect:exceptions">Exceptions</a></dt><dt>5.8. <a href="ar01s05.html#sect:construction_and_destruction">Construction and destruction</a></dt><dt>5.9. <a href="ar01s05.html#id2805233">Special lambda expressions</a></dt><dt>5.10. <a href="ar01s05.html#id2805803">Casts, sizeof and typeid</a></dt><dt>5.11. <a href="ar01s05.html#sect:nested_stl_algorithms">Nesting STL algorithm invocations</a></dt></dl></dd><dt>6. <a href="ar01s06.html">Extending return type deduction system</a></dt><dt>7. <a href="ar01s07.html">Practical considerations</a></dt><dd><dl><dt>7.1. <a href="ar01s07.html#id2807383">Performance</a></dt><dt>7.2. <a href="ar01s07.html#id2807426">About compiling</a></dt><dt>7.3. <a href="ar01s07.html#id2807495">Portability</a></dt></dl></dd><dt>8. <a href="ar01s08.html">Relation to other Boost libraries</a></dt><dd><dl><dt>8.1. <a href="ar01s08.html#id2807887">Boost Function</a></dt><dt>8.2. <a href="ar01s08.html#id2808050">Boost Bind</a></dt></dl></dd><dt>9. <a href="ar01s09.html">Contributors</a></dt><dt><a href="bi01.html">Bibliography</a></dt></dl></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="introduction"></a>1. In a nutshell</h2></div></div><p>
|
||||
</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt>1. <a href="index.html#introduction">In a nutshell</a></dt><dt>2. <a href="ar01s02.html">Getting Started</a></dt><dd><dl><dt>2.1. <a href="ar01s02.html#id2790109">Installing the library</a></dt><dt>2.2. <a href="ar01s02.html#id2741935">Conventions used in this document</a></dt></dl></dd><dt>3. <a href="ar01s03.html">Introduction</a></dt><dd><dl><dt>3.1. <a href="ar01s03.html#id2741989">Motivation</a></dt><dt>3.2. <a href="ar01s03.html#id2742784">Introduction to lambda expressions</a></dt></dl></dd><dt>4. <a href="ar01s04.html">Using the library</a></dt><dd><dl><dt>4.1. <a href="ar01s04.html#sect:introductory_examples">Introductory Examples</a></dt><dt>4.2. <a href="ar01s04.html#sect:parameter_and_return_types">Parameter and return types of lambda functors</a></dt><dt>4.3. <a href="ar01s04.html#sect:actual_arguments_to_lambda_functors">About actual arguments to lambda functors</a></dt><dt>4.4. <a href="ar01s04.html#sect:storing_bound_arguments">Storing bound arguments in lambda functions</a></dt></dl></dd><dt>5. <a href="ar01s05.html">Lambda expressions in details</a></dt><dd><dl><dt>5.1. <a href="ar01s05.html#sect:placeholders">Placeholders</a></dt><dt>5.2. <a href="ar01s05.html#sect:operator_expressions">Operator expressions</a></dt><dt>5.3. <a href="ar01s05.html#sect:bind_expressions">Bind expressions</a></dt><dt>5.4. <a href="ar01s05.html#sect:overriding_deduced_return_type">Overriding the deduced return type</a></dt><dt>5.5. <a href="ar01s05.html#sect:delaying_constants_and_variables">Delaying constants and variables</a></dt><dt>5.6. <a href="ar01s05.html#sect:lambda_expressions_for_control_structures">Lambda expressions for control structures</a></dt><dt>5.7. <a href="ar01s05.html#sect:exceptions">Exceptions</a></dt><dt>5.8. <a href="ar01s05.html#sect:construction_and_destruction">Construction and destruction</a></dt><dt>5.9. <a href="ar01s05.html#id2805476">Special lambda expressions</a></dt><dt>5.10. <a href="ar01s05.html#id2806049">Casts, sizeof and typeid</a></dt><dt>5.11. <a href="ar01s05.html#sect:nested_stl_algorithms">Nesting STL algorithm invocations</a></dt></dl></dd><dt>6. <a href="ar01s06.html">Extending return type deduction system</a></dt><dt>7. <a href="ar01s07.html">Practical considerations</a></dt><dd><dl><dt>7.1. <a href="ar01s07.html#id2807564">Performance</a></dt><dt>7.2. <a href="ar01s07.html#id2808057">About compiling</a></dt><dt>7.3. <a href="ar01s07.html#id2808118">Portability</a></dt></dl></dd><dt>8. <a href="ar01s08.html">Relation to other Boost libraries</a></dt><dd><dl><dt>8.1. <a href="ar01s08.html#id2808510">Boost Function</a></dt><dt>8.2. <a href="ar01s08.html#id2808614">Boost Bind</a></dt></dl></dd><dt>9. <a href="ar01s09.html">Contributors</a></dt><dt>A. <a href="apa.html">Rationale for some of the design decisions</a></dt><dd><dl><dt>1. <a href="apa.html#sect:why_weak_arity">
|
||||
Lambda functor arity
|
||||
</a></dt></dl></dd><dt><a href="bi01.html">Bibliography</a></dt></dl></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="introduction"></a>1. In a nutshell</h2></div></div><p>
|
||||
|
||||
The Boost Lambda Library (BLL in the sequel) is a C++ template
|
||||
library, which implements form of <span class="emphasis"><i>lambda abstractions</i></span> for C++.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <functional>
|
||||
|
||||
void begin_section(std::string name) {
|
||||
std::cout << "-------------------------------------------------------\n";
|
||||
std::cout << name << '\n';
|
||||
std::cout << "-------------------------------------------------------\n";
|
||||
return;
|
||||
};
|
||||
|
||||
void end_section() {
|
||||
std::cout << "-------------------------------------------------------\n";
|
||||
return;
|
||||
};
|
||||
|
||||
template<class Test>
|
||||
void call_test(Test t, std::string name)
|
||||
{
|
||||
begin_section(name);
|
||||
t();
|
||||
end_section();
|
||||
};
|
||||
|
||||
void introduction() {
|
||||
|
||||
using boost::lambda::_1;
|
||||
|
||||
std::cout << "Output should be: 1 2\n";
|
||||
std::vector<int> a; a.push_back(1); a.push_back(2);
|
||||
for_each(a.begin(), a.end(), std::cout << _1 << ' ');
|
||||
std::cout << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
void motivation() {
|
||||
|
||||
using std::vector;
|
||||
using std::ostream_iterator;
|
||||
using std::cout;
|
||||
using std::bind1st;
|
||||
using std::plus;
|
||||
|
||||
using std::transform;
|
||||
using std::for_each;
|
||||
|
||||
vector<int> a; a.push_back(1); a.push_back(2);
|
||||
|
||||
std::cout << "Output should be: 23 = 23 = 23\n";
|
||||
transform(a.begin(), a.end(), ostream_iterator<int>(cout),
|
||||
bind1st(plus<int>(), 1));
|
||||
|
||||
using boost::lambda::_1;
|
||||
|
||||
cout << " = ";
|
||||
|
||||
transform(a.begin(), a.end(), ostream_iterator<int>(cout), 1 + _1);
|
||||
|
||||
cout << " = ";
|
||||
|
||||
for_each(a.begin(), a.end(), cout << (_1 + 1));
|
||||
|
||||
std::cout << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
using std::cout;
|
||||
|
||||
call_test(introduction, "introduction"); cout << '\n';
|
||||
|
||||
call_test(motivation, "Motivation"); cout << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,5 +20,5 @@
|
||||
#include "boost/lambda/core.hpp"
|
||||
|
||||
#include "boost/lambda/detail/bind_functions.hpp"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,10 +32,10 @@ template<class T> class const_cast_action;
|
||||
template<class T> class reinterpret_cast_action;
|
||||
|
||||
class typeid_action;
|
||||
|
||||
class sizeof_action;
|
||||
|
||||
// Cast actions
|
||||
|
||||
template<class T> class cast_action<static_cast_action<T> >
|
||||
{
|
||||
public:
|
||||
@@ -91,28 +91,21 @@ public:
|
||||
|
||||
// return types of casting lambda_functors (all "T" type.)
|
||||
|
||||
template<template <class T> class cast_type, class T, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, cast_action< cast_type<T> > >, Args, Code>,
|
||||
Open>
|
||||
{
|
||||
template<template <class> class cast_type, class T, class A>
|
||||
struct return_type_N<cast_action< cast_type<T> >, A> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
// return type of typeid_action
|
||||
|
||||
template<class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, typeid_action >, Args, Code>,
|
||||
Open>
|
||||
{
|
||||
template<class A>
|
||||
struct return_type_N<typeid_action, A> {
|
||||
typedef std::type_info const & type;
|
||||
};
|
||||
|
||||
// return type of sizeof_action
|
||||
|
||||
template<class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, sizeof_action >, Args, Code>,
|
||||
Open >
|
||||
{
|
||||
template<class A>
|
||||
struct return_type_N<sizeof_action, A> {
|
||||
typedef std::size_t type;
|
||||
};
|
||||
|
||||
@@ -123,85 +116,69 @@ struct return_type<lambda_functor_args<action<1, sizeof_action >, Args, Code>,
|
||||
// static_cast
|
||||
template <class T, class Arg1>
|
||||
inline const lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<static_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<static_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
>
|
||||
ll_static_cast(const Arg1& a1) {
|
||||
return lambda_functor< lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<static_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value> >
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
return
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<static_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
}
|
||||
|
||||
// dynamic_cast
|
||||
template <class T, class Arg1>
|
||||
inline const lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<dynamic_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<dynamic_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
>
|
||||
ll_dynamic_cast(const Arg1& a1) {
|
||||
return lambda_functor< lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<dynamic_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value> >
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
return
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<dynamic_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
}
|
||||
|
||||
// const_cast
|
||||
template <class T, class Arg1>
|
||||
inline const lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<const_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<const_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
>
|
||||
ll_const_cast(const Arg1& a1) {
|
||||
return lambda_functor< lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<const_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value> >
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
return
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<const_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
}
|
||||
|
||||
// reinterpret_cast
|
||||
template <class T, class Arg1>
|
||||
inline const lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<reinterpret_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<reinterpret_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
>
|
||||
ll_reinterpret_cast(const Arg1& a1) {
|
||||
return lambda_functor< lambda_functor_args<
|
||||
action<1,
|
||||
cast_action<reinterpret_cast_action<T> >
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value> >
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
return
|
||||
lambda_functor_base<
|
||||
action<1, cast_action<reinterpret_cast_action<T> > >,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
}
|
||||
|
||||
// typeid
|
||||
@@ -209,44 +186,36 @@ ll_reinterpret_cast(const Arg1& a1) {
|
||||
// class object)
|
||||
template <class Arg1>
|
||||
inline const lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1,
|
||||
typeid_action
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value
|
||||
lambda_functor_base<
|
||||
action<1, typeid_action>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
>
|
||||
ll_typeid(const Arg1& a1) {
|
||||
return lambda_functor<lambda_functor_args<
|
||||
action<1,
|
||||
typeid_action
|
||||
>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>,
|
||||
dig_arity<Arg1>::value> >
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
return
|
||||
lambda_functor_base<
|
||||
action<1, typeid_action>,
|
||||
tuple<typename const_copy_argument <const Arg1>::type>
|
||||
>
|
||||
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
|
||||
}
|
||||
|
||||
// sizeof(expression)
|
||||
// Always takes a lambda expression (if not, built in sizeof will do)
|
||||
template <class Arg1>
|
||||
inline const lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<1, sizeof_action>,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
dig_arity<Arg1>::value
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
ll_sizeof(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<1, sizeof_action>,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
dig_arity<Arg1>::value
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
( tuple<lambda_functor<Arg1> >(a1));
|
||||
( tuple<lambda_functor<Arg1> >(a1));
|
||||
}
|
||||
|
||||
} // namespace lambda
|
||||
|
||||
289
include/boost/lambda/closures.hpp
Normal file
289
include/boost/lambda/closures.hpp
Normal file
@@ -0,0 +1,289 @@
|
||||
/*=============================================================================
|
||||
Adaptable closures
|
||||
|
||||
Phoenix V0.9
|
||||
Copyright (c) 2001-2002 Joel de Guzman
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the copyright holder be held liable for
|
||||
any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute
|
||||
it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
URL: http://spirit.sourceforge.net/
|
||||
|
||||
==============================================================================*/
|
||||
#ifndef PHOENIX_CLOSURES_HPP
|
||||
#define PHOENIX_CLOSURES_HPP
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "boost/lambda/core.hpp"
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Adaptable closures
|
||||
//
|
||||
// The framework will not be complete without some form of closures
|
||||
// support. Closures encapsulate a stack frame where local
|
||||
// variables are created upon entering a function and destructed
|
||||
// upon exiting. Closures provide an environment for local
|
||||
// variables to reside. Closures can hold heterogeneous types.
|
||||
//
|
||||
// Phoenix closures are true hardware stack based closures. At the
|
||||
// very least, closures enable true reentrancy in lambda functions.
|
||||
// A closure provides access to a function stack frame where local
|
||||
// variables reside. Modeled after Pascal nested stack frames,
|
||||
// closures can be nested just like nested functions where code in
|
||||
// inner closures may access local variables from in-scope outer
|
||||
// closures (accessing inner scopes from outer scopes is an error
|
||||
// and will cause a run-time assertion failure).
|
||||
//
|
||||
// There are three (3) interacting classes:
|
||||
//
|
||||
// 1) closure:
|
||||
//
|
||||
// At the point of declaration, a closure does not yet create a
|
||||
// stack frame nor instantiate any variables. A closure declaration
|
||||
// declares the types and names[note] of the local variables. The
|
||||
// closure class is meant to be subclassed. It is the
|
||||
// responsibility of a closure subclass to supply the names for
|
||||
// each of the local variable in the closure. Example:
|
||||
//
|
||||
// struct my_closure : closure<int, string, double> {
|
||||
//
|
||||
// member1 num; // names the 1st (int) local variable
|
||||
// member2 message; // names the 2nd (string) local variable
|
||||
// member3 real; // names the 3rd (double) local variable
|
||||
// };
|
||||
//
|
||||
// my_closure clos;
|
||||
//
|
||||
// Now that we have a closure 'clos', its local variables can be
|
||||
// accessed lazily using the dot notation. Each qualified local
|
||||
// variable can be used just like any primitive actor (see
|
||||
// primitives.hpp). Examples:
|
||||
//
|
||||
// clos.num = 30
|
||||
// clos.message = arg1
|
||||
// clos.real = clos.num * 1e6
|
||||
//
|
||||
// The examples above are lazily evaluated. As usual, these
|
||||
// expressions return composite actors that will be evaluated
|
||||
// through a second function call invocation (see operators.hpp).
|
||||
// Each of the members (clos.xxx) is an actor. As such, applying
|
||||
// the operator() will reveal its identity:
|
||||
//
|
||||
// clos.num() // will return the current value of clos.num
|
||||
//
|
||||
// *** [note] Acknowledgement: Juan Carlos Arevalo-Baeza (JCAB)
|
||||
// introduced and initilally implemented the closure member names
|
||||
// that uses the dot notation.
|
||||
//
|
||||
// 2) closure_member
|
||||
//
|
||||
// The named local variables of closure 'clos' above are actually
|
||||
// closure members. The closure_member class is an actor and
|
||||
// conforms to its conceptual interface. member1..memberN are
|
||||
// predefined typedefs that correspond to each of the listed types
|
||||
// in the closure template parameters.
|
||||
//
|
||||
// 3) closure_frame
|
||||
//
|
||||
// When a closure member is finally evaluated, it should refer to
|
||||
// an actual instance of the variable in the hardware stack.
|
||||
// Without doing so, the process is not complete and the evaluated
|
||||
// member will result to an assertion failure. Remember that the
|
||||
// closure is just a declaration. The local variables that a
|
||||
// closure refers to must still be instantiated.
|
||||
//
|
||||
// The closure_frame class does the actual instantiation of the
|
||||
// local variables and links these variables with the closure and
|
||||
// all its members. There can be multiple instances of
|
||||
// closure_frames typically situated in the stack inside a
|
||||
// function. Each closure_frame instance initiates a stack frame
|
||||
// with a new set of closure local variables. Example:
|
||||
//
|
||||
// void foo()
|
||||
// {
|
||||
// closure_frame<my_closure> frame(clos);
|
||||
// /* do something */
|
||||
// }
|
||||
//
|
||||
// where 'clos' is an instance of our closure 'my_closure' above.
|
||||
// Take note that the usage above precludes locally declared
|
||||
// classes. If my_closure is a locally declared type, we can still
|
||||
// use its self_type as a paramater to closure_frame:
|
||||
//
|
||||
// closure_frame<my_closure::self_type> frame(clos);
|
||||
//
|
||||
// Upon instantiation, the closure_frame links the local variables
|
||||
// to the closure. The previous link to another closure_frame
|
||||
// instance created before is saved. Upon destruction, the
|
||||
// closure_frame unlinks itself from the closure and relinks the
|
||||
// preceding closure_frame prior to this instance.
|
||||
//
|
||||
// The local variables in the closure 'clos' above is default
|
||||
// constructed in the stack inside function 'foo'. Once 'foo' is
|
||||
// exited, all of these local variables are destructed. In some
|
||||
// cases, default construction is not desirable and we need to
|
||||
// initialize the local closure variables with some values. This
|
||||
// can be done by passing in the initializers in a compatible
|
||||
// tuple. A compatible tuple is one with the same number of
|
||||
// elements as the destination and where each element from the
|
||||
// destination can be constructed from each corresponding element
|
||||
// in the source. Example:
|
||||
//
|
||||
// tuple<int, char const*, int> init(123, "Hello", 1000);
|
||||
// closure_frame<my_closure> frame(clos, init);
|
||||
//
|
||||
// Here now, our closure_frame's variables are initialized with
|
||||
// int: 123, char const*: "Hello" and int: 1000.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// closure_frame class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename ClosureT>
|
||||
class closure_frame : public ClosureT::tuple_t {
|
||||
|
||||
public:
|
||||
|
||||
closure_frame(ClosureT& clos)
|
||||
: ClosureT::tuple_t(), save(clos.frame), frame(clos.frame)
|
||||
{ clos.frame = this; }
|
||||
|
||||
template <typename TupleT>
|
||||
closure_frame(ClosureT& clos, TupleT const& init)
|
||||
: ClosureT::tuple_t(init), save(clos.frame), frame(clos.frame)
|
||||
{ clos.frame = this; }
|
||||
|
||||
~closure_frame()
|
||||
{ frame = save; }
|
||||
|
||||
private:
|
||||
|
||||
closure_frame(closure_frame const&); // no copy
|
||||
closure_frame& operator=(closure_frame const&); // no assign
|
||||
|
||||
closure_frame* save;
|
||||
closure_frame*& frame;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// closure_member class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <int N, typename ClosureT>
|
||||
class closure_member {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename ClosureT::tuple_t tuple_t;
|
||||
|
||||
closure_member()
|
||||
: frame(ClosureT::closure_frame_ref()) {}
|
||||
|
||||
template <typename TupleT>
|
||||
struct sig {
|
||||
|
||||
typedef typename detail::tuple_element_as_reference<
|
||||
N, typename ClosureT::tuple_t
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class Ret, class A, class B, class C>
|
||||
// typename detail::tuple_element_as_reference
|
||||
// <N, typename ClosureT::tuple_t>::type
|
||||
Ret
|
||||
call(A&, B&, C&) const
|
||||
{
|
||||
assert(frame);
|
||||
return boost::tuples::get<N>(*frame);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
typename ClosureT::closure_frame_t*& frame;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// closure class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <
|
||||
typename T0 = null_type,
|
||||
typename T1 = null_type,
|
||||
typename T2 = null_type,
|
||||
typename T3 = null_type,
|
||||
typename T4 = null_type
|
||||
>
|
||||
class closure {
|
||||
|
||||
public:
|
||||
|
||||
typedef tuple<T0, T1, T2, T3, T4> tuple_t;
|
||||
typedef closure<T0, T1, T2, T3, T4> self_t;
|
||||
typedef closure_frame<self_t> closure_frame_t;
|
||||
|
||||
closure()
|
||||
: frame(0) { closure_frame_ref(&frame); }
|
||||
closure_frame_t& context() { assert(frame); return frame; }
|
||||
closure_frame_t const& context() const { assert(frame); return frame; }
|
||||
|
||||
typedef lambda_functor<closure_member<0, self_t> > member1;
|
||||
typedef lambda_functor<closure_member<1, self_t> > member2;
|
||||
typedef lambda_functor<closure_member<2, self_t> > member3;
|
||||
typedef lambda_functor<closure_member<3, self_t> > member4;
|
||||
typedef lambda_functor<closure_member<4, self_t> > member5;
|
||||
|
||||
private:
|
||||
|
||||
closure(closure const&); // no copy
|
||||
closure& operator=(closure const&); // no assign
|
||||
|
||||
template <int N, typename ClosureT>
|
||||
friend struct closure_member;
|
||||
|
||||
template <typename ClosureT>
|
||||
friend class closure_frame;
|
||||
|
||||
static closure_frame_t*&
|
||||
closure_frame_ref(closure_frame_t** frame_ = 0)
|
||||
{
|
||||
static closure_frame_t** frame = 0;
|
||||
if (frame_ != 0)
|
||||
frame = frame_;
|
||||
return *frame;
|
||||
}
|
||||
|
||||
closure_frame_t* frame;
|
||||
};
|
||||
|
||||
}}
|
||||
// namespace
|
||||
|
||||
#endif
|
||||
@@ -28,7 +28,7 @@ namespace lambda {
|
||||
|
||||
template<class T> struct constructor {
|
||||
|
||||
typedef T result_type;
|
||||
template <class U> struct sig { typedef T type; };
|
||||
|
||||
T operator()() const {
|
||||
return T();
|
||||
@@ -120,8 +120,8 @@ struct destructor_helper<true> {
|
||||
// destructor funtion object
|
||||
struct destructor {
|
||||
|
||||
typedef void result_type;
|
||||
|
||||
template <class T> struct sig { typedef void type; };
|
||||
|
||||
template<class A1>
|
||||
void operator()(A1& a1) const {
|
||||
typedef typename boost::remove_cv<A1>::type plainA1;
|
||||
@@ -137,7 +137,7 @@ struct destructor {
|
||||
|
||||
template<class T> struct new_ptr {
|
||||
|
||||
typedef T* result_type;
|
||||
template <class U> struct sig { typedef T* type; };
|
||||
|
||||
T* operator()() const {
|
||||
return new T();
|
||||
@@ -199,7 +199,7 @@ template<class T> struct new_ptr {
|
||||
|
||||
struct delete_ptr {
|
||||
|
||||
typedef void result_type;
|
||||
template <class U> struct sig { typedef void type; };
|
||||
|
||||
template <class A1>
|
||||
void operator()(A1& a1) const {
|
||||
@@ -213,7 +213,7 @@ struct delete_ptr {
|
||||
|
||||
template<class T> struct new_array {
|
||||
|
||||
typedef T* result_type;
|
||||
template <class U> struct sig { typedef T* type; };
|
||||
|
||||
T* operator()(int size) const {
|
||||
return new T[size];
|
||||
@@ -225,7 +225,7 @@ template<class T> struct new_array {
|
||||
|
||||
struct delete_array {
|
||||
|
||||
typedef void result_type;
|
||||
template <class U> struct sig { typedef void type; };
|
||||
|
||||
template <class A1>
|
||||
void operator()(A1& a1) const {
|
||||
|
||||
@@ -23,5 +23,5 @@
|
||||
#include "boost/lambda/detail/operator_return_type_traits.hpp"
|
||||
|
||||
#include "boost/lambda/detail/control_structures_impl.hpp"
|
||||
#include "boost/lambda/detail/switch.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,6 @@ using ::boost::tuples::null_type;
|
||||
|
||||
#include "boost/lambda/detail/lambda_traits.hpp"
|
||||
|
||||
|
||||
#include "boost/lambda/detail/function_adaptors.hpp"
|
||||
#include "boost/lambda/detail/return_type_traits.hpp"
|
||||
|
||||
@@ -47,20 +46,20 @@ using ::boost::tuples::null_type;
|
||||
#include "boost/lambda/detail/lambda_functors.hpp"
|
||||
|
||||
#include "boost/lambda/detail/ret.hpp"
|
||||
#include "boost/lambda/detail/make_void.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
namespace {
|
||||
|
||||
boost::lambda::placeholder1_type free1;
|
||||
boost::lambda::placeholder2_type free2;
|
||||
boost::lambda::placeholder3_type free3;
|
||||
// These are constants types and need to be initialised
|
||||
boost::lambda::placeholder1_type free1 = boost::lambda::placeholder1_type();
|
||||
boost::lambda::placeholder2_type free2 = boost::lambda::placeholder2_type();
|
||||
boost::lambda::placeholder3_type free3 = boost::lambda::placeholder3_type();
|
||||
|
||||
boost::lambda::placeholder1_type& _1 = free1;
|
||||
boost::lambda::placeholder2_type& _2 = free2;
|
||||
boost::lambda::placeholder3_type& _3 = free3;
|
||||
boost::lambda::placeholder1_type& _1 = free1;
|
||||
boost::lambda::placeholder2_type& _2 = free2;
|
||||
boost::lambda::placeholder3_type& _3 = free3;
|
||||
// _1, _2, ... naming scheme by Peter Dimov
|
||||
} // unnamed
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace lambda {
|
||||
|
||||
|
||||
|
||||
template<int Arity, class Act> struct action;
|
||||
template<int Arity, class Act> class action;
|
||||
|
||||
// these need to be defined here, since the corresponding lambda
|
||||
// functions are members of lambda_functor classes
|
||||
@@ -31,27 +31,38 @@ template<int Arity, class Act> struct action;
|
||||
class assignment_action {};
|
||||
class subscript_action {};
|
||||
|
||||
class identity_action {};
|
||||
|
||||
template <class Action> class other_action;
|
||||
|
||||
|
||||
// action for specifying the explicit return type
|
||||
template <class RET> class explicit_return_type_action {};
|
||||
|
||||
// action for preventing the expansion of a lambda expression
|
||||
struct protect_action {};
|
||||
|
||||
// action for curried functions, I stands for the number of curried arguments
|
||||
// (can be 1 or 2)
|
||||
template <int I> class curry_action {};
|
||||
|
||||
template <class Action> class return_void_action;
|
||||
|
||||
// must be defined here, comma is a special case
|
||||
struct comma_action {};
|
||||
|
||||
|
||||
// actions, for which the existence of protect is checked in return type
|
||||
// deduction.
|
||||
|
||||
template <class Action> struct is_protectable {
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
|
||||
// NOTE: comma action is protectable. Other protectable actions
|
||||
// are listed in operator_actions.hpp
|
||||
|
||||
template<> struct is_protectable<other_action<comma_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
// this type is used in return type deductions to signal that deduction
|
||||
// did not find a result. It does not necessarily mean an error, it commonly
|
||||
// means that something else should be tried.
|
||||
class unspecified {};
|
||||
}
|
||||
|
||||
@@ -61,18 +72,15 @@ namespace detail {
|
||||
// argument of function_action template. Otherwise the argument gets the type
|
||||
// 'unspecified'.
|
||||
// This argument is only relevant in the return type deduction code
|
||||
template <int I, class Result_type = detail::unspecified> class function_action {};
|
||||
template <int I, class Result_type = detail::unspecified>
|
||||
class function_action {};
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
template<class T> class function_action<1, T> {
|
||||
public:
|
||||
template<class RET, class A1>
|
||||
static RET apply(A1& a1) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>(a1);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,23 +88,17 @@ template<class T> class function_action<2, T> {
|
||||
public:
|
||||
template<class RET, class A1, class A2>
|
||||
static RET apply(A1& a1, A2& a2) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T> struct is_lambda_functor;
|
||||
template<class T> class function_action<3, T> {
|
||||
public:
|
||||
|
||||
template<class RET, class A1, class A2, class A3>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3) {
|
||||
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3);
|
||||
|
||||
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,8 +106,8 @@ template<class T> class function_action<4, T> {
|
||||
public:
|
||||
template<class RET, class A1, class A2, class A3, class A4>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,8 +115,8 @@ template<class T> class function_action<5, T> {
|
||||
public:
|
||||
template<class RET, class A1, class A2, class A3, class A4, class A5>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4, a5);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4, a5);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -123,8 +125,8 @@ public:
|
||||
template<class RET, class A1, class A2, class A3, class A4, class A5,
|
||||
class A6>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4, a5, a6);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -133,8 +135,8 @@ public:
|
||||
template<class RET, class A1, class A2, class A3, class A4, class A5,
|
||||
class A6, class A7>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4, a5, a6, a7);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,8 +146,8 @@ public:
|
||||
class A6, class A7, class A8>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7,
|
||||
A8& a8) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,8 +157,8 @@ public:
|
||||
class A6, class A7, class A8, class A9>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7,
|
||||
A8& a8, A9& a9) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -166,32 +168,11 @@ public:
|
||||
class A6, class A7, class A8, class A9, class A10>
|
||||
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7,
|
||||
A8& a8, A9& a9, A10& a10) {
|
||||
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
|
||||
(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
|
||||
return function_adaptor<typename boost::remove_cv<A1>::type>::
|
||||
template apply<RET>(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
|
||||
}
|
||||
};
|
||||
|
||||
// actions, for which the existence of protect is checked in return type
|
||||
// deduction.
|
||||
class protectable {};
|
||||
|
||||
namespace detail {
|
||||
template<class T> struct is_protectable_action {
|
||||
BOOST_STATIC_CONSTANT(bool, value = (boost::is_base_and_derived<protectable, T>::value));
|
||||
};
|
||||
|
||||
template<> struct is_protectable_action<other_action<assignment_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<> struct is_protectable_action<other_action<comma_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -32,93 +32,80 @@ namespace lambda {
|
||||
// freeE placeholders and maybe free1 and free2 (EXCEPTION).
|
||||
// RETHROW means, that a rethrow expression is used somewhere in the lambda_functor.
|
||||
|
||||
enum { NONE = 0x00, // Notice we are using bits as flags here.
|
||||
FIRST = 0x01,
|
||||
SECOND = 0x02,
|
||||
THIRD = 0x04,
|
||||
EXCEPTION = 0x08,
|
||||
RETHROW = 0x10};
|
||||
enum { NONE = 0x00, // Notice we are using bits as flags here.
|
||||
FIRST = 0x01,
|
||||
SECOND = 0x02,
|
||||
THIRD = 0x04,
|
||||
EXCEPTION = 0x08,
|
||||
RETHROW = 0x10};
|
||||
|
||||
|
||||
// -- dig the arity from lambda_functor_args;
|
||||
template <class T> struct dig_arity;
|
||||
|
||||
template<class T>
|
||||
struct get_tuple_arity;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T> struct get_arity_;
|
||||
|
||||
} // end detail;
|
||||
|
||||
template <class T> struct get_arity {
|
||||
|
||||
BOOST_STATIC_CONSTANT(int, value = detail::get_arity_<typename boost::remove_cv<typename boost::remove_reference<T>::type>::type>::value);
|
||||
|
||||
template <int Arity, int Step> struct reduce_arity
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(int, value = Arity >> Step);
|
||||
};
|
||||
|
||||
// The implementation template, do not instantiate this directly
|
||||
template <class Arg> struct dig_arity_ {
|
||||
static const int value = NONE;
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
struct get_arity_ {
|
||||
BOOST_STATIC_CONSTANT(int, value = 0);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct get_arity_<lambda_functor<T> > {
|
||||
BOOST_STATIC_CONSTANT(int, value = get_arity<T>::value);
|
||||
};
|
||||
|
||||
template<class Action, class Args>
|
||||
struct get_arity_<lambda_functor_base<Action, Args> > {
|
||||
BOOST_STATIC_CONSTANT(int, value = get_tuple_arity<Args>::value);
|
||||
};
|
||||
|
||||
template<int I>
|
||||
struct get_arity_<placeholder<I> > {
|
||||
BOOST_STATIC_CONSTANT(int, value = I);
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
template<class T>
|
||||
struct get_tuple_arity {
|
||||
BOOST_STATIC_CONSTANT(int, value = get_arity<typename T::head_type>::value | get_tuple_arity<typename T::tail_type>::value);
|
||||
};
|
||||
|
||||
|
||||
template <class Args> struct dig_arity_<lambda_functor<Args> > {
|
||||
static const int value = dig_arity<Args>::value;
|
||||
// Args should be always plain, so it would be safe to instantiatie dig_arity_
|
||||
// To be very sure, we use dig_arity
|
||||
template<>
|
||||
struct get_tuple_arity<null_type> {
|
||||
BOOST_STATIC_CONSTANT(int, value = 0);
|
||||
};
|
||||
|
||||
template <class Act, class Args, int ArityCode>
|
||||
struct dig_arity_<lambda_functor_args<Act, Args, ArityCode> >{
|
||||
static const int value = ArityCode;
|
||||
|
||||
// Does T have placeholder<I> as it's subexpression?
|
||||
|
||||
template<class T, int I>
|
||||
struct has_placeholder {
|
||||
BOOST_STATIC_CONSTANT(bool, value = (get_arity<T>::value & I) != 0);
|
||||
};
|
||||
|
||||
template<int I, int J>
|
||||
struct includes_placeholder {
|
||||
BOOST_STATIC_CONSTANT(bool, value = (J & I) != 0);
|
||||
};
|
||||
|
||||
template <int I> struct dig_arity_<placeholder<I> > {
|
||||
static const int value = I;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// -- dig the arity from lambda_functor_args;
|
||||
template <class Arg> struct dig_arity {
|
||||
static const int value =
|
||||
detail::dig_arity_<
|
||||
typename boost::remove_cv<
|
||||
typename boost::remove_reference<Arg>::type
|
||||
>::type
|
||||
>::value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// compute the arity of a lambda expression (find the highest placeholder)
|
||||
|
||||
template <class A1 = boost::tuples::null_type,
|
||||
class A2 = boost::tuples::null_type,
|
||||
class A3 = boost::tuples::null_type,
|
||||
class A4 = boost::tuples::null_type,
|
||||
class A5 = boost::tuples::null_type,
|
||||
class A6 = boost::tuples::null_type,
|
||||
class A7 = boost::tuples::null_type,
|
||||
class A8 = boost::tuples::null_type,
|
||||
class A9 = boost::tuples::null_type,
|
||||
class A10 = boost::tuples::null_type>
|
||||
struct combine_arities {
|
||||
static const int ored_value =
|
||||
dig_arity<A1>::value |
|
||||
dig_arity<A2>::value |
|
||||
dig_arity<A3>::value |
|
||||
dig_arity<A4>::value |
|
||||
dig_arity<A5>::value |
|
||||
dig_arity<A6>::value |
|
||||
dig_arity<A7>::value |
|
||||
dig_arity<A8>::value |
|
||||
dig_arity<A9>::value |
|
||||
dig_arity<A10>::value;
|
||||
|
||||
// leave the highest placeholder bit on, set the lower off
|
||||
// EXCEPTION and RETHROW bits are retained as they are
|
||||
static const int value = (ored_value & THIRD
|
||||
? THIRD
|
||||
: (ored_value & SECOND
|
||||
? SECOND
|
||||
: ored_value)) | ( (EXCEPTION | RETHROW) & ored_value);
|
||||
|
||||
template<int I, int J>
|
||||
struct lacks_placeholder {
|
||||
BOOST_STATIC_CONSTANT(bool, value = ((J & I) == 0));
|
||||
};
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
55
include/boost/lambda/detail/control_constructs_common.hpp
Normal file
55
include/boost/lambda/detail/control_constructs_common.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// Boost Lambda Library -- control_constructs_common.hpp -------------------
|
||||
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
// Copyright (C) 2000 Gary Powell (gary.powell@sierra.com)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(BOOST_CONTROL_CONSTRUCTS_COMMON_HPP)
|
||||
#define BOOST_CONTROL_CONSTRUCTS_COMMON_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
// special types of lambda functors, used with control structures
|
||||
// to guarantee that they are composed correctly.
|
||||
|
||||
template<class Tag, class LambdaFunctor>
|
||||
class tagged_lambda_functor;
|
||||
|
||||
template<class Tag, class Args>
|
||||
class tagged_lambda_functor<Tag, lambda_functor<Args> >
|
||||
: public lambda_functor<Args>
|
||||
{
|
||||
public:
|
||||
tagged_lambda_functor(const Args& a) : lambda_functor<Args>(a) {}
|
||||
|
||||
tagged_lambda_functor(const lambda_functor<Args>& a)
|
||||
: lambda_functor<Args>(a) {}
|
||||
|
||||
// for the no body cases in control structures.
|
||||
tagged_lambda_functor() : lambda_functor<Args>() {}
|
||||
};
|
||||
|
||||
} // lambda
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_CONTROL_CONSTRUCTS_COMMON_HPP
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,36 +25,35 @@ namespace lambda {
|
||||
// -- void return control actions ----------------------
|
||||
|
||||
class forloop_action {};
|
||||
class forloop_no_body_action {};
|
||||
class ifthen_action {};
|
||||
class ifthenelse_action {};
|
||||
class whileloop_action {};
|
||||
class whileloop_no_body_action {};
|
||||
class dowhileloop_action {};
|
||||
|
||||
class dowhileloop_no_body_action {};
|
||||
// -- nonvoid return control actions ----------------------
|
||||
|
||||
class ifthenelsereturn_action {};
|
||||
|
||||
// For loop
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<4, return_void_action<forloop_action> >,
|
||||
lambda_functor_base<
|
||||
forloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >,
|
||||
combine_arities<Arg1, Arg2, Arg3, Arg4>::value
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >
|
||||
>
|
||||
>
|
||||
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
const lambda_functor<Arg3>& a3, const lambda_functor<Arg4>& a4) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<4, return_void_action<forloop_action> >,
|
||||
lambda_functor_base<
|
||||
forloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >,
|
||||
combine_arities<Arg1, Arg2, Arg3, Arg4>::value
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >
|
||||
>
|
||||
>
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >(a1, a2, a3, a4)
|
||||
);
|
||||
@@ -64,23 +63,20 @@ for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
template <class Arg1, class Arg2, class Arg3>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, return_void_action<forloop_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >,
|
||||
combine_arities<Arg1, Arg2, Arg3>::value
|
||||
lambda_functor_base<
|
||||
forloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
>
|
||||
>
|
||||
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
const lambda_functor<Arg3>& a3) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, return_void_action<forloop_action> >,
|
||||
lambda_functor_base<
|
||||
forloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3> >,
|
||||
combine_arities<Arg1, Arg2, Arg3>::value
|
||||
lambda_functor<Arg3> >
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3> >(a1, a2, a3) );
|
||||
}
|
||||
|
||||
@@ -88,42 +84,36 @@ for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
template <class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, return_void_action<whileloop_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
lambda_functor_base<
|
||||
whileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, return_void_action<whileloop_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
lambda_functor_base<
|
||||
whileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
}
|
||||
|
||||
// No body case.
|
||||
template <class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<whileloop_action> >,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
combine_arities<Arg1>::value
|
||||
lambda_functor_base<
|
||||
whileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
while_loop(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<whileloop_action> >,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
combine_arities<Arg1>::value
|
||||
lambda_functor_base<
|
||||
whileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1> >(a1) );
|
||||
( tuple<lambda_functor<Arg1> >(a1) );
|
||||
}
|
||||
|
||||
|
||||
@@ -131,42 +121,36 @@ while_loop(const lambda_functor<Arg1>& a1) {
|
||||
template <class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, return_void_action<dowhileloop_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
lambda_functor_base<
|
||||
dowhileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
do_while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, return_void_action<dowhileloop_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
lambda_functor_base<
|
||||
dowhileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
}
|
||||
|
||||
// No body case.
|
||||
template <class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<dowhileloop_action> >,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
combine_arities<Arg1>::value
|
||||
lambda_functor_base<
|
||||
dowhileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
do_while_loop(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<dowhileloop_action> >,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
combine_arities<Arg1>::value
|
||||
lambda_functor_base<
|
||||
dowhileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1> >(a1));
|
||||
( tuple<lambda_functor<Arg1> >(a1));
|
||||
}
|
||||
|
||||
|
||||
@@ -174,20 +158,18 @@ do_while_loop(const lambda_functor<Arg1>& a1) {
|
||||
template <class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, return_void_action<ifthen_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
lambda_functor_base<
|
||||
ifthen_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<action<2, return_void_action<ifthen_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
lambda_functor_base<
|
||||
ifthen_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
|
||||
}
|
||||
|
||||
// If then else
|
||||
@@ -195,21 +177,17 @@ if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
template <class Arg1, class Arg2, class Arg3>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, return_void_action<ifthenelse_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >,
|
||||
combine_arities<Arg1, Arg2, Arg3>::value
|
||||
lambda_functor_base<
|
||||
ifthenelse_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
>
|
||||
>
|
||||
if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
const lambda_functor<Arg3>& a3) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, return_void_action<ifthenelse_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >,
|
||||
combine_arities<Arg1, Arg2, Arg3>::value
|
||||
>
|
||||
lambda_functor_base<
|
||||
ifthenelse_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
>
|
||||
(tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
(a1, a2, a3) );
|
||||
@@ -220,28 +198,25 @@ if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
template <class Arg1, class Arg2, class Arg3>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<action<3, other_action<ifthenelsereturn_action> >,
|
||||
tuple<lambda_functor<Arg1>,
|
||||
lambda_functor_base<
|
||||
other_action<ifthenelsereturn_action>,
|
||||
tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type,
|
||||
typename const_copy_argument<Arg3>::type>,
|
||||
combine_arities<Arg1, Arg2, Arg3>::value
|
||||
typename const_copy_argument<Arg3>::type>
|
||||
>
|
||||
>
|
||||
if_then_else_return(const lambda_functor<Arg1>& a1,
|
||||
const Arg2 & a2,
|
||||
const Arg3 & a3) {
|
||||
const Arg2 & a2,
|
||||
const Arg3 & a3) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<3, other_action<ifthenelsereturn_action> >,
|
||||
lambda_functor_base<
|
||||
other_action<ifthenelsereturn_action>,
|
||||
tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type,
|
||||
typename const_copy_argument<Arg3>::type>,
|
||||
combine_arities<Arg1, Arg2, Arg3>::value
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg3>::type>
|
||||
> ( tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type,
|
||||
typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
|
||||
typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -296,7 +271,7 @@ struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
|
||||
2,
|
||||
boost::is_convertible<plainA,plainB>::value,
|
||||
boost::is_convertible<plainB,plainA>::value,
|
||||
boost::is_same<plainA,plainB>::value,
|
||||
boost::is_same<plainA,plainB>::value,
|
||||
plainA,
|
||||
plainB>::type type;
|
||||
};
|
||||
@@ -392,25 +367,6 @@ struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
|
||||
};
|
||||
|
||||
// PHASE 1 : Deduction is based on the second and third operand
|
||||
template <class Args, int Code, class Open>
|
||||
struct return_type<
|
||||
lambda_functor_args<
|
||||
action<3, other_action<ifthenelsereturn_action> >,
|
||||
Args,
|
||||
Code>,
|
||||
Open
|
||||
> {
|
||||
typedef
|
||||
typename return_type_2<
|
||||
other_action<ifthenelsereturn_action>,
|
||||
typename return_type<
|
||||
typename detail::tuple_element_as_reference<1, Args>::type, Open
|
||||
>::type,
|
||||
typename return_type<
|
||||
typename detail::tuple_element_as_reference<2, Args>::type, Open
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
// return type specialization for conditional expression ends -----------
|
||||
@@ -423,36 +379,38 @@ struct return_type<
|
||||
// Specialization for for_loop.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<4, return_void_action<forloop_action> >, Args> {
|
||||
lambda_functor_base<forloop_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
for(detail::select(boost::tuples::get<0>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<2>(args), a, b, c))
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
for(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS))
|
||||
|
||||
detail::select(boost::tuples::get<3>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<3>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// No body case
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<3, return_void_action<forloop_action> >, Args> {
|
||||
lambda_functor_base<forloop_no_body_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
for(detail::select(boost::tuples::get<0>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<2>(args), a, b, c)) {}
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
for(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS)) {}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -460,32 +418,34 @@ public:
|
||||
// Specialization for while_loop.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<2, return_void_action<whileloop_action> >, Args> {
|
||||
lambda_functor_base<whileloop_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
while(detail::select(boost::tuples::get<0>(args), a, b, c))
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
while(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
|
||||
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// No body case
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<1, return_void_action<whileloop_action> >, Args> {
|
||||
lambda_functor_base<whileloop_no_body_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
while(detail::select(boost::tuples::get<0>(args), a, b, c)) {}
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
while(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) {}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -493,32 +453,34 @@ public:
|
||||
// Note that the first argument is the condition.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<2, return_void_action<dowhileloop_action> >, Args> {
|
||||
lambda_functor_base<dowhileloop_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
do {
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
} while (detail::select(boost::tuples::get<0>(args), a, b, c) );
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
|
||||
}
|
||||
};
|
||||
|
||||
// No body case
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<1, return_void_action<dowhileloop_action> >, Args> {
|
||||
lambda_functor_base<dowhileloop_no_body_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
do {} while (detail::select(boost::tuples::get<0>(args), a, b, c) );
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
do {} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
|
||||
}
|
||||
};
|
||||
|
||||
@@ -526,51 +488,64 @@ public:
|
||||
// Specialization for if_then.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<2, return_void_action<ifthen_action> >, Args> {
|
||||
lambda_functor_base<ifthen_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
if (detail::select(boost::tuples::get<0>(args), a, b, c)) detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for if_then_else.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<3, return_void_action<ifthenelse_action> >, Args> {
|
||||
lambda_functor_base<ifthenelse_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
if (detail::select(boost::tuples::get<0>(args), a, b, c))
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
else
|
||||
detail::select(boost::tuples::get<2>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of lambda_functor_base for if_then_else_return.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<action<3, other_action<ifthenelsereturn_action> >, Args> {
|
||||
lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
|
||||
public:
|
||||
Args args;
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
private:
|
||||
typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
|
||||
typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
|
||||
public:
|
||||
typedef typename return_type_2<
|
||||
other_action<ifthenelsereturn_action>, ret1, ret2
|
||||
>::type type;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
return (detail::select(boost::tuples::get<0>(args), a, b, c)) ?
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c)
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)
|
||||
:
|
||||
detail::select(boost::tuples::get<2>(args), a, b, c);
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,18 @@ namespace lambda {
|
||||
|
||||
template <class Func> struct function_adaptor {
|
||||
|
||||
typedef detail::unspecified type;
|
||||
// we do not know the return type off-hand, we must ask it from Func
|
||||
template <class Args> class sig {
|
||||
typedef typename Args::head_type F;
|
||||
typedef typename detail::remove_reference_and_cv<Func>::type plainF;
|
||||
public:
|
||||
// To sig we pass a cons list, where the head is the function object type
|
||||
// itself (potentially cv-qualified)
|
||||
// and the tail contains the types of the actual arguments to be passed
|
||||
// to the function object. The arguments can be cv qualified
|
||||
// as well.
|
||||
typedef typename plainF::template sig<Args>::type type;
|
||||
};
|
||||
|
||||
template<class RET, class A1>
|
||||
static RET apply(A1& a1) {
|
||||
@@ -76,11 +87,77 @@ template <class Func> struct function_adaptor {
|
||||
}
|
||||
};
|
||||
|
||||
template <class Func> struct function_adaptor<const Func>; // error
|
||||
|
||||
// -- function adaptors with data member access
|
||||
template <class Object, class T>
|
||||
struct function_adaptor<T Object::*> {
|
||||
|
||||
// typedef detail::unspecified type;
|
||||
|
||||
// T can have qualifiers and can be a reference type
|
||||
// We get the return type by adding const, if the object through which
|
||||
// the data member is accessed is const, and finally adding a reference
|
||||
template<class Args> class sig {
|
||||
typedef typename boost::tuples::element<1, Args>::type argument_type;
|
||||
|
||||
typedef typename detail::IF<boost::is_const<argument_type>::value,
|
||||
typename boost::add_const<T>::type,
|
||||
T
|
||||
>::RET properly_consted_return_type;
|
||||
|
||||
typedef typename detail::IF<
|
||||
boost::is_volatile<properly_consted_return_type>::value,
|
||||
typename boost::add_volatile<properly_consted_return_type>::type,
|
||||
properly_consted_return_type
|
||||
>::RET properly_cvd_return_type;
|
||||
|
||||
|
||||
public:
|
||||
typedef typename
|
||||
boost::add_reference<properly_cvd_return_type>::type type;
|
||||
};
|
||||
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, Object& o) {
|
||||
return o.*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, const Object& o) {
|
||||
return o.*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, volatile Object& o) {
|
||||
return o.*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, const volatile Object& o) {
|
||||
return o.*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, Object* o) {
|
||||
return o->*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, const Object* o) {
|
||||
return o->*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, volatile Object* o) {
|
||||
return o->*data;
|
||||
}
|
||||
template <class RET>
|
||||
static RET apply( T Object::*data, const volatile Object* o) {
|
||||
return o->*data;
|
||||
}
|
||||
};
|
||||
|
||||
// -- function adaptors with 1 argument apply
|
||||
|
||||
template <class Result>
|
||||
struct function_adaptor<Result (void)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET>
|
||||
static Result apply(Result (*func)()) {
|
||||
return func();
|
||||
@@ -89,7 +166,8 @@ struct function_adaptor<Result (void)> {
|
||||
|
||||
template <class Result>
|
||||
struct function_adaptor<Result (*)(void)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET>
|
||||
static Result apply(Result (*func)()) {
|
||||
return func();
|
||||
@@ -100,7 +178,8 @@ struct function_adaptor<Result (*)(void)> {
|
||||
// -- function adaptors with 2 argument apply
|
||||
template <class Object, class Result>
|
||||
struct function_adaptor<Result (Object::*)() const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET>
|
||||
static Result apply( Result (Object::*func)() const, const Object* o) {
|
||||
return (o->*func)();
|
||||
@@ -113,7 +192,8 @@ struct function_adaptor<Result (Object::*)() const> {
|
||||
|
||||
template <class Object, class Result>
|
||||
struct function_adaptor<Result (Object::*)()> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET>
|
||||
static Result apply( Result (Object::*func)(), Object* o) {
|
||||
return (o->*func)();
|
||||
@@ -126,7 +206,8 @@ struct function_adaptor<Result (Object::*)()> {
|
||||
|
||||
template <class Arg1, class Result>
|
||||
struct function_adaptor<Result (Arg1)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1>
|
||||
static Result apply(Result (*func)(Arg1), A1& a1) {
|
||||
return func(a1);
|
||||
@@ -135,7 +216,8 @@ struct function_adaptor<Result (Arg1)> {
|
||||
|
||||
template <class Arg1, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1>
|
||||
static Result apply(Result (*func)(Arg1), A1& a1) {
|
||||
return func(a1);
|
||||
@@ -146,20 +228,24 @@ struct function_adaptor<Result (*)(Arg1)> {
|
||||
// -- function adaptors with 3 argument apply
|
||||
template <class Object, class Arg1, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1>
|
||||
static Result apply( Result (Object::*func)(Arg1) const, const Object* o, A1& a1) {
|
||||
static Result apply( Result (Object::*func)(Arg1) const, const Object* o,
|
||||
A1& a1) {
|
||||
return (o->*func)(a1);
|
||||
}
|
||||
template <class RET, class A1>
|
||||
static Result apply( Result (Object::*func)(Arg1) const, const Object& o, A1& a1) {
|
||||
static Result apply( Result (Object::*func)(Arg1) const, const Object& o,
|
||||
A1& a1) {
|
||||
return (o.*func)(a1);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Object, class Arg1, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1>
|
||||
static Result apply( Result (Object::*func)(Arg1), Object* o, A1& a1) {
|
||||
return (o->*func)(a1);
|
||||
@@ -172,7 +258,8 @@ struct function_adaptor<Result (Object::*)(Arg1)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2>
|
||||
static Result apply(Result (*func)(Arg1, Arg2), A1& a1, A2& a2) {
|
||||
return func(a1, a2);
|
||||
@@ -181,7 +268,8 @@ struct function_adaptor<Result (Arg1, Arg2)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2>
|
||||
static Result apply(Result (*func)(Arg1, Arg2), A1& a1, A2& a2) {
|
||||
return func(a1, a2);
|
||||
@@ -192,7 +280,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2)> {
|
||||
// -- function adaptors with 4 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2) const, const Object* o, A1& a1, A2& a2) {
|
||||
return (o->*func)(a1, a2);
|
||||
@@ -205,7 +294,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2) const> {
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2), Object* o, A1& a1, A2& a2) {
|
||||
return (o->*func)(a1, a2);
|
||||
@@ -218,7 +308,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3), A1& a1, A2& a2, A3& a3) {
|
||||
return func(a1, a2, a3);
|
||||
@@ -227,7 +318,8 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3), A1& a1, A2& a2, A3& a3) {
|
||||
return func(a1, a2, a3);
|
||||
@@ -238,7 +330,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3)> {
|
||||
// -- function adaptors with 5 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3) const, const Object* o, A1& a1, A2& a2, A3& a3) {
|
||||
return (o->*func)(a1, a2, a3);
|
||||
@@ -251,7 +344,7 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3) const> {
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3)> {
|
||||
typedef Result type;
|
||||
|
||||
template <class RET, class A1, class A2, class A3>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3), Object* o, A1& a1, A2& a2, A3& a3) {
|
||||
return (o->*func)(a1, a2, a3);
|
||||
@@ -264,7 +357,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4), A1& a1, A2& a2, A3& a3, A4& a4) {
|
||||
return func(a1, a2, a3, a4);
|
||||
@@ -273,7 +367,8 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4), A1& a1, A2& a2, A3& a3, A4& a4) {
|
||||
return func(a1, a2, a3, a4);
|
||||
@@ -284,7 +379,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4)> {
|
||||
// -- function adaptors with 6 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4) const, const Object* o, A1& a1, A2& a2, A3& a3, A4& a4) {
|
||||
return (o->*func)(a1, a2, a3, a4);
|
||||
@@ -297,7 +393,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4) const> {
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4), Object* o, A1& a1, A2& a2, A3& a3, A4& a4) {
|
||||
return (o->*func)(a1, a2, a3, a4);
|
||||
@@ -310,7 +407,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) {
|
||||
return func(a1, a2, a3, a4, a5);
|
||||
@@ -319,7 +417,8 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) {
|
||||
return func(a1, a2, a3, a4, a5);
|
||||
@@ -330,7 +429,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5)> {
|
||||
// -- function adaptors with 7 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5) const, const Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5);
|
||||
@@ -343,7 +443,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5) const>
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5), Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5);
|
||||
@@ -356,7 +457,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) {
|
||||
return func(a1, a2, a3, a4, a5, a6);
|
||||
@@ -365,7 +467,8 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) {
|
||||
return func(a1, a2, a3, a4, a5, a6);
|
||||
@@ -376,7 +479,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
|
||||
// -- function adaptors with 8 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const, const Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5, a6);
|
||||
@@ -389,7 +493,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) c
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5, a6);
|
||||
@@ -402,7 +507,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)>
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) {
|
||||
return func(a1, a2, a3, a4, a5, a6, a7);
|
||||
@@ -411,7 +517,8 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) {
|
||||
return func(a1, a2, a3, a4, a5, a6, a7);
|
||||
@@ -422,7 +529,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
|
||||
// -- function adaptors with 9 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const, const Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5, a6, a7);
|
||||
@@ -435,7 +543,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, A
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7), Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5, a6, a7);
|
||||
@@ -448,7 +557,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, A
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) {
|
||||
return func(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
@@ -457,7 +567,8 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)>
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) {
|
||||
return func(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
@@ -468,7 +579,8 @@ struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg
|
||||
// -- function adaptors with 10 argument apply
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) const> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) const, const Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
@@ -481,7 +593,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, A
|
||||
|
||||
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
|
||||
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
||||
static Result apply( Result (Object::*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8), Object* o, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) {
|
||||
return (o->*func)(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
@@ -494,7 +607,8 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, A
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Arg9, class Result>
|
||||
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9)> {
|
||||
typedef Result type;
|
||||
|
||||
template<class T> struct sig { typedef Result type; };
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9) {
|
||||
return func(a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
@@ -503,83 +617,13 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8,
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Arg9, class Result>
|
||||
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9)> {
|
||||
typedef Result type;
|
||||
|
||||
template <class RET, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
||||
static Result apply(Result (*func)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9), A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9) {
|
||||
return func(a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
}
|
||||
};
|
||||
|
||||
// we want to instantiate function adaptor from different places.
|
||||
// sometimes Func does not have the result_type defined. It is therefore
|
||||
// queried in a separate subclass.
|
||||
// Thus the super class can be
|
||||
// instantiated even with a Func that does no have result_type
|
||||
|
||||
|
||||
struct has_sig {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class F> struct get_result_type {
|
||||
typedef typename F::result_type type;
|
||||
};
|
||||
|
||||
template <class Args> class get_sig_result_type {
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename detail::remove_reference_and_cv<Func>::type plainF;
|
||||
public:
|
||||
// To sig we pass a cons list, where the head is the function object type
|
||||
// itself (potentially cv-qualified, always a reference type)
|
||||
// and the tail contains the types of the actual arguments to be passed
|
||||
// to the function object. The arguments are reference types
|
||||
typedef typename plainF::template sig<Args>::type type;
|
||||
};
|
||||
|
||||
|
||||
// check for a member typedef return_type or an member class template sig
|
||||
template <class Args> class get_functor_result_type {
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename detail::remove_reference_and_cv<Func>::type plain_F;
|
||||
|
||||
public:
|
||||
// if the function object inherits from has_sig, we check for sig
|
||||
// otherwise for result_type typedef
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
boost::is_base_and_derived<has_sig, plain_F>::value,
|
||||
detail::get_sig_result_type<Args>,
|
||||
detail::get_result_type<plain_F>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
} // end detail
|
||||
|
||||
|
||||
template <class Args>
|
||||
class function_adaptor_with_actuals
|
||||
{
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename detail::remove_reference_and_cv<Func>::type plain_Func;
|
||||
typedef typename function_adaptor<plain_Func>::type type1;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
detail::get_functor_result_type<
|
||||
Args // old code: boost::tuples::cons<Func, typename Args::tail_type>
|
||||
>, // it's ok to try this (an arbitrary func. object)
|
||||
function_adaptor<plain_Func>
|
||||
// Here we know Func's ret type
|
||||
// (func is a member function or function pointer/reference)
|
||||
>::type type;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -56,30 +56,30 @@
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
#define BOOST_LAMBDA_IS_INSTANCE_OF_TEMPLATE(INDEX) \
|
||||
\
|
||||
namespace detail { \
|
||||
\
|
||||
template <template<BOOST_LAMBDA_CLASS_LIST(INDEX,T)> class F> \
|
||||
struct BOOST_PP_CAT(conversion_tester_,INDEX) { \
|
||||
template<BOOST_LAMBDA_CLASS_ARG_LIST(INDEX,A)> \
|
||||
BOOST_PP_CAT(conversion_tester_,INDEX) \
|
||||
(const F<BOOST_LAMBDA_ARG_LIST(INDEX,A)>&); \
|
||||
}; \
|
||||
\
|
||||
} /* end detail */ \
|
||||
\
|
||||
#define BOOST_LAMBDA_IS_INSTANCE_OF_TEMPLATE(INDEX) \
|
||||
\
|
||||
namespace detail { \
|
||||
\
|
||||
template <template<BOOST_LAMBDA_CLASS_LIST(INDEX,T)> class F> \
|
||||
struct BOOST_PP_CAT(conversion_tester_,INDEX) { \
|
||||
template<BOOST_LAMBDA_CLASS_ARG_LIST(INDEX,A)> \
|
||||
BOOST_PP_CAT(conversion_tester_,INDEX) \
|
||||
(const F<BOOST_LAMBDA_ARG_LIST(INDEX,A)>&); \
|
||||
}; \
|
||||
\
|
||||
} /* end detail */ \
|
||||
\
|
||||
template <class From, template <BOOST_LAMBDA_CLASS_LIST(INDEX,T)> class To> \
|
||||
struct BOOST_PP_CAT(is_instance_of_,INDEX) \
|
||||
{ \
|
||||
private: \
|
||||
typedef ::boost::is_convertible< \
|
||||
From, \
|
||||
BOOST_PP_CAT(detail::conversion_tester_,INDEX)<To> \
|
||||
> helper_type; \
|
||||
\
|
||||
public: \
|
||||
BOOST_STATIC_CONSTANT(bool, value = helper_type::value); \
|
||||
struct BOOST_PP_CAT(is_instance_of_,INDEX) \
|
||||
{ \
|
||||
private: \
|
||||
typedef ::boost::is_convertible< \
|
||||
From, \
|
||||
BOOST_PP_CAT(detail::conversion_tester_,INDEX)<To> \
|
||||
> helper_type; \
|
||||
\
|
||||
public: \
|
||||
BOOST_STATIC_CONSTANT(bool, value = helper_type::value); \
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -27,12 +27,15 @@
|
||||
#define BOOST_NO_TEMPLATED_STREAMS
|
||||
#define BOOST_LAMBDA_INCORRECT_BIND_OVERLOADING
|
||||
#endif
|
||||
# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 95)
|
||||
#define BOOST_LAMBDA_FAILS_IN_TEMPLATE_KEYWORD_AFTER_SCOPE_OPER
|
||||
#endif
|
||||
#endif // __GNUC__
|
||||
|
||||
|
||||
#if defined __KCC
|
||||
|
||||
# if defined __KCC
|
||||
|
||||
#define BOOST_NO_FORWARD_DECLARADED_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMETERS
|
||||
#define BOOST_NO_FDECL_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMS
|
||||
|
||||
#endif // __KCC
|
||||
|
||||
|
||||
@@ -21,32 +21,239 @@
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
|
||||
// for return type deductions we wrap bound argument to this class,
|
||||
// which fulfils the base class contract for lambda_functors
|
||||
template <class T>
|
||||
class identity {
|
||||
|
||||
T elem;
|
||||
public:
|
||||
|
||||
typedef T element_t;
|
||||
|
||||
// take all parameters as const rererences. Note that non-const references
|
||||
// stay as they are.
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<T>::type
|
||||
>::type par_t;
|
||||
|
||||
explicit identity(par_t t) : elem(t) {}
|
||||
|
||||
template <typename SigArgs>
|
||||
struct sig { typedef element_t type; };
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const { CALL_USE_ARGS; return elem; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline lambda_functor<identity<T&> > var(T& t) { return identity<T&>(t); }
|
||||
|
||||
// for lambda functors, var is an identity operator. It was forbidden
|
||||
// at some point, but we might want to var something that can be a
|
||||
// non-lambda functor or a lambda functor.
|
||||
template <class T>
|
||||
lambda_functor<T> var(const lambda_functor<T>& t) { return t; }
|
||||
|
||||
template <class T> struct var_type {
|
||||
typedef lambda_functor<identity<T&> > type;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
lambda_functor<identity<typename bound_argument_conversion<const T>::type> >
|
||||
constant(const T& t) {
|
||||
return identity<typename bound_argument_conversion<const T>::type>(t);
|
||||
}
|
||||
template <class T>
|
||||
lambda_functor<T> constant(const lambda_functor<T>& t) { return t; }
|
||||
|
||||
template <class T> struct constant_type {
|
||||
typedef
|
||||
lambda_functor<
|
||||
identity<typename bound_argument_conversion<const T>::type>
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
inline lambda_functor<identity<const T&> > constant_ref(const T& t) {
|
||||
return identity<const T&>(t);
|
||||
}
|
||||
template <class T>
|
||||
lambda_functor<T> constant_ref(const lambda_functor<T>& t) { return t; }
|
||||
|
||||
template <class T> struct constant_ref_type {
|
||||
typedef
|
||||
lambda_functor<identity<const T&> > type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// as_lambda_functor turns any types to lambda functors
|
||||
// non-lambda_functors will be bound argument types
|
||||
template <class T>
|
||||
struct as_lambda_functor {
|
||||
typedef typename
|
||||
detail::remove_reference_and_cv<T>::type plain_T;
|
||||
typedef typename
|
||||
detail::IF<is_lambda_functor<plain_T>::value,
|
||||
plain_T,
|
||||
lambda_functor<
|
||||
identity<typename bound_argument_conversion<T>::type>
|
||||
>
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
// turns arbitrary objects into lambda functors
|
||||
template <class T>
|
||||
inline
|
||||
lambda_functor<identity<typename bound_argument_conversion<const T>::type> >
|
||||
to_lambda_functor(const T& t) {
|
||||
return identity<typename bound_argument_conversion<const T>::type>(t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline lambda_functor<T>
|
||||
to_lambda_functor(const lambda_functor<T>& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// In a call make_rvalues_const<T>::exec(x)
|
||||
// x should be of type T. If T is a non-reference type, exec
|
||||
|
||||
|
||||
// In a call constify_rvals<T>::go(x)
|
||||
// x should be of type T. If T is a non-reference type, do
|
||||
// returns x as const reference.
|
||||
// Otherwise the type doesn't change.
|
||||
// The purpose of this class is to avoid
|
||||
// 'cannot bind temporaries to non-const references' errors.
|
||||
template <class T> struct make_rvalues_const {
|
||||
template <class T> struct constify_rvals {
|
||||
template<class U>
|
||||
static const U& exec(const U& u) { return u; }
|
||||
static inline const U& go(const U& u) { return u; }
|
||||
};
|
||||
|
||||
template <class T> struct make_rvalues_const<T&> {
|
||||
template <class T> struct constify_rvals<T&> {
|
||||
template<class U>
|
||||
static U& exec(U& u) { return u; }
|
||||
static inline U& go(U& u) { return u; }
|
||||
};
|
||||
|
||||
template <int N, class Args, class A, class B, class C>
|
||||
struct nth_return_type {
|
||||
typedef typename
|
||||
return_type<
|
||||
typename tuple_element_as_reference<N, Args>::type,
|
||||
open_args<A, B, C>
|
||||
>::type type;
|
||||
// check whether one of the elements of a tuple (cons list) is of type
|
||||
// null_type. Needed, because the compiler goes ahead and instantiates
|
||||
// sig template for nullary case even if the nullary operator() is not
|
||||
// called
|
||||
template <class T> struct is_null_type
|
||||
{ BOOST_STATIC_CONSTANT(bool, value = false); };
|
||||
|
||||
template <> struct is_null_type<null_type>
|
||||
{ BOOST_STATIC_CONSTANT(bool, value = true); };
|
||||
|
||||
template<class Tuple> struct has_null_type {
|
||||
BOOST_STATIC_CONSTANT(bool, value = (is_null_type<typename Tuple::head_type>::value || has_null_type<typename Tuple::tail_type>::value));
|
||||
};
|
||||
template<> struct has_null_type<null_type> {
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
|
||||
|
||||
// helpers -------------------
|
||||
|
||||
|
||||
template<class Args, class SigArgs>
|
||||
class deduce_argument_types_ {
|
||||
typedef typename as_lambda_functor<typename Args::head_type>::type lf_t;
|
||||
typedef typename lf_t::inherited::template sig<SigArgs>::type el_t;
|
||||
public:
|
||||
typedef
|
||||
boost::tuples::cons<
|
||||
el_t,
|
||||
typename deduce_argument_types_<typename Args::tail_type, SigArgs>::type
|
||||
> type;
|
||||
};
|
||||
|
||||
template<class SigArgs>
|
||||
class deduce_argument_types_<null_type, SigArgs> {
|
||||
public:
|
||||
typedef null_type type;
|
||||
};
|
||||
|
||||
|
||||
// // note that tuples cannot have plain function types as elements.
|
||||
// // Hence, all other types will be non-const, except references to
|
||||
// // functions.
|
||||
// template <class T> struct remove_reference_except_from_functions {
|
||||
// typedef typename boost::remove_reference<T>::type t;
|
||||
// typedef typename detail::IF<boost::is_function<t>::value, T, t>::RET type;
|
||||
// };
|
||||
|
||||
template<class Args, class SigArgs>
|
||||
class deduce_non_ref_argument_types_ {
|
||||
typedef typename as_lambda_functor<typename Args::head_type>::type lf_t;
|
||||
typedef typename lf_t::inherited::template sig<SigArgs>::type el_t;
|
||||
public:
|
||||
typedef
|
||||
boost::tuples::cons<
|
||||
// typename detail::remove_reference_except_from_functions<el_t>::type,
|
||||
typename boost::remove_reference<el_t>::type,
|
||||
typename deduce_non_ref_argument_types_<typename Args::tail_type, SigArgs>::type
|
||||
> type;
|
||||
};
|
||||
|
||||
template<class SigArgs>
|
||||
class deduce_non_ref_argument_types_<null_type, SigArgs> {
|
||||
public:
|
||||
typedef null_type type;
|
||||
};
|
||||
|
||||
// -------------
|
||||
|
||||
// take stored Args and Open Args, and return a const list with
|
||||
// deduced elements (real return types)
|
||||
template<class Args, class SigArgs>
|
||||
class deduce_argument_types {
|
||||
typedef typename deduce_argument_types_<Args, SigArgs>::type t1;
|
||||
public:
|
||||
typedef typename detail::IF<
|
||||
has_null_type<t1>::value, null_type, t1
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
// take stored Args and Open Args, and return a const list with
|
||||
// deduced elements (references are stripped from the element types)
|
||||
|
||||
template<class Args, class SigArgs>
|
||||
class deduce_non_ref_argument_types {
|
||||
typedef typename deduce_non_ref_argument_types_<Args, SigArgs>::type t1;
|
||||
public:
|
||||
typedef typename detail::IF<
|
||||
has_null_type<t1>::value, null_type, t1
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
template <int N, class Args, class SigArgs>
|
||||
struct nth_return_type_sig {
|
||||
typedef typename
|
||||
as_lambda_functor<
|
||||
typename boost::tuples::element<N, Args>::type
|
||||
// typename tuple_element_as_reference<N, Args>::type
|
||||
>::type lf_type;
|
||||
|
||||
typedef typename lf_type::inherited::template sig<SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<int N, class Tuple> struct element_or_null {
|
||||
typedef typename boost::tuples::element<N, Tuple>::type type;
|
||||
};
|
||||
|
||||
template<int N> struct element_or_null<N, null_type> {
|
||||
typedef null_type type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // end detail
|
||||
@@ -55,28 +262,26 @@ struct nth_return_type {
|
||||
|
||||
// the explicit_return_type_action case -----------------------------------
|
||||
template<class RET, class Args>
|
||||
class lambda_functor_base<action<1, explicit_return_type_action<RET> >, Args>
|
||||
class lambda_functor_base<explicit_return_type_action<RET>, Args>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
|
||||
typedef RET result_type;
|
||||
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET_, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const
|
||||
// TODO: RET and RET_ should be the same type, add a compile time assert?
|
||||
template <class SigArgs> struct sig { typedef RET type; };
|
||||
|
||||
template<class RET_, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
return detail::make_rvalues_const<RET>::exec(
|
||||
detail::ret_selector<RET>::select(boost::tuples::get<0>(args), a, b, c));
|
||||
return detail::constify_rvals<RET>::go(
|
||||
detail::r_select<RET>::go(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS));
|
||||
}
|
||||
};
|
||||
|
||||
// the protect_action case -----------------------------------
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<1, protect_action >, Args>
|
||||
class lambda_functor_base<protect_action, Args>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
@@ -84,280 +289,308 @@ public:
|
||||
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
CALL_USE_ARGS;
|
||||
return boost::tuples::get<0>(args);
|
||||
}
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
// typedef typename detail::tuple_element_as_reference<0, SigArgs>::type type;
|
||||
typedef typename boost::tuples::element<0, Args>::type type;
|
||||
};
|
||||
};
|
||||
|
||||
// Do nothing --------------------------------------------------------
|
||||
class do_nothing_action {};
|
||||
|
||||
// The work of curry action is not defined in action class apply,
|
||||
// but rather directly in lambda_functor_base::call
|
||||
// The argument substitution would be messed up otherwise.
|
||||
|
||||
// the curry_action 2-ary lambda_functor, one curried arg -------------------
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<3, curry_action<1> >, Args>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
class lambda_functor_base<do_nothing_action, Args> {
|
||||
// Args args;
|
||||
public:
|
||||
// explicit lambda_functor_base(const Args& a) {}
|
||||
lambda_functor_base() {}
|
||||
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const
|
||||
{
|
||||
return boost::tuples::get<0>(args).template ret_call<RET>(
|
||||
boost::tuples::get<1>(args), a);
|
||||
template<class RET, CALL_TEMPLATE_ARGS> RET call(CALL_FORMAL_ARGS) const {
|
||||
CALL_USE_ARGS;
|
||||
}
|
||||
};
|
||||
|
||||
// the curry_action case, 3-ary lambda functor, one curried arg --------------
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<4, curry_action<1> >, Args>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
template<class SigArgs> struct sig { typedef void type; };
|
||||
};
|
||||
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const
|
||||
{
|
||||
return boost::tuples::get<0>(args).template ret_call<RET>(
|
||||
boost::tuples::get<1>(args), a, b);
|
||||
}
|
||||
};
|
||||
// These specializatoins provide a shorter notation to define actions.
|
||||
// These lambda_functor_base instances take care of the recursive evaluation
|
||||
// of the arguments and pass the evaluated arguments to the apply function
|
||||
// of an action class. To make action X work with these classes, one must
|
||||
// instantiate the lambda_functor_base as:
|
||||
// lambda_functor_base<action<ARITY, X>, Args>
|
||||
// Where ARITY is the arity of the apply function in X
|
||||
|
||||
// the curry_action case, 3-ary lambda functor, two curried args -------------
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<4, curry_action<2> >, Args>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
// The return type is queried as:
|
||||
// return_type_N<X, EvaluatedArgumentTypes>::type
|
||||
// for which there must be a specialization.
|
||||
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
// Function actions, casts, throws,... all go via these classes.
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const
|
||||
{
|
||||
return boost::tuples::get<0>(args).template ret_call<RET>(
|
||||
boost::tuples::get<1>(args), boost::tuples::get<2>(args), a);
|
||||
|
||||
template<class Act, class Args>
|
||||
class lambda_functor_base<action<0, Act>, Args>
|
||||
{
|
||||
public:
|
||||
// Args args; not needed
|
||||
explicit lambda_functor_base(const Args& a) {}
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename return_type_N<Act, null_type>::type type;
|
||||
};
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
CALL_USE_ARGS;
|
||||
return Act::template apply<RET>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART
|
||||
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(ARITY) \
|
||||
template<class Act, class Args>\
|
||||
class lambda_functor_base<action<ARITY, Act>, Args> \
|
||||
{\
|
||||
public:\
|
||||
Args args;\
|
||||
public:\
|
||||
\
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}\
|
||||
\
|
||||
template<class RET, class A, class B, class C>\
|
||||
RET call(A& a, B& b, C& c) const {\
|
||||
\
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(0)
|
||||
return Act::template apply<RET>(
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART
|
||||
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART"
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(ARITY) \
|
||||
template<class Act, class Args> \
|
||||
class lambda_functor_base<action<ARITY, Act>, Args> \
|
||||
{ \
|
||||
public: \
|
||||
Args args; \
|
||||
\
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class SigArgs> struct sig { \
|
||||
typedef typename \
|
||||
detail::deduce_non_ref_argument_types<Args, SigArgs>::type rets_t; \
|
||||
public: \
|
||||
typedef typename \
|
||||
return_type_N_prot<Act, rets_t>::type type; \
|
||||
}; \
|
||||
\
|
||||
\
|
||||
template<class RET, CALL_TEMPLATE_ARGS> \
|
||||
RET call(CALL_FORMAL_ARGS) const { \
|
||||
using boost::tuples::get; \
|
||||
using detail::constify_rvals; \
|
||||
using detail::r_select; \
|
||||
using detail::element_or_null; \
|
||||
using detail::deduce_argument_types;
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(1)
|
||||
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(2)
|
||||
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(3)
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c))
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(4)
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(5)
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename detail::nth_return_type<4, Args, A&, B&, C&>::type ret4;
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
typedef typename element_or_null<4, rets_t>::type rt4;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret4>::exec(detail::ret_selector<ret4>::select(boost::tuples::get<4>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt4>::go(r_select<rt4>::go(get<4>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(6)
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename detail::nth_return_type<4, Args, A&, B&, C&>::type ret4;
|
||||
typedef typename detail::nth_return_type<5, Args, A&, B&, C&>::type ret5;
|
||||
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
typedef typename element_or_null<4, rets_t>::type rt4;
|
||||
typedef typename element_or_null<5, rets_t>::type rt5;
|
||||
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret4>::exec(detail::ret_selector<ret4>::select(boost::tuples::get<4>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret5>::exec(detail::ret_selector<ret5>::select(boost::tuples::get<5>(args), a, b, c))
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt4>::go(r_select<rt4>::go(get<4>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt5>::go(r_select<rt5>::go(get<5>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(7)
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename detail::nth_return_type<4, Args, A&, B&, C&>::type ret4;
|
||||
typedef typename detail::nth_return_type<5, Args, A&, B&, C&>::type ret5;
|
||||
typedef typename detail::nth_return_type<6, Args, A&, B&, C&>::type ret6;
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
typedef typename element_or_null<4, rets_t>::type rt4;
|
||||
typedef typename element_or_null<5, rets_t>::type rt5;
|
||||
typedef typename element_or_null<6, rets_t>::type rt6;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret4>::exec(detail::ret_selector<ret4>::select(boost::tuples::get<4>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret5>::exec(detail::ret_selector<ret5>::select(boost::tuples::get<5>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret6>::exec(detail::ret_selector<ret6>::select(boost::tuples::get<6>(args), a, b, c))
|
||||
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt4>::go(r_select<rt4>::go(get<4>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt5>::go(r_select<rt5>::go(get<5>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt6>::go(r_select<rt6>::go(get<6>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(8)
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename detail::nth_return_type<4, Args, A&, B&, C&>::type ret4;
|
||||
typedef typename detail::nth_return_type<5, Args, A&, B&, C&>::type ret5;
|
||||
typedef typename detail::nth_return_type<6, Args, A&, B&, C&>::type ret6;
|
||||
typedef typename detail::nth_return_type<7, Args, A&, B&, C&>::type ret7;
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
typedef typename element_or_null<4, rets_t>::type rt4;
|
||||
typedef typename element_or_null<5, rets_t>::type rt5;
|
||||
typedef typename element_or_null<6, rets_t>::type rt6;
|
||||
typedef typename element_or_null<7, rets_t>::type rt7;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret4>::exec(detail::ret_selector<ret4>::select(boost::tuples::get<4>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret5>::exec(detail::ret_selector<ret5>::select(boost::tuples::get<5>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret6>::exec(detail::ret_selector<ret6>::select(boost::tuples::get<6>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret7>::exec(detail::ret_selector<ret7>::select(boost::tuples::get<7>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt4>::go(r_select<rt4>::go(get<4>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt5>::go(r_select<rt5>::go(get<5>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt6>::go(r_select<rt6>::go(get<6>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt7>::go(r_select<rt7>::go(get<7>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(9)
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
typedef typename element_or_null<4, rets_t>::type rt4;
|
||||
typedef typename element_or_null<5, rets_t>::type rt5;
|
||||
typedef typename element_or_null<6, rets_t>::type rt6;
|
||||
typedef typename element_or_null<7, rets_t>::type rt7;
|
||||
typedef typename element_or_null<8, rets_t>::type rt8;
|
||||
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename detail::nth_return_type<4, Args, A&, B&, C&>::type ret4;
|
||||
typedef typename detail::nth_return_type<5, Args, A&, B&, C&>::type ret5;
|
||||
typedef typename detail::nth_return_type<6, Args, A&, B&, C&>::type ret6;
|
||||
typedef typename detail::nth_return_type<7, Args, A&, B&, C&>::type ret7;
|
||||
typedef typename detail::nth_return_type<8, Args, A&, B&, C&>::type ret8;
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret4>::exec(detail::ret_selector<ret4>::select(boost::tuples::get<4>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret5>::exec(detail::ret_selector<ret5>::select(boost::tuples::get<5>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret6>::exec(detail::ret_selector<ret6>::select(boost::tuples::get<6>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret7>::exec(detail::ret_selector<ret7>::select(boost::tuples::get<7>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret8>::exec(detail::ret_selector<ret8>::select(boost::tuples::get<8>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt4>::go(r_select<rt4>::go(get<4>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt5>::go(r_select<rt5>::go(get<5>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt6>::go(r_select<rt6>::go(get<6>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt7>::go(r_select<rt7>::go(get<7>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt8>::go(r_select<rt8>::go(get<8>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(10)
|
||||
typedef typename
|
||||
deduce_argument_types<Args, tuple<CALL_REFERENCE_TYPES> >::type rets_t;
|
||||
typedef typename element_or_null<0, rets_t>::type rt0;
|
||||
typedef typename element_or_null<1, rets_t>::type rt1;
|
||||
typedef typename element_or_null<2, rets_t>::type rt2;
|
||||
typedef typename element_or_null<3, rets_t>::type rt3;
|
||||
typedef typename element_or_null<4, rets_t>::type rt4;
|
||||
typedef typename element_or_null<5, rets_t>::type rt5;
|
||||
typedef typename element_or_null<6, rets_t>::type rt6;
|
||||
typedef typename element_or_null<7, rets_t>::type rt7;
|
||||
typedef typename element_or_null<8, rets_t>::type rt8;
|
||||
typedef typename element_or_null<9, rets_t>::type rt9;
|
||||
|
||||
typedef typename detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
|
||||
typedef typename detail::nth_return_type<1, Args, A&, B&, C&>::type ret1;
|
||||
typedef typename detail::nth_return_type<2, Args, A&, B&, C&>::type ret2;
|
||||
typedef typename detail::nth_return_type<3, Args, A&, B&, C&>::type ret3;
|
||||
typedef typename detail::nth_return_type<4, Args, A&, B&, C&>::type ret4;
|
||||
typedef typename detail::nth_return_type<5, Args, A&, B&, C&>::type ret5;
|
||||
typedef typename detail::nth_return_type<6, Args, A&, B&, C&>::type ret6;
|
||||
typedef typename detail::nth_return_type<7, Args, A&, B&, C&>::type ret7;
|
||||
typedef typename detail::nth_return_type<8, Args, A&, B&, C&>::type ret8;
|
||||
typedef typename detail::nth_return_type<9, Args, A&, B&, C&>::type ret9;
|
||||
|
||||
|
||||
return Act::template apply<RET>(
|
||||
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret1>::exec(detail::ret_selector<ret1>::select(boost::tuples::get<1>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret2>::exec(detail::ret_selector<ret2>::select(boost::tuples::get<2>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret3>::exec(detail::ret_selector<ret3>::select(boost::tuples::get<3>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret4>::exec(detail::ret_selector<ret4>::select(boost::tuples::get<4>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret5>::exec(detail::ret_selector<ret5>::select(boost::tuples::get<5>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret6>::exec(detail::ret_selector<ret6>::select(boost::tuples::get<6>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret7>::exec(detail::ret_selector<ret7>::select(boost::tuples::get<7>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret8>::exec(detail::ret_selector<ret8>::select(boost::tuples::get<8>(args), a, b, c)),
|
||||
detail::make_rvalues_const<ret9>::exec(detail::ret_selector<ret9>::select(boost::tuples::get<9>(args), a, b, c))
|
||||
return Act::template apply<RET>(
|
||||
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt1>::go(r_select<rt1>::go(get<1>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt2>::go(r_select<rt2>::go(get<2>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt3>::go(r_select<rt3>::go(get<3>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt4>::go(r_select<rt4>::go(get<4>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt5>::go(r_select<rt5>::go(get<5>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt6>::go(r_select<rt6>::go(get<6>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt7>::go(r_select<rt7>::go(get<7>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt8>::go(r_select<rt8>::go(get<8>(args), CALL_ACTUAL_ARGS)),
|
||||
constify_rvals<rt9>::go(r_select<rt9>::go(get<9>(args), CALL_ACTUAL_ARGS))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,554 +34,180 @@ namespace {
|
||||
} // unnamed
|
||||
} // detail
|
||||
|
||||
#define const_null_type() detail::constant_null_type
|
||||
|
||||
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT\
|
||||
template<class A>\
|
||||
const lambda_functor<lambda_functor_args<\
|
||||
action<2, other_action<assignment_action> >,\
|
||||
boost::tuple<lambda_functor, \
|
||||
typename const_copy_argument <const A>::type>,\
|
||||
combine_arities<lambda_functor,A>::value> >\
|
||||
operator=(const A& a) const { \
|
||||
return lambda_functor<lambda_functor_args<\
|
||||
action<2, other_action<assignment_action> >,\
|
||||
boost::tuple<lambda_functor, \
|
||||
typename const_copy_argument <const A>::type>,\
|
||||
combine_arities<lambda_functor,A>::value> >\
|
||||
( boost::tuple<lambda_functor, \
|
||||
typename const_copy_argument <const A>::type>(*this, a) );\
|
||||
}\
|
||||
\
|
||||
|
||||
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT\
|
||||
template<class A>\
|
||||
const lambda_functor<lambda_functor_args<\
|
||||
action<2, other_action<subscript_action> >,\
|
||||
boost::tuple<lambda_functor, \
|
||||
typename const_copy_argument <const A>::type>,\
|
||||
combine_arities<lambda_functor,A>::value> >\
|
||||
operator[](const A& a) const { \
|
||||
return lambda_functor<lambda_functor_args<\
|
||||
action<2, other_action<subscript_action> >,\
|
||||
boost::tuple<lambda_functor, \
|
||||
typename const_copy_argument <const A>::type>,\
|
||||
combine_arities<lambda_functor,A>::value> >\
|
||||
( boost::tuple<lambda_functor, \
|
||||
typename const_copy_argument <const A>::type>(*this, a ) );\
|
||||
}\
|
||||
\
|
||||
|
||||
|
||||
template <int I>
|
||||
class lambda_functor<placeholder<I> > {
|
||||
public:
|
||||
lambda_functor() {}
|
||||
// default constructor (do nothing)
|
||||
// bug in gcc 2.95.2 for const template objects.
|
||||
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// helpers
|
||||
template <class T> struct identity { typedef T type; };
|
||||
|
||||
// take the Nth element in the tuple, or null_type if tuple is not
|
||||
// long enough
|
||||
|
||||
template <int N, class T>
|
||||
struct element_or_null_type {
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
(N < boost::tuples::length<T>::value),
|
||||
boost::tuples::element<N, T>,
|
||||
identity<null_type>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// Lambda functors all provide the sig member template for
|
||||
// querying their return type.
|
||||
// these type mappings implement the tools for that deduction
|
||||
|
||||
//type mapping to compute the new lambda functor resulting from a curried
|
||||
// call.
|
||||
template<class LF, int Args_expected, class SigArgs>
|
||||
struct curry_sig {
|
||||
|
||||
// First arg in SigArgs is the lambda functor type, that's why the -1
|
||||
BOOST_STATIC_CONSTANT(int, acount = boost::tuples::length<SigArgs>::value-1);
|
||||
|
||||
|
||||
// currying is only supported for 2- and 3-ary lambda functors, and
|
||||
// must be called by 1 or 2 arguments.
|
||||
// acount 1 or 2, dig_arity<LF>::value SECOND or THIRD
|
||||
|
||||
typedef typename detail::element_or_null_type<1, SigArgs>::type el_1;
|
||||
typedef typename detail::element_or_null_type<2, SigArgs>::type el_2;
|
||||
|
||||
typedef lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<Args_expected + 1, curry_action<acount> >,
|
||||
// remove_const_refernce takes care that const null_type will
|
||||
// be null_type, that arrays are always stored as const refs,
|
||||
// that nonconst refs remain nonconst refs, and everything else goes
|
||||
// to const copy.
|
||||
|
||||
tuple<
|
||||
LF,
|
||||
typename detail::remove_const_reference<el_1>::type,
|
||||
typename detail::remove_const_reference<el_2>::type
|
||||
>,
|
||||
detail::reduce_arity<dig_arity<LF>::value, acount>::value
|
||||
>
|
||||
> type;
|
||||
};
|
||||
|
||||
// enter the normal return type deduction
|
||||
template <class LF, class SigArgs>
|
||||
struct eval_sig
|
||||
{
|
||||
typedef typename
|
||||
return_type<
|
||||
LF,
|
||||
open_args<
|
||||
typename detail::element_or_null_type<1, SigArgs>::type,
|
||||
typename detail::element_or_null_type<2, SigArgs>::type,
|
||||
typename detail::element_or_null_type<3, SigArgs>::type
|
||||
>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// either a normal evaluation, or a curried call
|
||||
template <class LF, int Args_expected, class SigArgs>
|
||||
struct lambda_functor_sig
|
||||
{
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
(boost::tuples::length<SigArgs>::value - 1 < Args_expected),
|
||||
detail::curry_sig<LF, Args_expected, SigArgs>,
|
||||
detail::eval_sig<LF, SigArgs>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
// -- lambda_functor NONE ------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, NONE> >
|
||||
: public lambda_functor_base<Action, Args>, public has_sig
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
|
||||
explicit lambda_functor(const Args& args)
|
||||
: inherited(args) {}
|
||||
|
||||
// lambda functors can be copied, if arity and action are the same
|
||||
// and Args tuples are copyable
|
||||
template <class Args2> lambda_functor
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, NONE> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 0, SigArgs>::type type;
|
||||
};
|
||||
|
||||
typename return_type<
|
||||
lambda_functor,
|
||||
open_args<null_type, null_type, null_type>
|
||||
>::type
|
||||
operator()() const {
|
||||
return inherited::template
|
||||
call<
|
||||
typename return_type<
|
||||
lambda_functor,
|
||||
open_args<null_type, null_type, null_type> >::type
|
||||
>(const_null_type(), const_null_type(), const_null_type());
|
||||
}
|
||||
|
||||
template<class RET>
|
||||
RET ret_call() const {
|
||||
return inherited:: template call<RET>(const_null_type(),
|
||||
const_null_type(),
|
||||
const_null_type());
|
||||
}
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
};
|
||||
|
||||
// -- lambda_functor FIRST -------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, FIRST> >
|
||||
: public lambda_functor_base<Action, Args>
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
|
||||
explicit lambda_functor(const Args& args)
|
||||
: inherited(args) {}
|
||||
|
||||
// lambda functors can be copied, if arity and action are the same
|
||||
// and Args tuples copyable
|
||||
template <class Args2> lambda_functor
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, FIRST> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 1, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class A>
|
||||
typename
|
||||
return_type<lambda_functor, open_args<A&, null_type, null_type> >::type
|
||||
operator()(A& a) const
|
||||
{
|
||||
return inherited::template call<
|
||||
typename return_type<
|
||||
lambda_functor, open_args<A&, null_type, null_type>
|
||||
>::type
|
||||
>(a, const_null_type(), const_null_type());
|
||||
}
|
||||
|
||||
template<class RET, class A>
|
||||
RET ret_call(A& a) const
|
||||
{
|
||||
return inherited:: template call<RET>(a, const_null_type(), const_null_type());
|
||||
}
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
};
|
||||
|
||||
// -- lambda_functor SECOND -------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, SECOND> >
|
||||
: public lambda_functor_base<Action, Args>, public has_sig
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
|
||||
explicit lambda_functor(const Args& args)
|
||||
: inherited(args) {}
|
||||
|
||||
// lambda functors can be copied, if arity and action are the same
|
||||
// and Args tuples copyable
|
||||
template <class Args2> lambda_functor
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, SECOND> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 2, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class A, class B>
|
||||
typename return_type<lambda_functor, open_args<A&, B&, null_type> >::type
|
||||
operator()(A& a, B& b) const
|
||||
{
|
||||
return inherited::template call<
|
||||
typename return_type<
|
||||
lambda_functor, open_args<A&, B&, null_type>
|
||||
>::type>(a, b, const_null_type());
|
||||
}
|
||||
|
||||
// currying call: creates another lambda functor
|
||||
template<class A>
|
||||
typename sig<tuple<const lambda_functor&, A&> >::type
|
||||
operator()(A& a) const
|
||||
{
|
||||
return
|
||||
typename sig<tuple<const lambda_functor&, A&> >::type
|
||||
(
|
||||
tuple<lambda_functor,
|
||||
typename detail::remove_const_reference<A&>::type>(*this, a)
|
||||
);
|
||||
}
|
||||
|
||||
template<class RET, class A, class B>
|
||||
RET ret_call(A& a, B& b) const {
|
||||
return inherited::template call<RET>(a, b, const_null_type());
|
||||
}
|
||||
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
};
|
||||
|
||||
// -- lambda_functor THIRD -------------------------------------------------
|
||||
template <class Action, class Args>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, THIRD> > : public lambda_functor_base<Action, Args>, public has_sig
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
|
||||
explicit lambda_functor(const Args& args)
|
||||
: inherited(args) {}
|
||||
|
||||
// lambda functors can be copied, if arity and action are the same
|
||||
// and Args tuples copyable
|
||||
template <class Args2> lambda_functor
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, THIRD> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::lambda_functor_sig<lambda_functor, 3, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename return_type<lambda_functor, open_args<A&, B&, C&> >::type
|
||||
operator()(A& a, B& b, C& c) const
|
||||
{
|
||||
return inherited::template call<
|
||||
typename return_type<lambda_functor, open_args<A&, B&, C&>
|
||||
>::type>(a, b, c);
|
||||
}
|
||||
template<class RET, class A, class B, class C>
|
||||
RET ret_call(A& a, B& b, C& c) const {
|
||||
return inherited::template call<RET>(a, b, c);
|
||||
}
|
||||
|
||||
// currying call, one argument still missing
|
||||
template<class A, class B>
|
||||
typename sig<tuple<const lambda_functor&, A&, B&> >::type
|
||||
operator()(A& a, B& b) const
|
||||
{
|
||||
return
|
||||
typename sig<tuple<const lambda_functor&, A&, B&> >::type
|
||||
( tuple<
|
||||
lambda_functor,
|
||||
typename detail::remove_const_reference<A&>::type,
|
||||
typename detail::remove_const_reference<B&>::type
|
||||
> (*this, a, b)
|
||||
);
|
||||
}
|
||||
|
||||
// currying call, two arguments still missing
|
||||
|
||||
// The return type is:
|
||||
// lambda_functor<
|
||||
// lambda_functor_args<
|
||||
// action<4, curry_action<1> >,
|
||||
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
|
||||
// SECOND
|
||||
// >
|
||||
// >
|
||||
|
||||
template<class A>
|
||||
typename sig<tuple<const lambda_functor&, A&> >::type
|
||||
operator()(A& a) const
|
||||
{
|
||||
return
|
||||
typename sig<tuple<const lambda_functor&, A&> >::type
|
||||
(
|
||||
tuple<lambda_functor, typename detail::remove_const_reference<A&>::type>(*this, a)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
};
|
||||
|
||||
// -- lambda_functor (Arbitrary Code) ---------------------------------------
|
||||
// matches any arity code with EXCEPTION or RETHROW bits on
|
||||
|
||||
// This specialisation is only instantiated if delayed exception
|
||||
// handling is used. See exceptions.hpp.
|
||||
// ----------------------------------------------------------
|
||||
template <class Action, class Args, int Code>
|
||||
class lambda_functor<lambda_functor_args<Action, Args, Code> >
|
||||
: public lambda_functor_base<Action, Args>
|
||||
{
|
||||
public:
|
||||
typedef lambda_functor_base<Action, Args> inherited;
|
||||
|
||||
explicit lambda_functor(const Args& args)
|
||||
: inherited(args) {}
|
||||
|
||||
// lambda functors can be copied, if arity and action are the same
|
||||
// and Args tuples copyable
|
||||
template <class Args2> lambda_functor
|
||||
(const lambda_functor<lambda_functor_args<Action, Args2, Code> >& f)
|
||||
: inherited(f.args) {}
|
||||
|
||||
|
||||
// No operator() for this, since this lambda_functor can only be used
|
||||
// in a catch_exception or catch_all
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET ret_call(A& a, B& b, C& c) const
|
||||
{
|
||||
return inherited::template call<RET>(a, b, c);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// any lambda functor can be turned into a const_incorrect_lambda_functor
|
||||
// The operator() takes arguments as consts and then casts constness
|
||||
// away. So this breaks const correctness!!! but is a necessary workaround
|
||||
// in some cases due to language limitations.
|
||||
// Note, that this is not a lambda_functor anymore, so it can not be used
|
||||
// as a sub lambda expression.
|
||||
|
||||
template <class Arg>
|
||||
struct const_incorrect_lambda_functor
|
||||
: private lambda_functor<Arg> {
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
|
||||
// only allowed for normal lambda functions, not EXCEPTION ones
|
||||
|
||||
typedef lambda_functor<Arg> inherited;
|
||||
|
||||
explicit const_incorrect_lambda_functor(const lambda_functor<Arg>& lf)
|
||||
: inherited(lf.args) {}
|
||||
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
::boost::lambda::lambda_functor<Arg>::template sig<SigArgs>::type type;
|
||||
};
|
||||
|
||||
typename sig<tuple<const lambda_functor<Arg>& > >::type
|
||||
operator()() const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>& > >::type>();
|
||||
}
|
||||
|
||||
template<class A>
|
||||
typename sig<tuple<const lambda_functor<Arg>&, A&> >::type
|
||||
operator()(const A& a) const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&> >::type >(const_cast<A&>(a));
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
typename sig<tuple<const lambda_functor<Arg>&, A&, B&> >::type
|
||||
operator()(const A& a, const B& b) const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&, B&> >::type >(const_cast<A&>(a), const_cast<B&>(b));
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename sig<tuple<const lambda_functor<Arg>&, A&, B&, C&> >::type
|
||||
operator()(const A& a, const B& b, const C& c) const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&, B&, C&> >::type>(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// any lambda functor can be turned into a const_parameter_lambda_functor
|
||||
// The operator() takes arguments as const.
|
||||
// This is useful if lambda functors are called with non-const rvalues.
|
||||
// Note, that this is not a lambda_functor anymore, so it can not be used
|
||||
// as a sub lambda expression.
|
||||
|
||||
template <class Arg>
|
||||
struct const_parameter_lambda_functor
|
||||
: private lambda_functor<Arg> {
|
||||
public:
|
||||
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
|
||||
// only allowed for normal lambda functions, not EXCEPTION ones
|
||||
|
||||
typedef lambda_functor<Arg> inherited;
|
||||
|
||||
explicit const_parameter_lambda_functor(const lambda_functor<Arg>& lf)
|
||||
: inherited(lf.args) {}
|
||||
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
::boost::lambda::lambda_functor<Arg>::template sig<SigArgs>::type type;
|
||||
};
|
||||
|
||||
// This is provided just for completeness; no arguments, no constness
|
||||
// problems.
|
||||
|
||||
typename sig<tuple<const lambda_functor<Arg>& > >::type
|
||||
operator()() const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>& > >::type>();
|
||||
}
|
||||
|
||||
template<class A>
|
||||
typename sig<tuple<const lambda_functor<Arg>&, const A&> >::type
|
||||
operator()(const A& a) const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&> >::type >(a);
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&> >::type
|
||||
operator()(const A& a, const B& b) const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&> >::type >(a, b);
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&, const C&> >::type
|
||||
operator()(const A& a, const B& b, const C& c) const {
|
||||
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&, const C&> >::type>(a, b, c);
|
||||
}
|
||||
};
|
||||
class unused {};
|
||||
|
||||
#define cnull_type() detail::constant_null_type
|
||||
|
||||
// -- free variables types --------------------------------------------------
|
||||
|
||||
template <int I> class placeholder {};
|
||||
|
||||
// helper to work around the case where the nullary return type deduction
|
||||
// is always performed, even though the functor is not nullary
|
||||
namespace detail {
|
||||
template<int N, class Tuple> struct get_element_or_null_type {
|
||||
typedef typename
|
||||
detail::tuple_element_as_reference<N, Tuple>::type type;
|
||||
};
|
||||
template<int N> struct get_element_or_null_type<N, null_type> {
|
||||
typedef null_type type;
|
||||
};
|
||||
}
|
||||
|
||||
template <int I> struct placeholder;
|
||||
|
||||
template<> struct placeholder<FIRST> {
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename detail::get_element_or_null_type<0, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
BOOST_STATIC_ASSERT(boost::is_reference<RET>::value);
|
||||
CALL_USE_ARGS; // does nothing, prevents warnings for unused args
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct placeholder<SECOND> {
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename detail::get_element_or_null_type<1, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const { CALL_USE_ARGS; return b; }
|
||||
};
|
||||
|
||||
template<> struct placeholder<THIRD> {
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename detail::get_element_or_null_type<2, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const { CALL_USE_ARGS; return c; }
|
||||
};
|
||||
|
||||
template<> struct placeholder<EXCEPTION> {
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename detail::get_element_or_null_type<3, SigArgs>::type type;
|
||||
};
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const { CALL_USE_ARGS; return env; }
|
||||
};
|
||||
|
||||
typedef const lambda_functor<placeholder<FIRST> > placeholder1_type;
|
||||
typedef const lambda_functor<placeholder<SECOND> > placeholder2_type;
|
||||
typedef const lambda_functor<placeholder<THIRD> > placeholder3_type;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// free variables are lambda_functors. This is to allow uniform handling with
|
||||
// other lambda_functors.
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
|
||||
// Tagged lambda_functor -------------
|
||||
// This is a generic class for special types of lambda functors,
|
||||
// e.g. certain parameters of switch_statement must be case_statements,
|
||||
// rather than arbitrary lambda functors
|
||||
|
||||
|
||||
template<class Tag, class LambdaFunctor>
|
||||
class tagged_lambda_functor;
|
||||
|
||||
template<class Tag, class Args>
|
||||
class tagged_lambda_functor<Tag, lambda_functor<Args> >
|
||||
: public lambda_functor<Args>
|
||||
// -- lambda_functor NONE ------------------------------------------------
|
||||
template <class T>
|
||||
class lambda_functor : public T
|
||||
{
|
||||
|
||||
BOOST_STATIC_CONSTANT(int, arity_bits = get_arity<T>::value);
|
||||
|
||||
public:
|
||||
template<class T>
|
||||
tagged_lambda_functor(const lambda_functor<T>& a)
|
||||
: lambda_functor<Args>(a) {}
|
||||
typedef T inherited;
|
||||
|
||||
// only works for the no body case.
|
||||
explicit tagged_lambda_functor() : lambda_functor<Args>( null_type() ) {}
|
||||
lambda_functor() {}
|
||||
lambda_functor(const lambda_functor& l) : inherited(l) {}
|
||||
|
||||
lambda_functor(const T& t) : inherited(t) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename inherited::template
|
||||
sig<typename SigArgs::tail_type>::type type;
|
||||
};
|
||||
|
||||
// Note that this return type deduction template is instantiated, even
|
||||
// if the nullary
|
||||
// operator() is not called at all. One must make sure that it does not fail.
|
||||
typedef typename
|
||||
inherited::template sig<null_type>::type
|
||||
nullary_return_type;
|
||||
|
||||
nullary_return_type operator()() const {
|
||||
return inherited::template
|
||||
call<nullary_return_type>
|
||||
(cnull_type(), cnull_type(), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A>
|
||||
typename inherited::template sig<tuple<A&> >::type
|
||||
operator()(A& a) const {
|
||||
return inherited::template call<
|
||||
typename inherited::template sig<tuple<A&> >::type
|
||||
>(a, cnull_type(), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
typename inherited::template sig<tuple<A&, B&> >::type
|
||||
operator()(A& a, B& b) const {
|
||||
return inherited::template call<
|
||||
typename inherited::template sig<tuple<A&, B&> >::type
|
||||
>(a, b, cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename inherited::template sig<tuple<A&, B&, C&> >::type
|
||||
operator()(A& a, B& b, C& c) const
|
||||
{
|
||||
return inherited::template call<
|
||||
typename inherited::template sig<tuple<A&, B&, C&> >::type
|
||||
>(a, b, c, cnull_type());
|
||||
}
|
||||
|
||||
// for internal calls with env
|
||||
template<CALL_TEMPLATE_ARGS>
|
||||
typename inherited::template sig<tuple<CALL_REFERENCE_TYPES> >::type
|
||||
internal_call(CALL_FORMAL_ARGS) const {
|
||||
return inherited::template
|
||||
call<typename inherited::template
|
||||
sig<tuple<CALL_REFERENCE_TYPES> >::type>(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
template<class A>
|
||||
const lambda_functor<lambda_functor_base<
|
||||
other_action<assignment_action>,
|
||||
boost::tuple<lambda_functor,
|
||||
typename const_copy_argument <const A>::type> > >
|
||||
operator=(const A& a) const {
|
||||
return lambda_functor_base<
|
||||
other_action<assignment_action>,
|
||||
boost::tuple<lambda_functor,
|
||||
typename const_copy_argument <const A>::type> >
|
||||
( boost::tuple<lambda_functor,
|
||||
typename const_copy_argument <const A>::type>(*this, a) );
|
||||
}
|
||||
|
||||
template<class A>
|
||||
const lambda_functor<lambda_functor_base<
|
||||
other_action<subscript_action>,
|
||||
boost::tuple<lambda_functor,
|
||||
typename const_copy_argument <const A>::type> > >
|
||||
operator[](const A& a) const {
|
||||
return lambda_functor_base<
|
||||
other_action<subscript_action>,
|
||||
boost::tuple<lambda_functor,
|
||||
typename const_copy_argument <const A>::type> >
|
||||
( boost::tuple<lambda_functor,
|
||||
typename const_copy_argument <const A>::type>(*this, a ) );
|
||||
}
|
||||
};
|
||||
|
||||
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
|
||||
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_ADDRESSOF
|
||||
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
@@ -28,26 +28,16 @@ template<class T> struct generate_error;
|
||||
}
|
||||
// -- placeholders --------------------------------------------
|
||||
|
||||
template <int I> class placeholder;
|
||||
template <int I> struct placeholder;
|
||||
|
||||
// function_adaptors
|
||||
template <class Func>
|
||||
struct function_adaptor;
|
||||
|
||||
// The return_type traits class:
|
||||
template <class Action, class Open>
|
||||
class return_type;
|
||||
|
||||
template <int I, class Act> class action;
|
||||
|
||||
template <class BinderArgs>
|
||||
struct lambda_functor;
|
||||
|
||||
|
||||
template <class Action,
|
||||
class Args,
|
||||
int ArityCode>
|
||||
class lambda_functor_args;
|
||||
template <class Base>
|
||||
class lambda_functor;
|
||||
|
||||
template <class Act, class Args>
|
||||
class lambda_functor_base;
|
||||
@@ -56,4 +46,34 @@ class lambda_functor_base;
|
||||
} // namespace boost
|
||||
|
||||
|
||||
// #define CALL_TEMPLATE_ARGS class A, class Env
|
||||
// #define CALL_FORMAL_ARGS A& a, Env& env
|
||||
// #define CALL_ACTUAL_ARGS a, env
|
||||
// #define CALL_ACTUAL_ARGS_NO_ENV a
|
||||
// #define CALL_REFERENCE_TYPES A&, Env&
|
||||
// #define CALL_PLAIN_TYPES A, Env
|
||||
#define CALL_TEMPLATE_ARGS class A, class B, class C, class Env
|
||||
#define CALL_FORMAL_ARGS A& a, B& b, C& c, Env& env
|
||||
#define CALL_ACTUAL_ARGS a, b, c, env
|
||||
#define CALL_ACTUAL_ARGS_NO_ENV a, b, c
|
||||
#define CALL_REFERENCE_TYPES A&, B&, C&, Env&
|
||||
#define CALL_PLAIN_TYPES A, B, C, Env
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
namespace detail {
|
||||
|
||||
template<class A1, class A2, class A3, class A4>
|
||||
void do_nothing(A1&, A2&, A3&, A4&) {}
|
||||
|
||||
} // detail
|
||||
} // lambda
|
||||
} // boost
|
||||
|
||||
// prevent the warnings from unused argumetns
|
||||
#define CALL_USE_ARGS \
|
||||
::boost::lambda::detail::do_nothing(a, b, c, env)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -58,6 +58,9 @@ struct IF_type
|
||||
IF_type_<typename IF<C, T, E>::RET >::type type;
|
||||
};
|
||||
|
||||
// helper that can be used to give typedef T to some type
|
||||
template <class T> struct identity_mapping { typedef T type; };
|
||||
|
||||
// An if construct for finding an integral constant 'value'
|
||||
// Does not instantiate the non-matching branch
|
||||
// Called as IF_value<condition, A, B>::value
|
||||
@@ -103,13 +106,11 @@ template<class T> struct remove_reference_and_cv {
|
||||
|
||||
|
||||
// returns a reference to the element of tuple T
|
||||
// If the element is stored as a copy, the reference is to
|
||||
// const type. Constness of reference type elements remain unchanged.
|
||||
template<int N, class T> struct tuple_element_as_reference {
|
||||
typedef typename
|
||||
boost::tuples::access_traits<
|
||||
typename boost::tuples::element<N, T>::type
|
||||
>::const_type type;
|
||||
>::non_const_type type;
|
||||
};
|
||||
|
||||
// returns the cv and reverence stripped type of a tuple element
|
||||
@@ -167,7 +168,8 @@ struct parameter_traits_ {
|
||||
// Do not instantiate with reference types
|
||||
template<class T, class Any> struct parameter_traits_<T&, Any> {
|
||||
typedef typename
|
||||
generate_error<T&>::parameter_traits_class_instantiated_with_reference_type type;
|
||||
generate_error<T&>::
|
||||
parameter_traits_class_instantiated_with_reference_type type;
|
||||
};
|
||||
|
||||
// Arrays can't be stored as plain types; convert them to references
|
||||
@@ -214,6 +216,28 @@ template<class Any>
|
||||
struct parameter_traits_<void, Any> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<class Arg, class Any>
|
||||
struct parameter_traits_<lambda_functor<Arg>, Any > {
|
||||
typedef lambda_functor<Arg> type;
|
||||
};
|
||||
|
||||
template<class Arg, class Any>
|
||||
struct parameter_traits_<const lambda_functor<Arg>, Any > {
|
||||
typedef lambda_functor<Arg> type;
|
||||
};
|
||||
|
||||
// Are the volatile versions needed?
|
||||
template<class Arg, class Any>
|
||||
struct parameter_traits_<volatile lambda_functor<Arg>, Any > {
|
||||
typedef lambda_functor<Arg> type;
|
||||
};
|
||||
|
||||
template<class Arg, class Any>
|
||||
struct parameter_traits_<const volatile lambda_functor<Arg>, Any > {
|
||||
typedef lambda_functor<Arg> type;
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
|
||||
@@ -252,15 +276,27 @@ template<class T, int n> struct const_copy_argument <volatile T[n]> {
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct const_copy_argument<T&> {
|
||||
typedef typename detail::generate_error<T&>::references_not_allowed type;
|
||||
};
|
||||
struct const_copy_argument<T&> {};
|
||||
// do not instantiate with references
|
||||
// typedef typename detail::generate_error<T&>::references_not_allowed type;
|
||||
|
||||
|
||||
template<>
|
||||
struct const_copy_argument<void> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
|
||||
// Does the same as const_copy_argument, but passes references through as such
|
||||
template<class T>
|
||||
struct bound_argument_conversion {
|
||||
typedef typename const_copy_argument<T>::type type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct bound_argument_conversion<T&> {
|
||||
typedef T& type;
|
||||
};
|
||||
|
||||
// The default is non-const reference -------------------------
|
||||
// const T -> const T&,
|
||||
@@ -473,10 +509,9 @@ class bind_type_generator {
|
||||
public:
|
||||
typedef
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action_type,
|
||||
args_t,
|
||||
combine_arities<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value
|
||||
args_t
|
||||
>
|
||||
> type;
|
||||
|
||||
@@ -494,4 +529,4 @@ template <class T> inline const T& make_const(const T& t) { return t; }
|
||||
|
||||
|
||||
|
||||
#endif // BOOST_LAMBDA_TRAITS_HPP
|
||||
#endif // BOOST_LAMBDA_TRAITS_HPP
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
// -- Boost Lambda Library -- exceptions.hpp ----------------
|
||||
//
|
||||
// Copyright (C) 2000 Gary Powell (gwpowell@hotmail.com)
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see http://www.boost.org
|
||||
|
||||
// -----------------------------------------------------
|
||||
|
||||
// make_void( x ) turns a lambda functor x with some return type y into
|
||||
// another lambda functor, which has a void return type
|
||||
// when called, the original return type is discarded
|
||||
|
||||
#if !defined(BOOST_LAMBDA_MAKE_VOID_HPP)
|
||||
#define BOOST_LAMBDA_MAKE_VOID_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
template<> struct return_void_action<other_action<identity_action> > {
|
||||
template<class RET, class A>
|
||||
static RET apply(A& a) {}
|
||||
};
|
||||
|
||||
|
||||
template<class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<other_action<identity_action> > >,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
combine_arities<Arg1>::value
|
||||
>
|
||||
>
|
||||
make_void(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<other_action<identity_action> > >,
|
||||
tuple<lambda_functor<Arg1> >,
|
||||
combine_arities<Arg1>::value
|
||||
>
|
||||
>
|
||||
(tuple<lambda_functor<Arg1> > (a1));
|
||||
}
|
||||
|
||||
|
||||
// if its already returning void don't add another layer.
|
||||
template <class ActionType, class Args, int Code>
|
||||
inline const lambda_functor<lambda_functor_args<action<1, return_void_action<ActionType> >,
|
||||
Args, Code > >
|
||||
make_void(const lambda_functor<lambda_functor_args<action<1, return_void_action<ActionType> >,
|
||||
Args, Code > >& a1) {
|
||||
return lambda_functor<lambda_functor_args<action<1, return_void_action<ActionType> >,
|
||||
Args, Code > >
|
||||
(a1);
|
||||
}
|
||||
|
||||
template <class ActionType, class Args, int Code>
|
||||
inline const lambda_functor<lambda_functor_args<action<2, return_void_action<ActionType> >,
|
||||
Args,
|
||||
Code > >
|
||||
make_void(const lambda_functor<lambda_functor_args<action<2, return_void_action<ActionType> >,
|
||||
Args,
|
||||
Code > >& a1) {
|
||||
return lambda_functor<lambda_functor_args<action<2, return_void_action<ActionType> >,
|
||||
Args,
|
||||
Code > >
|
||||
(a1);
|
||||
}
|
||||
|
||||
template <class ActionType, class Args, int Code>
|
||||
inline const lambda_functor<lambda_functor_args<action<3, return_void_action<ActionType> >,
|
||||
Args, Code > >
|
||||
make_void(const lambda_functor<lambda_functor_args<action<3, return_void_action<ActionType> >,
|
||||
Args, Code > >& a1) {
|
||||
return lambda_functor<lambda_functor_args<action<3, return_void_action<ActionType> >,
|
||||
Args, Code > >
|
||||
(a1);
|
||||
}
|
||||
|
||||
template <class ActionType, int N, class Args, int Code>
|
||||
inline const lambda_functor<lambda_functor_args<action<N, return_void_action<ActionType> >,
|
||||
Args, Code > >
|
||||
make_void(const lambda_functor<lambda_functor_args<action<N, return_void_action<ActionType> >,
|
||||
Args, Code > >& a1) {
|
||||
return lambda_functor<lambda_functor_args<action<N, return_void_action<ActionType> >,
|
||||
Args, Code > >
|
||||
(a1);
|
||||
}
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
|
||||
class member_pointer_action {};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
// the boost type_traits member_pointer traits are not enough,
|
||||
@@ -507,6 +511,7 @@ struct member_pointer_action_helper;
|
||||
template <>
|
||||
struct member_pointer_action_helper<true, false> {
|
||||
public:
|
||||
|
||||
template<class RET, class A, class B>
|
||||
static RET apply(A& a, B& b) {
|
||||
return a->*b;
|
||||
@@ -514,14 +519,22 @@ public:
|
||||
|
||||
template<class A, class B>
|
||||
struct return_type {
|
||||
|
||||
private:
|
||||
typedef typename detail::remove_reference_and_cv<B>::type plainB;
|
||||
|
||||
typedef typename detail::member_pointer<plainB>::type type1;
|
||||
typedef typename detail::member_pointer<plainB>::type type0;
|
||||
// we remove the reference now, as we may have to add cv:s
|
||||
typedef typename boost::remove_reference<type0>::type type1;
|
||||
|
||||
// A is a pointer type
|
||||
typedef typename ::boost::remove_pointer<A>::type non_pointer_A;
|
||||
// A is a reference to pointer
|
||||
// remove the top level cv qualifiers and reference
|
||||
typedef typename
|
||||
detail::remove_reference_and_cv<A>::type non_ref_A;
|
||||
|
||||
// A is a pointer type, so take the type pointed to
|
||||
typedef typename ::boost::remove_pointer<non_ref_A>::type non_pointer_A;
|
||||
|
||||
public:
|
||||
// For non-reference types, we must add const and/or volatile if
|
||||
// the pointer type has these qualifiers
|
||||
// If the member is a reference, these do not have any effect
|
||||
@@ -536,6 +549,7 @@ public:
|
||||
typename ::boost::add_volatile<type2>::type,
|
||||
type2
|
||||
>::RET type3;
|
||||
// add reference back
|
||||
typedef typename ::boost::add_reference<type3>::type type;
|
||||
};
|
||||
};
|
||||
@@ -551,9 +565,14 @@ public:
|
||||
}
|
||||
// an overloaded member pointer operators, user should have specified
|
||||
// the return type
|
||||
// At this point we know that there is no matching specialization for
|
||||
// return_type_2, so try return_type_2_plain
|
||||
template<class A, class B>
|
||||
struct return_type {
|
||||
typedef detail::unspecified type;
|
||||
|
||||
typedef typename plain_return_type_2<
|
||||
other_action<member_pointer_action>, A, B
|
||||
>::type type;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -574,21 +593,30 @@ struct member_pointer_action_helper<false, true> {
|
||||
typedef typename ::boost::remove_cv<B>::type plainB;
|
||||
typedef typename detail::member_pointer<plainB>::type ret_t;
|
||||
|
||||
return detail::member_pointer_caller<ret_t, A&, B&>(a, b);
|
||||
// we always add const (it is just the pointer types, not the types
|
||||
// pointed to) to make the to routes (calling and type deduction)
|
||||
// to give the same results (and the const does not make any functional
|
||||
// difference)
|
||||
return detail::member_pointer_caller<ret_t, const A&, const B&>(a, b);
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
struct return_type {
|
||||
typedef typename detail::remove_reference_and_cv<B>::type plainB;
|
||||
typedef typename detail::member_pointer<plainB>::type ret_t;
|
||||
typedef detail::member_pointer_caller<ret_t, A, B> type;
|
||||
|
||||
// we always add const (it is just the pointer types, not the types
|
||||
// pointed to)
|
||||
typedef detail::member_pointer_caller<
|
||||
ret_t,
|
||||
typename boost::add_reference<const A>::type,
|
||||
typename boost::add_reference<const B>::type
|
||||
> type;
|
||||
};
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
class member_pointer_action {};
|
||||
|
||||
template<> class other_action<member_pointer_action> {
|
||||
public:
|
||||
template<class RET, class A, class B>
|
||||
@@ -622,14 +650,13 @@ public:
|
||||
// In such a case either ret<> must be used, or a return_type_2 user
|
||||
// defined specialization must be provided
|
||||
|
||||
|
||||
template<class A, class B>
|
||||
struct return_type_2<other_action<member_pointer_action>, A, B> {
|
||||
|
||||
private:
|
||||
typedef typename
|
||||
detail::remove_reference_and_cv<B>::type plainB;
|
||||
typedef typename
|
||||
detail::member_pointer<plainB>::qualified_class_type B_class;
|
||||
|
||||
public:
|
||||
typedef typename
|
||||
detail::member_pointer_action_helper<
|
||||
detail::member_pointer<plainB>::is_data_member,
|
||||
@@ -637,69 +664,74 @@ struct return_type_2<other_action<member_pointer_action>, A, B> {
|
||||
>::template return_type<A, B>::type type;
|
||||
};
|
||||
|
||||
// this is the way the generic lambda_functor_base functions instantiate
|
||||
// return type deduction. We turn it into return_type_2, so that the
|
||||
// user can provide specializations on that level.
|
||||
template<class Args>
|
||||
struct return_type_N<other_action<member_pointer_action>, Args> {
|
||||
typedef typename boost::tuples::element<0, Args>::type A;
|
||||
typedef typename boost::tuples::element<1, Args>::type B;
|
||||
typedef typename
|
||||
return_type_2<other_action<member_pointer_action>,
|
||||
typename boost::remove_reference<A>::type,
|
||||
typename boost::remove_reference<B>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<2, other_action<member_pointer_action> >,
|
||||
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>
|
||||
>
|
||||
>
|
||||
operator->*(const lambda_functor<Arg1>& a1, const Arg2& a2)
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<2, other_action<member_pointer_action> >,
|
||||
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>
|
||||
>
|
||||
> (tuple<lambda_functor<Arg1>,
|
||||
(tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type>(a1, a2));
|
||||
}
|
||||
|
||||
template<class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<2, other_action<member_pointer_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
operator->*(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2)
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<2, other_action<member_pointer_action> >,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
> (tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
(tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
}
|
||||
|
||||
template<class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<2, other_action<member_pointer_action> >,
|
||||
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
operator->*(const Arg1& a1, const lambda_functor<Arg2>& a2)
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
lambda_functor_base<
|
||||
action<2, other_action<member_pointer_action> >,
|
||||
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >,
|
||||
combine_arities<Arg1, Arg2>::value
|
||||
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >
|
||||
>
|
||||
> (tuple<typename const_copy_argument<Arg1>::type,
|
||||
(tuple<typename const_copy_argument<Arg1>::type,
|
||||
lambda_functor<Arg2> >(a1, a2));
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,6 @@ class decrement_action {};
|
||||
|
||||
// -- void return ------------------------------
|
||||
|
||||
class do_nothing_action {};
|
||||
|
||||
// -- other ------------------------------
|
||||
|
||||
class addressof_action {};
|
||||
@@ -80,122 +78,67 @@ template <class Action> class pre_increment_decrement_action;
|
||||
template <class Action> class post_increment_decrement_action;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
#if defined BOOST_LAMBDA_BINARY_ACTION
|
||||
#error "Multiple defines of BOOST_LAMBDA_BINARY_ACTION"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
|
||||
template<> class GROUP < OPER_NAME> : public protectable {\
|
||||
public: \
|
||||
template<class RET, class A, class B>\
|
||||
static RET apply(A& a, B& b) { \
|
||||
return a OPER_SYMBOL b; }\
|
||||
};\
|
||||
\
|
||||
// actions, for which the existence of protect is checked in return type
|
||||
// deduction.
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(+,arithmetic_action,plus_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(-,arithmetic_action,minus_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(*,arithmetic_action,multiply_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(/,arithmetic_action,divide_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(%,arithmetic_action,remainder_action)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(<<,bitwise_action,leftshift_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>>,bitwise_action,rightshift_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(&,bitwise_action,and_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(|,bitwise_action,or_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(^,bitwise_action,xor_action)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(<,relational_action,less_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>,relational_action,greater_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(<=,relational_action,lessorequal_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>=,relational_action,greaterorequal_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(==,relational_action,equal_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(!=,relational_action,notequal_action)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(+=,arithmetic_assignment_action,plus_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(-=,arithmetic_assignment_action,minus_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(*=,arithmetic_assignment_action,multiply_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(/=,arithmetic_assignment_action,divide_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(%=,arithmetic_assignment_action,remainder_action)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(<<=,bitwise_assignment_action,leftshift_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>>=,bitwise_assignment_action,rightshift_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(&=,bitwise_assignment_action,and_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(|=,bitwise_assignment_action,or_action)
|
||||
BOOST_LAMBDA_BINARY_ACTION(^=,bitwise_assignment_action,xor_action)
|
||||
|
||||
// && and || are defined directly in specializations for lambda_functor_base
|
||||
// to achieve short circuiting
|
||||
// Still we define some empty action classes for them, as they are instantiated:
|
||||
template<> class logical_action<or_action> : public protectable {};
|
||||
template<> class logical_action<and_action> : public protectable {};
|
||||
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(=,other_action, assignment_action)
|
||||
// subscript is done directly because BOOST_LAMBDA_BINARY_ACTION currently doesn't handle it.
|
||||
|
||||
template<> class other_action<subscript_action> : public protectable {
|
||||
public:
|
||||
template<class RET, class A, class B>
|
||||
static RET apply(A& a, B& b) { return a[b]; }
|
||||
template <class Act> struct is_protectable<arithmetic_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act> struct is_protectable<bitwise_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act> struct is_protectable<logical_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act> struct is_protectable<relational_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act>
|
||||
struct is_protectable<arithmetic_assignment_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act> struct is_protectable<bitwise_assignment_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act> struct is_protectable<unary_arithmetic_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act>
|
||||
struct is_protectable<pre_increment_decrement_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Act> struct
|
||||
is_protectable<post_increment_decrement_action<Act> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
// do_nothing_action is also specified directly for the same reason.
|
||||
template<> class return_void_action<do_nothing_action> {
|
||||
public:
|
||||
template<class RET>
|
||||
static RET apply() {}
|
||||
template <> struct is_protectable<other_action<addressof_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <> struct is_protectable<other_action<contentsof_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
// comma_action removed, a specialisation is provided to lambda_functor_base
|
||||
// This is to handle void arguments (built-in comma operator can take void
|
||||
// arguments whereas a user-defined function can't) (JJ)
|
||||
template<> struct is_protectable<other_action<subscript_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template<> struct is_protectable<other_action<assignment_action> > {
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
#if defined BOOST_LAMBDA_PREFIX_UNARY_ACTION
|
||||
#error "Multiple defines of BOOST_LAMBDA_PREFIX_UNARY_ACTION"
|
||||
#endif
|
||||
// NOTE: comma action is also protectable, but the specialization is
|
||||
// in actions.hpp
|
||||
|
||||
#define BOOST_LAMBDA_PREFIX_UNARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
|
||||
template<> class GROUP <OPER_NAME> : public protectable {\
|
||||
public: \
|
||||
template<class RET, class A>\
|
||||
static RET apply(A& a) { return OPER_SYMBOL a; }\
|
||||
};\
|
||||
\
|
||||
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(+, unary_arithmetic_action,plus_action)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(-, unary_arithmetic_action,minus_action)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(~, bitwise_action,not_action)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(!, logical_action,not_action)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(++, pre_increment_decrement_action,increment_action)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(--, pre_increment_decrement_action,decrement_action)
|
||||
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(&,other_action, addressof_action)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(*,other_action, contentsof_action)
|
||||
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION( , other_action, identity_action)
|
||||
|
||||
#if defined BOOST_LAMBDA_POSTFIX_UNARY_ACTION
|
||||
#error "Multiple defines of BOOST_LAMBDA_POSTFIX_UNARY_ACTION"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_POSTFIX_UNARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
|
||||
template<> class GROUP <OPER_NAME> : public protectable {\
|
||||
public: \
|
||||
template<class RET, class A>\
|
||||
static RET apply(A& a) { return a OPER_SYMBOL; }\
|
||||
};\
|
||||
\
|
||||
|
||||
BOOST_LAMBDA_POSTFIX_UNARY_ACTION(++, post_increment_decrement_action,increment_action)
|
||||
BOOST_LAMBDA_POSTFIX_UNARY_ACTION(--, post_increment_decrement_action,decrement_action)
|
||||
|
||||
|
||||
#undef BOOST_LAMBDA_BINARY_ACTION
|
||||
#undef BOOST_LAMBDA_PREFIX_UNARY_ACTION
|
||||
#undef BOOST_LAMBDA_POSTFIX_UNARY_ACTION
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
276
include/boost/lambda/detail/operator_lambda_func_base.hpp
Normal file
276
include/boost/lambda/detail/operator_lambda_func_base.hpp
Normal file
@@ -0,0 +1,276 @@
|
||||
// Boost Lambda Library - operator_lambda_func_base.hpp -----------------
|
||||
//
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef BOOST_LAMBDA_OPERATOR_LAMBDA_FUNC_BASE_HPP
|
||||
#define BOOST_LAMBDA_OPERATOR_LAMBDA_FUNC_BASE_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
|
||||
// These operators cannot be implemented as apply functions of action
|
||||
// templates
|
||||
|
||||
|
||||
// Specialization for comma.
|
||||
template<class Args>
|
||||
class lambda_functor_base<other_action<comma_action>, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
return detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS),
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
private:
|
||||
typedef typename
|
||||
detail::deduce_argument_types<Args, SigArgs>::type rets_t;
|
||||
public:
|
||||
typedef typename return_type_2_comma< // comma needs special handling
|
||||
typename detail::element_or_null<0, rets_t>::type,
|
||||
typename detail::element_or_null<1, rets_t>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// helper traits to make the expression shorter, takes binary action
|
||||
// bound argument tuple, open argument tuple and gives the return type
|
||||
|
||||
template<class Action, class Bound, class Open> class binary_rt {
|
||||
private:
|
||||
typedef typename
|
||||
detail::deduce_argument_types<Bound, Open>::type rets_t;
|
||||
public:
|
||||
typedef typename return_type_2_prot<
|
||||
Action,
|
||||
typename detail::element_or_null<0, rets_t>::type,
|
||||
typename detail::element_or_null<1, rets_t>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
// same for unary actions
|
||||
template<class Action, class Bound, class Open> class unary_rt {
|
||||
private:
|
||||
typedef typename
|
||||
detail::deduce_argument_types<Bound, Open>::type rets_t;
|
||||
public:
|
||||
typedef typename return_type_1_prot<
|
||||
Action,
|
||||
typename detail::element_or_null<0, rets_t>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
} // end detail
|
||||
|
||||
// Specialization for logical and (to preserve shortcircuiting)
|
||||
// this could be done with a macro as the others, code used to be different
|
||||
template<class Args>
|
||||
class lambda_functor_base<logical_action<and_action>, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
return detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) &&
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::binary_rt<logical_action<and_action>, Args, SigArgs>::type type;
|
||||
};
|
||||
};
|
||||
|
||||
// Specialization for logical or (to preserve shortcircuiting)
|
||||
// this could be done with a macro as the others, code used to be different
|
||||
template<class Args>
|
||||
class lambda_functor_base<logical_action< or_action>, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
return detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ||
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::binary_rt<logical_action<or_action>, Args, SigArgs>::type type;
|
||||
};
|
||||
};
|
||||
|
||||
// Specialization for subscript
|
||||
template<class Args>
|
||||
class lambda_functor_base<other_action<subscript_action>, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
return detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)
|
||||
[detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)];
|
||||
}
|
||||
|
||||
template<class SigArgs> struct sig {
|
||||
typedef typename
|
||||
detail::binary_rt<other_action<subscript_action>, Args, SigArgs>::type
|
||||
type;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_ACTION(SYMBOL, ACTION_CLASS) \
|
||||
template<class Args> \
|
||||
class lambda_functor_base<ACTION_CLASS, Args> { \
|
||||
public: \
|
||||
Args args; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, CALL_TEMPLATE_ARGS> \
|
||||
RET call(CALL_FORMAL_ARGS) const { \
|
||||
return detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) \
|
||||
SYMBOL \
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS); \
|
||||
} \
|
||||
template<class SigArgs> struct sig { \
|
||||
typedef typename \
|
||||
detail::binary_rt<ACTION_CLASS, Args, SigArgs>::type type; \
|
||||
}; \
|
||||
};
|
||||
|
||||
#define BOOST_LAMBDA_PREFIX_UNARY_ACTION(SYMBOL, ACTION_CLASS) \
|
||||
template<class Args> \
|
||||
class lambda_functor_base<ACTION_CLASS, Args> { \
|
||||
public: \
|
||||
Args args; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, CALL_TEMPLATE_ARGS> \
|
||||
RET call(CALL_FORMAL_ARGS) const { \
|
||||
return SYMBOL \
|
||||
detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS); \
|
||||
} \
|
||||
template<class SigArgs> struct sig { \
|
||||
typedef typename \
|
||||
detail::unary_rt<ACTION_CLASS, Args, SigArgs>::type type; \
|
||||
}; \
|
||||
};
|
||||
|
||||
#define BOOST_LAMBDA_POSTFIX_UNARY_ACTION(SYMBOL, ACTION_CLASS) \
|
||||
template<class Args> \
|
||||
class lambda_functor_base<ACTION_CLASS, Args> { \
|
||||
public: \
|
||||
Args args; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, CALL_TEMPLATE_ARGS> \
|
||||
RET call(CALL_FORMAL_ARGS) const { \
|
||||
return \
|
||||
detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) SYMBOL; \
|
||||
} \
|
||||
template<class SigArgs> struct sig { \
|
||||
typedef typename \
|
||||
detail::unary_rt<ACTION_CLASS, Args, SigArgs>::type type; \
|
||||
}; \
|
||||
};
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(+,arithmetic_action<plus_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(-,arithmetic_action<minus_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(*,arithmetic_action<multiply_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(/,arithmetic_action<divide_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(%,arithmetic_action<remainder_action>)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(<<,bitwise_action<leftshift_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>>,bitwise_action<rightshift_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(&,bitwise_action<and_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(|,bitwise_action<or_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(^,bitwise_action<xor_action>)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(<,relational_action<less_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>,relational_action<greater_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(<=,relational_action<lessorequal_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>=,relational_action<greaterorequal_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(==,relational_action<equal_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(!=,relational_action<notequal_action>)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(+=,arithmetic_assignment_action<plus_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(-=,arithmetic_assignment_action<minus_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(*=,arithmetic_assignment_action<multiply_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(/=,arithmetic_assignment_action<divide_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(%=,arithmetic_assignment_action<remainder_action>)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(<<=,bitwise_assignment_action<leftshift_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(>>=,bitwise_assignment_action<rightshift_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(&=,bitwise_assignment_action<and_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(|=,bitwise_assignment_action<or_action>)
|
||||
BOOST_LAMBDA_BINARY_ACTION(^=,bitwise_assignment_action<xor_action>)
|
||||
|
||||
BOOST_LAMBDA_BINARY_ACTION(=,other_action< assignment_action>)
|
||||
|
||||
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(+, unary_arithmetic_action<plus_action>)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(-, unary_arithmetic_action<minus_action>)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(~, bitwise_action<not_action>)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(!, logical_action<not_action>)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(++, pre_increment_decrement_action<increment_action>)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(--, pre_increment_decrement_action<decrement_action>)
|
||||
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(&,other_action<addressof_action>)
|
||||
BOOST_LAMBDA_PREFIX_UNARY_ACTION(*,other_action<contentsof_action>)
|
||||
|
||||
BOOST_LAMBDA_POSTFIX_UNARY_ACTION(++, post_increment_decrement_action<increment_action>)
|
||||
BOOST_LAMBDA_POSTFIX_UNARY_ACTION(--, post_increment_decrement_action<decrement_action>)
|
||||
|
||||
|
||||
#undef BOOST_LAMBDA_POSTFIX_UNARY_ACTION
|
||||
#undef BOOST_LAMBDA_PREFIX_UNARY_ACTION
|
||||
#undef BOOST_LAMBDA_BINARY_ACTION
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// Boost Lambda Library - operator_lambda_functor_base.hpp -----------------
|
||||
//
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#ifndef BOOST_LAMBDA_OPERATOR_LAMBDA_FUNCTOR_BASE_HPP
|
||||
#define BOOST_LAMBDA_OPERATOR_LAMBDA_FUNCTOR_BASE_HPP
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
|
||||
// These operators cannot be implemented as apply functions of action
|
||||
// templates
|
||||
|
||||
|
||||
// Specialization for comma.
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<2, other_action<comma_action> >, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
return detail::select(boost::tuples::get<0>(args), a, b, c),
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for logical and (to preserve shortcircuiting)
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<2, logical_action<and_action> >, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
return detail::select(boost::tuples::get<0>(args), a, b, c) &&
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for logical or (to preserve shortcircuiting)
|
||||
template<class Args>
|
||||
class lambda_functor_base<action<2, logical_action< or_action> >, Args> {
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
return detail::select(boost::tuples::get<0>(args), a, b, c) ||
|
||||
detail::select(boost::tuples::get<1>(args), a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -87,11 +87,11 @@ template <> struct promote_to_int<short int> { typedef int type; };
|
||||
// of unsigned short int, otherwise go to unsigned int.
|
||||
template <> struct promote_to_int<unsigned short int>
|
||||
{
|
||||
typedef
|
||||
detail::IF<sizeof(int) <= sizeof(unsigned short int),
|
||||
typedef
|
||||
detail::IF<sizeof(int) <= sizeof(unsigned short int),
|
||||
// I had the logic reversed but ">" messes up the parsing.
|
||||
unsigned int,
|
||||
int>::RET type;
|
||||
unsigned int,
|
||||
int>::RET type;
|
||||
};
|
||||
|
||||
|
||||
@@ -139,14 +139,9 @@ template<class A> struct return_type_1<bitwise_action<not_action>, A> {
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// identity_action
|
||||
template<class A> struct return_type_1<other_action<identity_action>, A> {
|
||||
typedef A type;
|
||||
};
|
||||
|
||||
|
||||
// prefix increment and decrement operators return the default is
|
||||
// a non-const reference
|
||||
// prefix increment and decrement operators return
|
||||
// their argument by default as a non-const reference
|
||||
template<class Act, class A>
|
||||
struct plain_return_type_1<pre_increment_decrement_action<Act>, A> {
|
||||
typedef A& type;
|
||||
@@ -229,6 +224,12 @@ template <class A> struct contentsof_type {
|
||||
typedef typename std::iterator_traits<A>::reference type;
|
||||
};
|
||||
|
||||
// this is since the nullary () in lambda_functor is always instantiated
|
||||
template <> struct contentsof_type<null_type> {
|
||||
typedef detail::unspecified type;
|
||||
};
|
||||
|
||||
|
||||
template <class A> struct contentsof_type<const A> {
|
||||
typedef typename contentsof_type<A>::type type1;
|
||||
// return a reference to the underlying const type
|
||||
@@ -297,6 +298,7 @@ template<class A, int N> struct contentsof_type<const volatile A[N]> {
|
||||
|
||||
template<class A>
|
||||
struct return_type_1<other_action<contentsof_action>, A> {
|
||||
|
||||
typedef
|
||||
typename plain_return_type_1<
|
||||
other_action<contentsof_action>,
|
||||
@@ -311,10 +313,7 @@ struct return_type_1<other_action<contentsof_action>, A> {
|
||||
detail::contentsof_type<
|
||||
typename boost::remove_reference<A>::type
|
||||
>,
|
||||
plain_return_type_1<
|
||||
other_action<contentsof_action>,
|
||||
typename detail::remove_reference_and_cv<A>::type
|
||||
>
|
||||
detail::identity_mapping<type1>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
@@ -491,22 +490,22 @@ struct return_type_2_arithmetic_phase_2 {
|
||||
// struct so I don't have to type this twice.
|
||||
struct promotion_of_unsigned_int
|
||||
{
|
||||
typedef
|
||||
detail::IF<sizeof(long) <= sizeof(unsigned int),
|
||||
typedef
|
||||
detail::IF<sizeof(long) <= sizeof(unsigned int),
|
||||
// I had the logic reversed but ">" messes up the parsing.
|
||||
unsigned long,
|
||||
long>::RET type;
|
||||
unsigned long,
|
||||
long>::RET type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct return_type_2_arithmetic_phase_2<unsigned int, long>
|
||||
{
|
||||
typedef promotion_of_unsigned_int::type type;
|
||||
typedef promotion_of_unsigned_int::type type;
|
||||
};
|
||||
template<>
|
||||
struct return_type_2_arithmetic_phase_2<long, unsigned int>
|
||||
{
|
||||
typedef promotion_of_unsigned_int::type type;
|
||||
typedef promotion_of_unsigned_int::type type;
|
||||
};
|
||||
|
||||
|
||||
@@ -563,22 +562,17 @@ struct return_type_2<bitwise_action<Act>, A, B>
|
||||
|
||||
namespace detail {
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATED_STREAMS
|
||||
|
||||
template<class A, class B>
|
||||
struct leftshift_type {
|
||||
|
||||
typedef typename detail::IF<
|
||||
#ifdef BOOST_NO_TEMPLATED_STREAMS
|
||||
boost::is_convertible<
|
||||
typename boost::remove_reference<A>::type*,
|
||||
std::ostream*
|
||||
>::value,
|
||||
#else
|
||||
is_instance_of_2<
|
||||
typename boost::remove_reference<A>::type,
|
||||
std::basic_ostream
|
||||
>::value,
|
||||
#endif
|
||||
A, //reference to the stream
|
||||
>::value,
|
||||
std::ostream&,
|
||||
typename detail::remove_reference_and_cv<A>::type
|
||||
>::RET type;
|
||||
};
|
||||
@@ -587,22 +581,55 @@ template<class A, class B>
|
||||
struct rightshift_type {
|
||||
|
||||
typedef typename detail::IF<
|
||||
#ifdef BOOST_NO_TEMPLATED_STREAMS
|
||||
|
||||
boost::is_convertible<
|
||||
typename boost::remove_reference<A>::type*,
|
||||
std::istream*
|
||||
>::value,
|
||||
#else
|
||||
is_instance_of_2<
|
||||
typename boost::remove_reference<A>::type,
|
||||
std::basic_istream
|
||||
>::value,
|
||||
#endif
|
||||
A, //reference to the stream
|
||||
std::istream&,
|
||||
typename detail::remove_reference_and_cv<A>::type
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <class T> struct get_ostream_type {
|
||||
typedef std::basic_ostream<typename T::char_type,
|
||||
typename T::traits_type>& type;
|
||||
};
|
||||
|
||||
template <class T> struct get_istream_type {
|
||||
typedef std::basic_istream<typename T::char_type,
|
||||
typename T::traits_type>& type;
|
||||
};
|
||||
|
||||
template<class A, class B>
|
||||
struct leftshift_type {
|
||||
private:
|
||||
typedef typename boost::remove_reference<A>::type plainA;
|
||||
public:
|
||||
typedef typename detail::IF_type<
|
||||
is_instance_of_2<plainA, std::basic_ostream>::value,
|
||||
get_ostream_type<plainA>, //reference to the stream
|
||||
detail::remove_reference_and_cv<A>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<class A, class B>
|
||||
struct rightshift_type {
|
||||
private:
|
||||
typedef typename boost::remove_reference<A>::type plainA;
|
||||
public:
|
||||
typedef typename detail::IF_type<
|
||||
is_instance_of_2<plainA, std::basic_istream>::value,
|
||||
get_istream_type<plainA>, //reference to the stream
|
||||
detail::remove_reference_and_cv<A>
|
||||
>::type type;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
} // end detail
|
||||
|
||||
// ostream
|
||||
@@ -682,8 +709,8 @@ struct return_type_2<relational_action<Act>, A, B> {
|
||||
};
|
||||
|
||||
// Assingment actions -----------------------------------------------
|
||||
// return type is the type of the first argument
|
||||
// (note: other templates guarantee that it is a referece).
|
||||
// return type is the type of the first argument as reference
|
||||
|
||||
// note that cv-qualifiers are preserved.
|
||||
// Yes, assignment operator can be const!
|
||||
|
||||
@@ -703,7 +730,7 @@ struct return_type_2<arithmetic_assignment_action<Act>, A, B> {
|
||||
typedef typename
|
||||
detail::IF<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
A,
|
||||
typename boost::add_reference<A>::type,
|
||||
type1
|
||||
>::RET type;
|
||||
};
|
||||
@@ -722,7 +749,7 @@ struct return_type_2<bitwise_assignment_action<Act>, A, B> {
|
||||
typedef typename
|
||||
detail::IF<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
A,
|
||||
typename boost::add_reference<A>::type,
|
||||
type1
|
||||
>::RET type;
|
||||
};
|
||||
@@ -740,7 +767,7 @@ struct return_type_2<other_action<assignment_action>, A, B> {
|
||||
typedef typename
|
||||
detail::IF<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
A,
|
||||
typename boost::add_reference<A>::type,
|
||||
type1
|
||||
>::RET type;
|
||||
};
|
||||
@@ -750,26 +777,22 @@ struct return_type_2<other_action<assignment_action>, A, B> {
|
||||
// comma action ----------------------------------
|
||||
// Note: this may not be true for some weird user-defined types,
|
||||
|
||||
// NOTE! A and B in comma_action can be non-reference types too!!!
|
||||
// NOTE! This only tries the plain_return_type_2 layer and gives
|
||||
// detail::unspecified as default. If no such specialization is found, the
|
||||
// type rule in the spcecialization of the return_type_2_prot is used
|
||||
// to give the type of the right argument (which can be a reference too)
|
||||
// (The built in operator, can return a l- or rvalue).
|
||||
template<class A, class B>
|
||||
struct return_type_2<other_action<comma_action>, A, B> {
|
||||
|
||||
typedef typename detail::remove_reference_and_cv<A>::type plain_A;
|
||||
typedef typename detail::remove_reference_and_cv<B>::type plain_B;
|
||||
|
||||
typedef typename
|
||||
plain_return_type_2<
|
||||
other_action<comma_action>, plain_A, plain_B
|
||||
>::type type1;
|
||||
|
||||
typedef typename
|
||||
detail::IF<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
B,
|
||||
type1
|
||||
>::RET type;
|
||||
|
||||
};
|
||||
>::type type;
|
||||
};
|
||||
|
||||
// subscript action -----------------------------------------------
|
||||
|
||||
|
||||
@@ -15,117 +15,121 @@
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
#ifndef BOOST_LAMBDA_BINARY_EXPRESSIONS_HPP
|
||||
#define BOOST_LAMBDA_BINARY_EXPRESSIONS_HPP
|
||||
#ifndef BOOST_LAMBDA_OPERATORS_HPP
|
||||
#define BOOST_LAMBDA_OPERATORS_HPP
|
||||
|
||||
#include "boost/lambda/detail/is_instance_of.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
#if defined BOOST_LAMBDA_BINARY_EXPRESSION1
|
||||
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION1"
|
||||
#if defined BOOST_LAMBDA_BE1
|
||||
#error "Multiple defines of BOOST_LAMBDA_BE1"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_EXPRESSION1(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) template<class Arg, class B> \
|
||||
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<lambda_functor<Arg>, \
|
||||
typename CONST_CONVERSION <CONSTB B>::type>,\
|
||||
dig_arity<Arg>::value> >\
|
||||
OPER_FUNC_NAME (const lambda_functor<Arg>& a, \
|
||||
CONSTB B& b)\
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<lambda_functor<Arg>, typename CONST_CONVERSION <CONSTB B>::type>, \
|
||||
dig_arity<Arg>::value> >\
|
||||
(\
|
||||
tuple<lambda_functor<Arg>, typename CONST_CONVERSION <CONSTB B>::type>(a, b)\
|
||||
);\
|
||||
}\
|
||||
\
|
||||
#define BOOST_LAMBDA_BE1(OPER_NAME, ACTION, CONSTA, CONSTB, CONVERSION) \
|
||||
template<class Arg, class B> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_base< \
|
||||
ACTION, \
|
||||
tuple<lambda_functor<Arg>, typename CONVERSION <CONSTB B>::type> \
|
||||
> \
|
||||
> \
|
||||
OPER_NAME (const lambda_functor<Arg>& a, CONSTB B& b) { \
|
||||
return \
|
||||
lambda_functor_base< \
|
||||
ACTION, \
|
||||
tuple<lambda_functor<Arg>, typename CONVERSION <CONSTB B>::type> \
|
||||
> \
|
||||
(tuple<lambda_functor<Arg>, typename CONVERSION <CONSTB B>::type>(a, b)); \
|
||||
}
|
||||
|
||||
#if defined BOOST_LAMBDA_BINARY_EXPRESSION2
|
||||
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION2"
|
||||
|
||||
#if defined BOOST_LAMBDA_BE2
|
||||
#error "Multiple defines of BOOST_LAMBDA_BE2"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_EXPRESSION2(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) template<class A, class Arg> \
|
||||
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >,\
|
||||
tuple<typename CONST_CONVERSION <CONSTA A>::type, \
|
||||
lambda_functor<Arg> >,\
|
||||
dig_arity<Arg>::value> >\
|
||||
OPER_FUNC_NAME (CONSTA A& a,\
|
||||
const lambda_functor<Arg>& b)\
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<typename CONST_CONVERSION <CONSTA A>::type, lambda_functor<Arg> >, \
|
||||
dig_arity<Arg>::value> >\
|
||||
(\
|
||||
tuple<typename CONST_CONVERSION <CONSTA A>::type, lambda_functor<Arg> >(a, b)\
|
||||
);\
|
||||
}\
|
||||
\
|
||||
#define BOOST_LAMBDA_BE2(OPER_NAME, ACTION, CONSTA, CONSTB, CONVERSION) \
|
||||
template<class A, class Arg> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_base< \
|
||||
ACTION, \
|
||||
tuple<typename CONVERSION <CONSTA A>::type, lambda_functor<Arg> > \
|
||||
> \
|
||||
> \
|
||||
OPER_NAME (CONSTA A& a, const lambda_functor<Arg>& b) { \
|
||||
return \
|
||||
lambda_functor_base< \
|
||||
ACTION, \
|
||||
tuple<typename CONVERSION <CONSTA A>::type, lambda_functor<Arg> > \
|
||||
> \
|
||||
(tuple<typename CONVERSION <CONSTA A>::type, lambda_functor<Arg> >(a, b)); \
|
||||
}
|
||||
|
||||
#if defined BOOST_LAMBDA_BINARY_EXPRESSION3
|
||||
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION3"
|
||||
|
||||
#if defined BOOST_LAMBDA_BE3
|
||||
#error "Multiple defines of BOOST_LAMBDA_BE3"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_EXPRESSION3(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) template<class ArgA, class ArgB> \
|
||||
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >,\
|
||||
tuple<lambda_functor<ArgA>, \
|
||||
lambda_functor<ArgB> >,\
|
||||
combine_arities<ArgA, ArgB>::value> >\
|
||||
OPER_FUNC_NAME (const lambda_functor<ArgA>& a, \
|
||||
const lambda_functor<ArgB>& b)\
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<lambda_functor<ArgA>, \
|
||||
lambda_functor<ArgB> >,\
|
||||
combine_arities<ArgA, ArgB>::value> >\
|
||||
(\
|
||||
boost::make_tuple(a, b)\
|
||||
);\
|
||||
}\
|
||||
\
|
||||
#define BOOST_LAMBDA_BE3(OPER_NAME, ACTION, CONSTA, CONSTB, CONVERSION) \
|
||||
template<class ArgA, class ArgB> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_base< \
|
||||
ACTION, \
|
||||
tuple<lambda_functor<ArgA>, lambda_functor<ArgB> > \
|
||||
> \
|
||||
> \
|
||||
OPER_NAME (const lambda_functor<ArgA>& a, const lambda_functor<ArgB>& b) { \
|
||||
return \
|
||||
lambda_functor_base< \
|
||||
ACTION, \
|
||||
tuple<lambda_functor<ArgA>, lambda_functor<ArgB> > \
|
||||
> \
|
||||
(tuple<lambda_functor<ArgA>, lambda_functor<ArgB> >(a, b)); \
|
||||
}
|
||||
|
||||
#if defined BOOST_LAMBDA_BINARY_EXPRESSION
|
||||
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION"
|
||||
#if defined BOOST_LAMBDA_BE
|
||||
#error "Multiple defines of BOOST_LAMBDA_BE"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_BINARY_EXPRESSION(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) \
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION1(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION)\
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION2(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION)\
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION3(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION)
|
||||
#define BOOST_LAMBDA_BE(OPER_NAME, ACTION, CONSTA, CONSTB, CONST_CONVERSION) \
|
||||
BOOST_LAMBDA_BE1(OPER_NAME, ACTION, CONSTA, CONSTB, CONST_CONVERSION) \
|
||||
BOOST_LAMBDA_BE2(OPER_NAME, ACTION, CONSTA, CONSTB, CONST_CONVERSION) \
|
||||
BOOST_LAMBDA_BE3(OPER_NAME, ACTION, CONSTA, CONSTB, CONST_CONVERSION)
|
||||
|
||||
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator+, arithmetic_action< plus_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator-, arithmetic_action< minus_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator*, arithmetic_action< multiply_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator/, arithmetic_action< divide_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator%, arithmetic_action< remainder_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator<<, bitwise_action< leftshift_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator>>, bitwise_action< rightshift_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator&, bitwise_action< and_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator|, bitwise_action< or_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator^, bitwise_action< xor_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator&&, logical_action< and_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator||, logical_action< or_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator<, relational_action< less_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator>, relational_action< greater_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator<=, relational_action< lessorequal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator>=, relational_action< greaterorequal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator==, relational_action< equal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator!=, relational_action< notequal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator+, arithmetic_action<plus_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator-, arithmetic_action<minus_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator*, arithmetic_action<multiply_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator/, arithmetic_action<divide_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator%, arithmetic_action<remainder_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator<<, bitwise_action<leftshift_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator>>, bitwise_action<rightshift_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator&, bitwise_action<and_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator|, bitwise_action<or_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator^, bitwise_action<xor_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator&&, logical_action<and_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator||, logical_action<or_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator<, relational_action<less_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator>, relational_action<greater_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator<=, relational_action<lessorequal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator>=, relational_action<greaterorequal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator==, relational_action<equal_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE(operator!=, relational_action<notequal_action>, const, const, const_copy_argument)
|
||||
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator+=, arithmetic_assignment_action< plus_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator-=, arithmetic_assignment_action< minus_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator*=, arithmetic_assignment_action< multiply_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator/=, arithmetic_assignment_action< divide_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator%=, arithmetic_assignment_action< remainder_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator<<=, bitwise_assignment_action< leftshift_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator>>=, bitwise_assignment_action< rightshift_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator&=, bitwise_assignment_action< and_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator|=, bitwise_assignment_action< or_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION(operator^=, bitwise_assignment_action< xor_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator+=, arithmetic_assignment_action<plus_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator-=, arithmetic_assignment_action<minus_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator*=, arithmetic_assignment_action<multiply_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator/=, arithmetic_assignment_action<divide_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator%=, arithmetic_assignment_action<remainder_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator<<=, bitwise_assignment_action<leftshift_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator>>=, bitwise_assignment_action<rightshift_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator&=, bitwise_assignment_action<and_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator|=, bitwise_assignment_action<or_action>, , const, reference_argument)
|
||||
BOOST_LAMBDA_BE(operator^=, bitwise_assignment_action<xor_action>, , const, reference_argument)
|
||||
|
||||
|
||||
// A special trick for comma operator for correct preprocessing
|
||||
@@ -135,9 +139,9 @@ BOOST_LAMBDA_BINARY_EXPRESSION(operator^=, bitwise_assignment_action< xor_action
|
||||
|
||||
#define BOOST_LAMBDA_COMMA_OPERATOR_NAME operator,
|
||||
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION1(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action< comma_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION2(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action< comma_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION3(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action< comma_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE1(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action<comma_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE2(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action<comma_action>, const, const, const_copy_argument)
|
||||
BOOST_LAMBDA_BE3(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action<comma_action>, const, const, const_copy_argument)
|
||||
|
||||
|
||||
|
||||
@@ -193,8 +197,8 @@ template<class T> struct convert_istream_to_ref_others_to_c_plain_by_default {
|
||||
|
||||
} // detail
|
||||
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION2(operator<<, bitwise_action< leftshift_action>, , const, detail::convert_ostream_to_ref_others_to_c_plain_by_default)
|
||||
BOOST_LAMBDA_BINARY_EXPRESSION2(operator>>, bitwise_action< rightshift_action>, , const, detail::convert_istream_to_ref_others_to_c_plain_by_default)
|
||||
BOOST_LAMBDA_BE2(operator<<, bitwise_action< leftshift_action>, , const, detail::convert_ostream_to_ref_others_to_c_plain_by_default)
|
||||
BOOST_LAMBDA_BE2(operator>>, bitwise_action< rightshift_action>, , const, detail::convert_istream_to_ref_others_to_c_plain_by_default)
|
||||
|
||||
|
||||
// special case for io_manipulators.
|
||||
@@ -205,43 +209,37 @@ BOOST_LAMBDA_BINARY_EXPRESSION2(operator>>, bitwise_action< rightshift_action>,
|
||||
template<class Arg, class Ret, class ManipArg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, bitwise_action<leftshift_action> >,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
|
||||
dig_arity<Arg>::value
|
||||
lambda_functor_base<
|
||||
bitwise_action<leftshift_action>,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
|
||||
>
|
||||
>
|
||||
operator<<(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, bitwise_action<leftshift_action> >,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
|
||||
dig_arity<Arg>::value
|
||||
lambda_functor_base<
|
||||
bitwise_action<leftshift_action>,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
|
||||
( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
|
||||
}
|
||||
|
||||
template<class Arg, class Ret, class ManipArg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, bitwise_action<rightshift_action> >,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
|
||||
dig_arity<Arg>::value
|
||||
lambda_functor_base<
|
||||
bitwise_action<rightshift_action>,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
|
||||
>
|
||||
>
|
||||
operator>>(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, bitwise_action<rightshift_action> >,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
|
||||
dig_arity<Arg>::value
|
||||
lambda_functor_base<
|
||||
bitwise_action<rightshift_action>,
|
||||
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
|
||||
>
|
||||
> ( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
|
||||
( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
|
||||
}
|
||||
|
||||
|
||||
@@ -251,123 +249,115 @@ operator>>(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
|
||||
// the result of a+1 would be const
|
||||
// To make the latter work too,
|
||||
// non-const arrays are taken as non-const and stored as non-const as well.
|
||||
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1
|
||||
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1"
|
||||
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_E1
|
||||
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_E1"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(OPER_FUNC_NAME, OPER_NAME, CONST) template<class Arg, int N, class B> \
|
||||
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<lambda_functor<Arg>, \
|
||||
CONST B (&) [N]>,\
|
||||
dig_arity<Arg>::value> > \
|
||||
OPER_FUNC_NAME (const lambda_functor<Arg>& a, \
|
||||
CONST B (&b) [N])\
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<lambda_functor<Arg>, CONST B (&) [N]>, \
|
||||
dig_arity<Arg>::value> >\
|
||||
(\
|
||||
tuple<lambda_functor<Arg>, CONST B (&) [N]>(a, b)\
|
||||
);\
|
||||
}\
|
||||
\
|
||||
#define BOOST_LAMBDA_PTR_ARITHMETIC_E1(OPER_NAME, ACTION, CONST) \
|
||||
template<class Arg, int N, class B> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_base<ACTION, tuple<lambda_functor<Arg>, CONST B(&)[N]> > \
|
||||
> \
|
||||
OPER_NAME (const lambda_functor<Arg>& a, CONST B(&b)[N]) \
|
||||
{ \
|
||||
return lambda_functor< \
|
||||
lambda_functor_base<ACTION, tuple<lambda_functor<Arg>, CONST B(&)[N]> > \
|
||||
>(tuple<lambda_functor<Arg>, CONST B(&)[N]>(a, b)); \
|
||||
}
|
||||
|
||||
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2
|
||||
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2"
|
||||
|
||||
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_E2
|
||||
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_E2"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(OPER_FUNC_NAME, OPER_NAME, CONST) template<int N, class A, class Arg> \
|
||||
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<CONST A (&) [N], lambda_functor<Arg> >, \
|
||||
dig_arity<Arg>::value> > \
|
||||
OPER_FUNC_NAME (CONST A (&a) [N], const lambda_functor<Arg>& b) \
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
|
||||
tuple<CONST A (&) [N], lambda_functor<Arg> >, \
|
||||
dig_arity<Arg>::value> >\
|
||||
(\
|
||||
tuple<CONST A (&) [N], lambda_functor<Arg> >(a, b)\
|
||||
);\
|
||||
}\
|
||||
\
|
||||
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(operator+, arithmetic_action< plus_action>,)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator+, arithmetic_action< plus_action>,)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(operator+, arithmetic_action< plus_action>,const)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator+, arithmetic_action< plus_action>,const)
|
||||
#define BOOST_LAMBDA_PTR_ARITHMETIC_E2(OPER_NAME, ACTION, CONST) \
|
||||
template<int N, class A, class Arg> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_base<ACTION, tuple<CONST A(&)[N], lambda_functor<Arg> > > \
|
||||
> \
|
||||
OPER_NAME (CONST A(&a)[N], const lambda_functor<Arg>& b) \
|
||||
{ \
|
||||
return \
|
||||
lambda_functor_base<ACTION, tuple<CONST A(&)[N], lambda_functor<Arg> > > \
|
||||
(tuple<CONST A(&)[N], lambda_functor<Arg> >(a, b)); \
|
||||
}
|
||||
|
||||
|
||||
//BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(operator-, arithmetic_action<minus_action>)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_E1(operator+, arithmetic_action<plus_action>,)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_E2(operator+, arithmetic_action<plus_action>,)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_E1(operator+, arithmetic_action<plus_action>,const)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_E2(operator+, arithmetic_action<plus_action>,const)
|
||||
|
||||
|
||||
//BOOST_LAMBDA_PTR_ARITHMETIC_E1(operator-, arithmetic_action<minus_action>)
|
||||
// This is not needed, since the result of ptr-ptr is an rvalue anyway
|
||||
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator-, arithmetic_action< minus_action>, )
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator-, arithmetic_action< minus_action>, const)
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_E2(operator-, arithmetic_action<minus_action>, )
|
||||
BOOST_LAMBDA_PTR_ARITHMETIC_E2(operator-, arithmetic_action<minus_action>, const)
|
||||
|
||||
|
||||
#undef BOOST_LAMBDA_BINARY_EXPRESSION1
|
||||
#undef BOOST_LAMBDA_BINARY_EXPRESSION2
|
||||
#undef BOOST_LAMBDA_BINARY_EXPRESSION3
|
||||
#undef BOOST_LAMBDA_BINARY_EXPRESSION
|
||||
#undef BOOST_LAMBDA_BE1
|
||||
#undef BOOST_LAMBDA_BE2
|
||||
#undef BOOST_LAMBDA_BE3
|
||||
#undef BOOST_LAMBDA_BE
|
||||
#undef BOOST_LAMBDA_COMMA_OPERATOR_NAME
|
||||
|
||||
#undef BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1
|
||||
#undef BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2
|
||||
#undef BOOST_LAMBDA_PTR_ARITHMETIC_E1
|
||||
#undef BOOST_LAMBDA_PTR_ARITHMETIC_E2
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// unary operators -----------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
#if defined BOOST_LAMBDA_UNARY_EXPRESSION
|
||||
#error "Multiple defines of BOOST_LAMBDA_UNARY_EXPRESSION"
|
||||
#if defined BOOST_LAMBDA_UE
|
||||
#error "Multiple defines of BOOST_LAMBDA_UE"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_UNARY_EXPRESSION(FUNCTION_NAME, ACTION_NAME) \
|
||||
template<class Arg>\
|
||||
inline const lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
|
||||
tuple<lambda_functor<Arg> >,\
|
||||
dig_arity<Arg>::value> >\
|
||||
FUNCTION_NAME (const lambda_functor<Arg>& a)\
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
|
||||
tuple<lambda_functor<Arg> >,\
|
||||
dig_arity<Arg>::value> >\
|
||||
( make_tuple(a) );\
|
||||
}\
|
||||
\
|
||||
#define BOOST_LAMBDA_UE(OPER_NAME, ACTION) \
|
||||
template<class Arg> \
|
||||
inline const \
|
||||
lambda_functor<lambda_functor_base<ACTION, tuple<lambda_functor<Arg> > > > \
|
||||
OPER_NAME (const lambda_functor<Arg>& a) \
|
||||
{ \
|
||||
return \
|
||||
lambda_functor_base<ACTION, tuple<lambda_functor<Arg> > > \
|
||||
( tuple<lambda_functor<Arg> >(a) ); \
|
||||
}
|
||||
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator+, unary_arithmetic_action<plus_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator-, unary_arithmetic_action<minus_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator~, bitwise_action<not_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator!, logical_action<not_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator++, pre_increment_decrement_action<increment_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator--, pre_increment_decrement_action<decrement_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator*, other_action<contentsof_action>)
|
||||
BOOST_LAMBDA_UNARY_EXPRESSION(operator&, other_action<addressof_action>)
|
||||
|
||||
#if defined BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION
|
||||
#error "Multiple defines of BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION"
|
||||
BOOST_LAMBDA_UE(operator+, unary_arithmetic_action<plus_action>)
|
||||
BOOST_LAMBDA_UE(operator-, unary_arithmetic_action<minus_action>)
|
||||
BOOST_LAMBDA_UE(operator~, bitwise_action<not_action>)
|
||||
BOOST_LAMBDA_UE(operator!, logical_action<not_action>)
|
||||
BOOST_LAMBDA_UE(operator++, pre_increment_decrement_action<increment_action>)
|
||||
BOOST_LAMBDA_UE(operator--, pre_increment_decrement_action<decrement_action>)
|
||||
BOOST_LAMBDA_UE(operator*, other_action<contentsof_action>)
|
||||
BOOST_LAMBDA_UE(operator&, other_action<addressof_action>)
|
||||
|
||||
#if defined BOOST_LAMBDA_POSTFIX_UE
|
||||
#error "Multiple defines of BOOST_LAMBDA_POSTFIX_UE"
|
||||
#endif
|
||||
|
||||
#define BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(FUNCTION_NAME, ACTION_NAME) \
|
||||
template<class Arg>\
|
||||
inline const lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
|
||||
tuple<lambda_functor<Arg> >,\
|
||||
dig_arity<Arg>::value> >\
|
||||
FUNCTION_NAME (const lambda_functor<Arg>& a, int)\
|
||||
{\
|
||||
return lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
|
||||
tuple<lambda_functor<Arg> >,\
|
||||
dig_arity<Arg>::value> >\
|
||||
( make_tuple(a) );\
|
||||
}\
|
||||
\
|
||||
#define BOOST_LAMBDA_POSTFIX_UE(OPER_NAME, ACTION) \
|
||||
template<class Arg> \
|
||||
inline const \
|
||||
lambda_functor<lambda_functor_base<ACTION, tuple<lambda_functor<Arg> > > > \
|
||||
OPER_NAME (const lambda_functor<Arg>& a, int) \
|
||||
{ \
|
||||
return \
|
||||
lambda_functor_base<ACTION, tuple<lambda_functor<Arg> > > \
|
||||
( tuple<lambda_functor<Arg> >(a) ); \
|
||||
}
|
||||
|
||||
BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(operator++, post_increment_decrement_action<increment_action>)
|
||||
BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(operator--, post_increment_decrement_action<decrement_action>)
|
||||
|
||||
#undef BOOST_LAMBDA_UNARY_EXPRESSION
|
||||
#undef BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION
|
||||
BOOST_LAMBDA_POSTFIX_UE(operator++, post_increment_decrement_action<increment_action>)
|
||||
BOOST_LAMBDA_POSTFIX_UE(operator--, post_increment_decrement_action<decrement_action>)
|
||||
|
||||
#undef BOOST_LAMBDA_UE
|
||||
#undef BOOST_LAMBDA_POSTFIX_UE
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
@@ -43,22 +43,19 @@ namespace lambda {
|
||||
template<class RET, class Arg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, explicit_return_type_action<RET> >,
|
||||
tuple<lambda_functor<Arg> >,
|
||||
dig_arity<Arg>::value
|
||||
lambda_functor_base<
|
||||
explicit_return_type_action<RET>,
|
||||
tuple<lambda_functor<Arg> >
|
||||
>
|
||||
>
|
||||
ret(const lambda_functor<Arg>& a1)
|
||||
{
|
||||
return lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, explicit_return_type_action<RET> >,
|
||||
tuple<lambda_functor<Arg> >,
|
||||
dig_arity<Arg>::value
|
||||
>
|
||||
>
|
||||
(tuple<lambda_functor<Arg> >(a1));
|
||||
return
|
||||
lambda_functor_base<
|
||||
explicit_return_type_action<RET>,
|
||||
tuple<lambda_functor<Arg> >
|
||||
>
|
||||
(tuple<lambda_functor<Arg> >(a1));
|
||||
}
|
||||
|
||||
// protect ------------------
|
||||
@@ -70,101 +67,21 @@ inline const T& protect(const T& t) { return t; }
|
||||
template<class Arg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, protect_action>,
|
||||
tuple<lambda_functor<Arg> >,
|
||||
NONE
|
||||
lambda_functor_base<
|
||||
protect_action,
|
||||
tuple<lambda_functor<Arg> >
|
||||
>
|
||||
>
|
||||
protect(const lambda_functor<Arg>& a1)
|
||||
{
|
||||
return lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, protect_action>,
|
||||
tuple<lambda_functor<Arg> >,
|
||||
NONE
|
||||
return
|
||||
lambda_functor_base<
|
||||
protect_action,
|
||||
tuple<lambda_functor<Arg> >
|
||||
>
|
||||
>
|
||||
(tuple<lambda_functor<Arg> >(a1));
|
||||
}
|
||||
|
||||
// -- identity -------------------------
|
||||
// identity templates
|
||||
template<class Arg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, other_action<identity_action> >,
|
||||
tuple<typename const_copy_argument<const Arg>::type>,
|
||||
NONE> >
|
||||
constant(const Arg& a)
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, other_action<identity_action> >,
|
||||
tuple<typename const_copy_argument<const Arg>::type>,
|
||||
NONE
|
||||
>
|
||||
> (tuple<typename const_copy_argument<const Arg>::type>(a));
|
||||
}
|
||||
|
||||
// since typedef's can't take template arguments,
|
||||
// I made this struct so you can use
|
||||
// constant_type<TYPE>::type constant_name(constant(value)); (GWP)
|
||||
|
||||
template<class Arg>
|
||||
class constant_type {
|
||||
public:
|
||||
typedef const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, other_action<identity_action> >,
|
||||
tuple<typename const_copy_argument<const Arg>::type>,
|
||||
NONE
|
||||
>
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
template<class Arg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, other_action<identity_action> >,
|
||||
tuple<typename reference_argument<Arg>::type>,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
var(Arg& a)
|
||||
{
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, other_action<identity_action> >,
|
||||
tuple<typename reference_argument<Arg>::type>,
|
||||
NONE
|
||||
>
|
||||
> (tuple<typename reference_argument<Arg>::type>(a));
|
||||
}
|
||||
|
||||
// since typedef's can't take template arguments, I made this struct so
|
||||
// you can use var_type<TYPE>::type var_name(var(i)); (GWP)
|
||||
|
||||
template<class Arg>
|
||||
class var_type {
|
||||
public:
|
||||
typedef
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, other_action<identity_action> >,
|
||||
tuple<typename reference_argument<Arg>::type>,
|
||||
NONE
|
||||
>
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Hides the lambda functorness of a lambda functor.
|
||||
@@ -175,51 +92,46 @@ public:
|
||||
// note, unlambda and protect are different things. Protect hides the lambda
|
||||
// functor for one application, unlambda for good.
|
||||
|
||||
template <class Arg>
|
||||
class non_lambda_functor : public has_sig {
|
||||
lambda_functor<Arg> lf; // a lambda functor
|
||||
template <class LambdaFunctor>
|
||||
class non_lambda_functor
|
||||
{
|
||||
LambdaFunctor lf;
|
||||
public:
|
||||
|
||||
|
||||
// This functor defines the result_type typedef.
|
||||
// The result type must be deducible without knowing the arguments
|
||||
|
||||
// TODO: check that passing unspecified as open args fails
|
||||
// typedef typename
|
||||
// return_type<Arg,
|
||||
// open_args<detail::unspecified,
|
||||
// detail::unspecified,
|
||||
// detail::unspecified> >::type
|
||||
// result_type;
|
||||
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
lambda_functor<Arg>::template sig<SigArgs>::type type;
|
||||
LambdaFunctor::inherited::
|
||||
template sig<typename SigArgs::tail_type>::type type;
|
||||
};
|
||||
|
||||
non_lambda_functor(const lambda_functor<Arg>& a) : lf(a) {}
|
||||
explicit non_lambda_functor(const LambdaFunctor& a) : lf(a) {}
|
||||
|
||||
typename sig<tuple<lambda_functor<Arg> > >::type
|
||||
typename LambdaFunctor::nullary_return_type
|
||||
operator()() const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg> > >::type>();
|
||||
return lf.template
|
||||
call<typename LambdaFunctor::nullary_return_type>
|
||||
(cnull_type(), cnull_type(), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A>
|
||||
typename sig<tuple<lambda_functor<Arg>, A&> >::type
|
||||
typename sig<tuple<const non_lambda_functor, A&> >::type
|
||||
operator()(A& a) const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&> >::type >(a);
|
||||
return lf.template call<typename sig<tuple<const non_lambda_functor, A&> >::type >(a, cnull_type(), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type
|
||||
typename sig<tuple<const non_lambda_functor, A&, B&> >::type
|
||||
operator()(A& a, B& b) const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type >(a, b);
|
||||
return lf.template call<typename sig<tuple<const non_lambda_functor, A&, B&> >::type >(a, b, cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type
|
||||
typename sig<tuple<const non_lambda_functor, A&, B&, C&> >::type
|
||||
operator()(A& a, B& b, C& c) const {
|
||||
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type>(a, b, c);
|
||||
return lf.template call<typename sig<tuple<const non_lambda_functor, A&, B&, C&> >::type>(a, b, c, cnull_type());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -227,9 +139,10 @@ template <class Arg>
|
||||
inline const Arg& unlambda(const Arg& a) { return a; }
|
||||
|
||||
template <class Arg>
|
||||
inline const non_lambda_functor<Arg> unlambda(const lambda_functor<Arg>& a)
|
||||
inline const non_lambda_functor<lambda_functor<Arg> >
|
||||
unlambda(const lambda_functor<Arg>& a)
|
||||
{
|
||||
return non_lambda_functor<Arg>(a);
|
||||
return non_lambda_functor<lambda_functor<Arg> >(a);
|
||||
}
|
||||
|
||||
// Due to a language restriction, lambda functors cannot be made to
|
||||
@@ -237,21 +150,173 @@ inline const non_lambda_functor<Arg> unlambda(const lambda_functor<Arg>& a)
|
||||
// temporaries, but sometimes they do. That's why a workaround is provided.
|
||||
// Note, that this potentially breaks const correctness, so be careful!
|
||||
|
||||
template <class Arg>
|
||||
inline const const_incorrect_lambda_functor<Arg>
|
||||
break_const(const lambda_functor<Arg>& lf)
|
||||
{
|
||||
return const_incorrect_lambda_functor<Arg>(lf);
|
||||
}
|
||||
|
||||
// any lambda functor can be turned into a const_incorrect_lambda_functor
|
||||
// The operator() takes arguments as consts and then casts constness
|
||||
// away. So this breaks const correctness!!! but is a necessary workaround
|
||||
// in some cases due to language limitations.
|
||||
// Note, that this is not a lambda_functor anymore, so it can not be used
|
||||
// as a sub lambda expression.
|
||||
|
||||
template <class LambdaFunctor>
|
||||
struct const_incorrect_lambda_functor {
|
||||
LambdaFunctor lf;
|
||||
public:
|
||||
|
||||
explicit const_incorrect_lambda_functor(const LambdaFunctor& a) : lf(a) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
LambdaFunctor::inherited::template
|
||||
sig<typename SigArgs::tail_type>::type type;
|
||||
};
|
||||
|
||||
// The nullary case is not needed (no arguments, no parameter type problems)
|
||||
|
||||
template<class A>
|
||||
typename sig<tuple<const const_incorrect_lambda_functor, A&> >::type
|
||||
operator()(const A& a) const {
|
||||
return lf.template call<typename sig<tuple<const const_incorrect_lambda_functor, A&> >::type >(const_cast<A&>(a), cnull_type(), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
typename sig<tuple<const const_incorrect_lambda_functor, A&, B&> >::type
|
||||
operator()(const A& a, const B& b) const {
|
||||
return lf.template call<typename sig<tuple<const const_incorrect_lambda_functor, A&, B&> >::type >(const_cast<A&>(a), const_cast<B&>(b), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename sig<tuple<const const_incorrect_lambda_functor, A&, B&, C&> >::type
|
||||
operator()(const A& a, const B& b, const C& c) const {
|
||||
return lf.template call<typename sig<tuple<const const_incorrect_lambda_functor, A&, B&, C&> >::type>(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c), cnull_type());
|
||||
}
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// any lambda functor can be turned into a const_parameter_lambda_functor
|
||||
// The operator() takes arguments as const.
|
||||
// This is useful if lambda functors are called with non-const rvalues.
|
||||
// Note, that this is not a lambda_functor anymore, so it can not be used
|
||||
// as a sub lambda expression.
|
||||
|
||||
template <class LambdaFunctor>
|
||||
struct const_parameter_lambda_functor {
|
||||
LambdaFunctor lf;
|
||||
public:
|
||||
|
||||
explicit const_parameter_lambda_functor(const LambdaFunctor& a) : lf(a) {}
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
typedef typename
|
||||
LambdaFunctor::inherited::template
|
||||
sig<typename SigArgs::tail_type>::type type;
|
||||
};
|
||||
|
||||
// The nullary case is not needed: no arguments, no constness problems.
|
||||
|
||||
template<class A>
|
||||
typename sig<tuple<const const_parameter_lambda_functor, const A&> >::type
|
||||
operator()(const A& a) const {
|
||||
return lf.template call<typename sig<tuple<const const_parameter_lambda_functor, const A&> >::type >(a, cnull_type(), cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B>
|
||||
typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&> >::type
|
||||
operator()(const A& a, const B& b) const {
|
||||
return lf.template call<typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&> >::type >(a, b, cnull_type(), cnull_type());
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&, const C&>
|
||||
>::type
|
||||
operator()(const A& a, const B& b, const C& c) const {
|
||||
return lf.template call<typename sig<tuple<const const_parameter_lambda_functor, const A&, const B&, const C&> >::type>(a, b, c, cnull_type());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Arg>
|
||||
inline const const_parameter_lambda_functor<Arg>
|
||||
inline const const_incorrect_lambda_functor<lambda_functor<Arg> >
|
||||
break_const(const lambda_functor<Arg>& lf)
|
||||
{
|
||||
return const_incorrect_lambda_functor<lambda_functor<Arg> >(lf);
|
||||
}
|
||||
|
||||
|
||||
template <class Arg>
|
||||
inline const const_parameter_lambda_functor<lambda_functor<Arg> >
|
||||
const_parameters(const lambda_functor<Arg>& lf)
|
||||
{
|
||||
return const_parameter_lambda_functor<Arg>(lf);
|
||||
return const_parameter_lambda_functor<lambda_functor<Arg> >(lf);
|
||||
}
|
||||
|
||||
|
||||
// make void ------------------------------------------------
|
||||
// make_void( x ) turns a lambda functor x with some return type y into
|
||||
// another lambda functor, which has a void return type
|
||||
// when called, the original return type is discarded
|
||||
|
||||
// we use this action. The action class will be called, which means that
|
||||
// the wrapped lambda functor is evaluated, but we just don't do anything
|
||||
// with the result.
|
||||
struct voidifier_action {
|
||||
template<class Ret, class A> static Ret apply(A&) {}
|
||||
};
|
||||
|
||||
template<class Args> struct return_type_N<voidifier_action, Args> {
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
action<1, voidifier_action>,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
make_void(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
action<1, voidifier_action>,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
(tuple<lambda_functor<Arg1> > (a1));
|
||||
}
|
||||
|
||||
// for non-lambda functors, make_void does nothing
|
||||
// (the argument gets evaluated immediately)
|
||||
|
||||
template<class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<do_nothing_action, null_type>
|
||||
>
|
||||
make_void(const Arg1& a1) {
|
||||
return
|
||||
lambda_functor_base<do_nothing_action, null_type>();
|
||||
}
|
||||
|
||||
// std_functor -----------------------------------------------------
|
||||
|
||||
// The STL uses the result_type typedef as the convention to let binders know
|
||||
// the return type of a function object.
|
||||
// LL uses the sig template.
|
||||
// To let LL know that the function object has the result_type typedef
|
||||
// defined, it can be wrapped with the std_functor function.
|
||||
|
||||
|
||||
// Just inherit form the template parameter (the standard functor),
|
||||
// and provide a sig template. So we have a class which is still the
|
||||
// same functor + the sig template.
|
||||
|
||||
template<class T>
|
||||
struct result_type_to_sig : public T {
|
||||
template<class Args> struct sig { typedef typename T::result_type type; };
|
||||
result_type_to_sig(const T& t) : T(t) {}
|
||||
};
|
||||
|
||||
template<class F>
|
||||
inline result_type_to_sig<F> std_functor(const F& f) { return f; }
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -22,6 +22,27 @@
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
using ::boost::type_traits::ice_and;
|
||||
using ::boost::type_traits::ice_or;
|
||||
using ::boost::type_traits::ice_not;
|
||||
|
||||
// Much of the type deduction code for standard arithmetic types
|
||||
// from Gary Powell
|
||||
|
||||
// different arities:
|
||||
template <class Act, class A1> struct return_type_1; // 1-ary actions
|
||||
template <class Act, class A1, class A2> struct return_type_2; // 2-ary
|
||||
template <class Act, class Args> struct return_type_N; // >3- ary
|
||||
|
||||
template <class Act, class A1> struct return_type_1_prot;
|
||||
template <class Act, class A1, class A2> struct return_type_2_prot; // 2-ary
|
||||
template <class Act, class A1> struct return_type_N_prot; // >3-ary
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class> class return_type_deduction_failure {};
|
||||
|
||||
// In some cases return type deduction should fail (an invalid lambda
|
||||
// expression). Sometimes the lambda expression can be ok, the return type
|
||||
// just is not deducible (user defined operators). Then return type deduction
|
||||
@@ -37,43 +58,45 @@ namespace lambda {
|
||||
// fail directly, but rather result in a valid but wrong return type,
|
||||
// causing a compile time error only if the function is really called.
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class> class return_type_deduction_failure {};
|
||||
|
||||
}
|
||||
} // end detail
|
||||
|
||||
// Much of the type deduction code for standard arithmetic types
|
||||
// from Gary Powell
|
||||
|
||||
template<class A, class B, class C>
|
||||
struct open_args {
|
||||
typedef A type1;
|
||||
typedef B type2;
|
||||
typedef C type3;
|
||||
|
||||
// return_type_X_prot classes --------------------------------------------
|
||||
// These classes are the first layer that gets instantiated from the
|
||||
// lambda_functor_base sig templates. It will check whether
|
||||
// the action is protectable and one of arguments is "protected" or its
|
||||
// evaluation will otherwise result in another lambda functor.
|
||||
// If this is a case, the result type will be another lambda functor.
|
||||
|
||||
// The arguments are always non-reference types, except for comma action
|
||||
// where the right argument can be a reference too. This is because it
|
||||
// matters (in the builtin case) whether the argument is an lvalue or
|
||||
// rvalue: int i; i, 1 -> rvalue; 1, i -> lvalue
|
||||
|
||||
template <class Act, class A> struct return_type_1_prot {
|
||||
public:
|
||||
typedef typename
|
||||
detail::IF<
|
||||
// is_protectable<Act>::value && is_lambda_functor<A>::value,
|
||||
ice_and<is_protectable<Act>::value, is_lambda_functor<A>::value>::value,
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
Act,
|
||||
tuple<typename detail::remove_reference_and_cv<A>::type>
|
||||
>
|
||||
>,
|
||||
typename return_type_1<Act, A>::type
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
|
||||
// -- return type -------------------------------------
|
||||
// does not handle lambda_functor lambda_functors
|
||||
// e.g. if the lambda_functor action is a lambda_functor
|
||||
|
||||
// The primary template:
|
||||
// if we know nothing about Arg, it is not a lambda_functor.
|
||||
// Hence the return type is Arg itself.
|
||||
|
||||
template <class Arg, class Open>
|
||||
struct return_type {
|
||||
typedef Arg type;
|
||||
// take care of the unavoidable instantiation for nullary case
|
||||
template<class Act> struct return_type_1_prot<Act, null_type> {
|
||||
typedef null_type type;
|
||||
};
|
||||
|
||||
|
||||
// different arities:
|
||||
template <class Act, class A1> class return_type_1; // 1-ary actions
|
||||
template <class Act, class A1, class A2> class return_type_2; // 2-ary
|
||||
template <class Act, class Args> class return_type_N; // >3- ary
|
||||
|
||||
|
||||
|
||||
// Unary actions (result from unary operators)
|
||||
// do not have a default return type.
|
||||
template<class Act, class A> struct return_type_1 {
|
||||
@@ -82,55 +105,27 @@ template<class Act, class A> struct return_type_1 {
|
||||
};
|
||||
|
||||
|
||||
|
||||
// read the comments for return_type_2_protect
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class A>
|
||||
class protect_conversion {
|
||||
|
||||
// T -> const T
|
||||
// T& -> T&
|
||||
// const T& -> const T
|
||||
// function& -> function&
|
||||
// const array& -> const array&
|
||||
// lambda functors are not stored as references
|
||||
// function reference types are function reference types
|
||||
typedef typename boost::remove_reference<A>::type A1;
|
||||
template <class T>
|
||||
class protect_conversion {
|
||||
typedef typename boost::remove_reference<T>::type non_ref_T;
|
||||
public:
|
||||
|
||||
public:
|
||||
|
||||
typedef typename detail::IF<
|
||||
boost::is_reference<A>::value
|
||||
&& !boost::is_const<A1>::value
|
||||
&& !is_lambda_functor<A1>::value,
|
||||
A,
|
||||
typename const_copy_argument<A1>::type // handles funtion and array type correctly
|
||||
>::RET type;
|
||||
};
|
||||
// add const to rvalues, so that all rvalues are stored as const in
|
||||
// the args tuple
|
||||
typedef typename detail::IF_type<
|
||||
// boost::is_reference<T>::value && !boost::is_const<non_ref_T>::value,
|
||||
ice_and<boost::is_reference<T>::value,
|
||||
ice_not<boost::is_const<non_ref_T>::value>::value>::value,
|
||||
detail::identity_mapping<T>,
|
||||
const_copy_argument<non_ref_T> // handles funtion and array
|
||||
>::type type; // types correctly
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
template <class Act, class A> struct return_type_1_protect {
|
||||
|
||||
typedef typename
|
||||
detail::IF<
|
||||
is_lambda_functor<A>::value,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, Act>,
|
||||
tuple<typename detail::protect_conversion<A>::type>,
|
||||
dig_arity<A>::value
|
||||
>
|
||||
>,
|
||||
typename return_type_1<Act, A>::type
|
||||
>::RET type;
|
||||
|
||||
};
|
||||
|
||||
// binary actions ---------------------------------------------------
|
||||
template <class Act, class A, class B> struct return_type_2;
|
||||
template <class Act, class A, class B> struct return_type_2_prot {
|
||||
|
||||
// experimental feature
|
||||
// We may have a lambda functor as a result type of a subexpression
|
||||
@@ -140,8 +135,8 @@ typedef typename
|
||||
// We need to make a conservative choise here.
|
||||
// The resulting lambda functor stores all const reference arguments as
|
||||
// const copies. References to non-const are stored as such.
|
||||
// So if the source of the argument is an const open argument, a bound
|
||||
// argument stroed as a const reference, or a function returning a
|
||||
// So if the source of the argument is a const open argument, a bound
|
||||
// argument stored as a const reference, or a function returning a
|
||||
// const reference, that information is lost. There is no way of
|
||||
// telling apart 'real const references' from just 'LL internal
|
||||
// const references' (or it would be really hard)
|
||||
@@ -151,460 +146,112 @@ typedef typename
|
||||
// action type and code, and a copy compatible argument tuple.
|
||||
|
||||
|
||||
|
||||
template <class Act, class A, class B> struct return_type_2_protect {
|
||||
|
||||
// typedef typename boost::remove_reference<A>::type A1;
|
||||
// typedef typename boost::remove_reference<B>::type B1;
|
||||
|
||||
// // adding const to a function type fails, these tests are to
|
||||
// // avoid that. Note that only the true branch is instantiated with this IF
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// !is_lambda_functor<A1>::value && (boost::is_function<A1>::value || !(boost::is_const<A1>::value)),
|
||||
// boost::add_reference<A1>,
|
||||
// boost::add_const<A1>
|
||||
// >::type A2;
|
||||
|
||||
// typedef typename
|
||||
// detail::IF_type<
|
||||
// !is_lambda_functor<B1>::value && ( boost::is_function<B1>::value || !(boost::is_const<B1>::value)),
|
||||
// boost::add_reference<B1>,
|
||||
// boost::add_const<B1>
|
||||
// >::type B2;
|
||||
|
||||
typedef typename boost::remove_reference<A>::type non_ref_A;
|
||||
typedef typename boost::remove_reference<B>::type non_ref_B;
|
||||
|
||||
typedef typename
|
||||
detail::IF<
|
||||
is_lambda_functor<A>::value || is_lambda_functor<B>::value,
|
||||
// is_protectable<Act>::value &&
|
||||
// (is_lambda_functor<A>::value || is_lambda_functor<B>::value),
|
||||
ice_and<is_protectable<Act>::value,
|
||||
ice_or<is_lambda_functor<A>::value,
|
||||
is_lambda_functor<B>::value>::value>::value,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<2, Act>,
|
||||
lambda_functor_base<
|
||||
Act,
|
||||
tuple<typename detail::protect_conversion<A>::type,
|
||||
typename detail::protect_conversion<B>::type>,
|
||||
combine_arities<A, B>::value
|
||||
typename detail::protect_conversion<B>::type>
|
||||
>
|
||||
>,
|
||||
typename return_type_2<Act, A, B>::type
|
||||
typename return_type_2<Act, non_ref_A, non_ref_B>::type
|
||||
>::RET type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// // unary function action (it is binary action)
|
||||
// // If a function object overloads operator(), the return type could depend
|
||||
// // on the argument types. This is not taken into consideration.
|
||||
// template<class A, class B, class Ret>
|
||||
// struct return_type_2<function_action<2, Ret>, A, B> {
|
||||
// typedef typename return_type_1<function_action<1, Ret>, A>::type type;
|
||||
// };
|
||||
|
||||
|
||||
// reduce to lambda_functor_args
|
||||
// to be on the safe side, constness and references are stripped away,
|
||||
// though the type should always be plain
|
||||
template <class Arg, class Open>
|
||||
struct return_type<lambda_functor<Arg>, Open> {
|
||||
typedef typename return_type<Arg, Open>::type type;
|
||||
// take care of the unavoidable instantiation for nullary case
|
||||
template<class Act> struct return_type_2_prot<Act, null_type, null_type> {
|
||||
typedef null_type type;
|
||||
};
|
||||
template <class Arg, class Open>
|
||||
struct return_type<const lambda_functor<Arg>, Open> {
|
||||
typedef typename return_type<Arg, Open>::type type;
|
||||
// take care of the unavoidable instantiation for nullary case
|
||||
template<class Act, class Other> struct return_type_2_prot<Act, Other, null_type> {
|
||||
typedef null_type type;
|
||||
};
|
||||
template <class Arg, class Open>
|
||||
struct return_type<lambda_functor<Arg>&, Open> {
|
||||
typedef typename return_type<Arg, Open>::type type;
|
||||
};
|
||||
template <class Arg, class Open>
|
||||
struct return_type<const lambda_functor<Arg>&, Open> {
|
||||
typedef typename return_type<Arg, Open>::type type;
|
||||
// take care of the unavoidable instantiation for nullary case
|
||||
template<class Act, class Other> struct return_type_2_prot<Act, null_type, Other> {
|
||||
typedef null_type type;
|
||||
};
|
||||
|
||||
// placeholders
|
||||
// to be on the safe side, constness and references are stripped away,
|
||||
// though the type should always be plain
|
||||
template<int I, class Open>
|
||||
struct return_type<const placeholder<I>, Open> {
|
||||
typedef typename return_type<placeholder<I>, Open>::type type;
|
||||
};
|
||||
template<int I, class Open>
|
||||
struct return_type<placeholder<I>&, Open> {
|
||||
typedef typename return_type<placeholder<I>, Open>::type type;
|
||||
};
|
||||
template<int I, class Open>
|
||||
struct return_type<const placeholder<I>&, Open> {
|
||||
typedef typename return_type<placeholder<I>, Open>::type type;
|
||||
// comma is a special case, as the user defined operator can return
|
||||
// an lvalue (reference) too, hence it must be handled at this level.
|
||||
template<class A, class B>
|
||||
struct return_type_2_comma
|
||||
{
|
||||
typedef typename boost::remove_reference<A>::type non_ref_A;
|
||||
typedef typename boost::remove_reference<B>::type non_ref_B;
|
||||
|
||||
typedef typename
|
||||
detail::IF<
|
||||
// is_protectable<other_action<comma_action> >::value && // it is protectable
|
||||
// (is_lambda_functor<A>::value || is_lambda_functor<B>::value),
|
||||
ice_and<is_protectable<other_action<comma_action> >::value, // it is protectable
|
||||
ice_or<is_lambda_functor<A>::value,
|
||||
is_lambda_functor<B>::value>::value>::value,
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
other_action<comma_action>,
|
||||
tuple<typename detail::protect_conversion<A>::type,
|
||||
typename detail::protect_conversion<B>::type>
|
||||
>
|
||||
>,
|
||||
typename
|
||||
return_type_2<other_action<comma_action>, non_ref_A, non_ref_B>::type
|
||||
>::RET type1;
|
||||
|
||||
// if no user defined return_type_2 (or plain_return_type_2) specialization
|
||||
// matches, then return the righthand argument
|
||||
typedef typename
|
||||
detail::IF<
|
||||
boost::is_same<type1, detail::unspecified>::value,
|
||||
B,
|
||||
type1
|
||||
>::RET type;
|
||||
|
||||
};
|
||||
|
||||
template <class Open>
|
||||
struct return_type<placeholder<FIRST>, Open> {
|
||||
typedef typename Open::type1 type;
|
||||
|
||||
// currently there are no protectable actions with > 2 args
|
||||
// Note, that if there will be, lambda_functor_base will have to be
|
||||
// changed to not get rid of references in Args elements
|
||||
|
||||
template<class Act, class Args> struct return_type_N_prot {
|
||||
typedef typename return_type_N<Act, Args>::type type;
|
||||
};
|
||||
|
||||
template <class Open>
|
||||
struct return_type<placeholder<SECOND>, Open> {
|
||||
typedef typename Open::type2 type;
|
||||
};
|
||||
|
||||
template <class Open>
|
||||
struct return_type<placeholder<THIRD>, Open> {
|
||||
typedef typename Open::type2 type;
|
||||
};
|
||||
|
||||
// the exception placeholder deduction, the third placeholder slot
|
||||
// is reused
|
||||
template <class Open>
|
||||
struct return_type<placeholder<EXCEPTION>, Open> {
|
||||
typedef typename Open::type3 type;
|
||||
// take care of the unavoidable instantiation for nullary case
|
||||
template<class Act> struct return_type_N_prot<Act, null_type> {
|
||||
typedef null_type type;
|
||||
};
|
||||
|
||||
// handle different kind of actions ------------------------
|
||||
|
||||
// function action: this covers all arities:
|
||||
// If a function object overloads operator(), the return type could depend
|
||||
// on the argument types. This is not taken into consideration.
|
||||
|
||||
// use the return type given in the bind invocation as bind<Ret>(...)
|
||||
template<class A, class Ret>
|
||||
struct return_type_1<function_action<1, Ret>, A > {
|
||||
typedef Ret type;
|
||||
};
|
||||
template<class A, class B, class Ret>
|
||||
struct return_type_2<function_action<2, Ret>, A, B > {
|
||||
typedef Ret type;
|
||||
};
|
||||
template<int I, class Args, class Ret>
|
||||
struct return_type_N<function_action<I, Ret>, Args> {
|
||||
typedef Ret type;
|
||||
};
|
||||
|
||||
// Ret is detail::unspecified, so try to deduce return type
|
||||
template<class A>
|
||||
struct return_type_1<function_action<1, detail::unspecified>, A > {
|
||||
typedef typename function_adaptor_with_actuals<typename tuple<A>::inherited>::type type;
|
||||
};
|
||||
template<class A, class B>
|
||||
struct return_type_2<function_action<2, detail::unspecified>, A, B > {
|
||||
typedef typename function_adaptor_with_actuals<typename tuple<A, B>::inherited>::type type;
|
||||
};
|
||||
template<int I, class Args>
|
||||
struct return_type_N<function_action<I, detail::unspecified>, Args > {
|
||||
typedef typename function_adaptor_with_actuals<Args>::type type;
|
||||
};
|
||||
|
||||
// in the case of function action, the first element in Args is
|
||||
// some type of function
|
||||
typedef typename Args::head_type Func;
|
||||
typedef typename detail::remove_reference_and_cv<Func>::type plain_Func;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T, class Open>
|
||||
struct map_to_return_types {
|
||||
typedef typename return_type<
|
||||
typename boost::tuples::access_traits<typename T::head_type>::const_type,
|
||||
Open
|
||||
>::type ret_type;
|
||||
|
||||
// const and reference is added, so that specializations for return_type_1
|
||||
// become easier (we can rely on the Args always being references, so the
|
||||
// number of specializations doesn't explode.
|
||||
// Note! If T is already a reference to nonconst, it will remain that way
|
||||
// To return type deduction, const T& is the same as rvalue T
|
||||
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<ret_type>::type
|
||||
>::type ref_to_const_ret_type;
|
||||
|
||||
typedef boost::tuples::cons<
|
||||
ref_to_const_ret_type,
|
||||
typename map_to_return_types<typename T::tail_type, Open>::type
|
||||
> type;
|
||||
};
|
||||
|
||||
template <class Open>
|
||||
struct map_to_return_types<boost::tuples::null_type, Open> {
|
||||
typedef boost::tuples::null_type type;
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
// general unary and binary actions
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, Act>, Args, Code>, Open> {
|
||||
|
||||
typedef typename return_type<
|
||||
typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
Open
|
||||
>::type A_type;
|
||||
|
||||
// const and reference is added, so that specializations for return_type_1
|
||||
// become easier (we can rely on the Args always being references, so the
|
||||
// number of specializations doesn't explode.
|
||||
// Note! If T is already a reference to nonconst, it will remain that way
|
||||
// To return type deduction, const T& is the same as rvalue T
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<A_type>::type
|
||||
>::type refc_A_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
detail::is_protectable_action<Act>::value,
|
||||
return_type_1_protect<Act, refc_A_type>,
|
||||
return_type_1<Act, refc_A_type>
|
||||
>::type type;
|
||||
|
||||
};
|
||||
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
class return_type<lambda_functor_args<action<2, Act>, Args, Code>, Open> {
|
||||
|
||||
typedef typename return_type<
|
||||
typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
Open
|
||||
>::type A_type;
|
||||
|
||||
typedef typename return_type<
|
||||
typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
Open
|
||||
>::type B_type;
|
||||
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<A_type>::type
|
||||
>::type refc_A_type;
|
||||
typedef typename boost::add_reference<
|
||||
typename boost::add_const<B_type>::type
|
||||
>::type refc_B_type;
|
||||
|
||||
public:
|
||||
typedef typename
|
||||
detail::IF_type<
|
||||
detail::is_protectable_action<Act>::value,
|
||||
return_type_2_protect<Act, refc_A_type, refc_B_type>,
|
||||
return_type_2<Act, refc_A_type, refc_B_type>
|
||||
>::type type;
|
||||
|
||||
};
|
||||
|
||||
// This is the general case. Will match any action with arity >= 3
|
||||
template<int I, class Act, class Args, int Code, class Open>
|
||||
class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
typedef typename detail::map_to_return_types<Args, Open>::type actual_args;
|
||||
public:
|
||||
typedef typename return_type_N<Act, actual_args>::type type;
|
||||
};
|
||||
|
||||
// template<class Act, class Args, int Code, class Open>
|
||||
// class return_type<lambda_functor_args<action<3, Act>, Args, Code>, Open> {
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type A_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
// Open
|
||||
// >::type B_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<2, Args>::type,
|
||||
// Open
|
||||
// >::type C_type;
|
||||
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<A_type>::type
|
||||
// >::type refc_A_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<B_type>::type
|
||||
// >::type refc_B_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<C_type>::type
|
||||
// >::type refc_C_type;
|
||||
|
||||
// public:
|
||||
// // no 3- or higher ary protectable actions exist, no need to check
|
||||
// typedef typename return_type_3<Act, refc_A_type, refc_B_type, refc_C_type>::type type;
|
||||
// };
|
||||
|
||||
// // 4 args or more (must be a function action)
|
||||
// template<int I, class Act, class Args, int Code, class Open>
|
||||
// class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type A_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
// Open
|
||||
// >::type B_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<2, Args>::type,
|
||||
// Open
|
||||
// >::type C_type;
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<3, Args>::type,
|
||||
// Open
|
||||
// >::type D_type;
|
||||
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<A_type>::type
|
||||
// >::type refc_A_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<B_type>::type
|
||||
// >::type refc_B_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<C_type>::type
|
||||
// >::type refc_C_type;
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<D_type>::type
|
||||
// >::type refc_D_type;
|
||||
|
||||
// public:
|
||||
// typedef typename return_type_4<Act, refc_A_type, refc_B_type, refc_C_type, refc_D_type>::type type;
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// special case for comma action:
|
||||
// As the return type needs to be exactly the type of the rightmost argument,
|
||||
// we cannot add a const and reference (we need to preserve rvalueness)
|
||||
// note, that return_type_2_protect is still called, so user can overload
|
||||
// return_type_2 for user defined types.
|
||||
|
||||
template<class Args, int Code, class Open>
|
||||
class return_type<lambda_functor_args<action<2, other_action<comma_action> >, Args, Code>, Open> {
|
||||
|
||||
typedef typename return_type<
|
||||
typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
Open
|
||||
>::type A_type;
|
||||
|
||||
typedef typename return_type<
|
||||
typename detail::tuple_element_as_reference<1, Args>::type,
|
||||
Open
|
||||
>::type B_type;
|
||||
|
||||
public:
|
||||
typedef typename
|
||||
return_type_2_protect<other_action<comma_action>, A_type, B_type>::type type;
|
||||
};
|
||||
|
||||
// protect action:
|
||||
// the return type is the lambda_functor wrapped inside protect
|
||||
template<class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, protect_action>, Args, Code>, Open> {
|
||||
typedef typename detail::tuple_element_as_reference<0,Args>::type type;
|
||||
};
|
||||
|
||||
// curry action:
|
||||
template<class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<3, curry_action<1> >,
|
||||
Args, Code>, Open> {
|
||||
// take one stored argument type and push it to the open args
|
||||
typedef typename
|
||||
return_type<
|
||||
typename boost::tuples::element<0,Args>::type,
|
||||
open_args<typename boost::tuples::element<1,Args>::type,
|
||||
typename Open::type1,
|
||||
typename Open::type2> >::type
|
||||
type;
|
||||
};
|
||||
|
||||
template<class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<4, curry_action<1> >, Args, Code>, Open> {
|
||||
// take one stored argument type and push it to the open args
|
||||
typedef typename
|
||||
return_type<typename boost::tuples::element<0,Args>::type,
|
||||
open_args<typename boost::tuples::element<1,Args>::type,
|
||||
typename Open::type1,
|
||||
typename Open::type2> >::type
|
||||
type;
|
||||
};
|
||||
template<class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<4, curry_action<2> >, Args, Code>, Open> {
|
||||
// take two stored arguments type and push them to the open args
|
||||
typedef typename
|
||||
return_type<typename boost::tuples::element<0,Args>::type,
|
||||
open_args<typename boost::tuples::element<1,Args>::type,
|
||||
typename boost::tuples::element<2,Args>::type,
|
||||
typename Open::type1> >::type
|
||||
type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// // 3 arguments or more ---------------------------------------------
|
||||
// // this must be a function_action. Note that the previous unary and binary
|
||||
// // specalisations take care of nullary and unary function adaptors, that is,
|
||||
// // unary and binary actions.
|
||||
// // Since function_actions determine the return type based on the function
|
||||
// // object only, we can ignore the arguments and reuse return_type_1.
|
||||
|
||||
// template <int I, class Act, class Args, int Code, class Open>
|
||||
// class return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
|
||||
|
||||
// typedef typename return_type<
|
||||
// typename detail::tuple_element_as_reference<0, Args>::type,
|
||||
// Open
|
||||
// >::type A_type;
|
||||
|
||||
// // reference is added, so that specializations for return_type_1
|
||||
// // become easier.
|
||||
// typedef typename boost::add_reference<
|
||||
// typename boost::add_const<A_type>::type
|
||||
// >::type refc_A_type;
|
||||
|
||||
// public:
|
||||
|
||||
// typedef typename return_type_1_protect<Act, refc_A_type>::type type;
|
||||
// };
|
||||
|
||||
// The explicit return type action case, it is unary
|
||||
template<class RET, class Args, int Code, class Open>
|
||||
struct return_type<
|
||||
lambda_functor_args<
|
||||
action<1, explicit_return_type_action<RET> >,
|
||||
Args,
|
||||
Code>,
|
||||
Open>
|
||||
{
|
||||
typedef RET type;
|
||||
};
|
||||
|
||||
|
||||
// return types of control constructs (all return void)
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<1, return_void_action<Act> >,
|
||||
Args, Code>, Open >
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<2, return_void_action<Act> >,
|
||||
Args, Code>, Open >
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<3, return_void_action<Act> >,
|
||||
Args, Code>, Open >
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<int I, class Act, class Args, int Code, class Open>
|
||||
struct return_type<lambda_functor_args<action<I, return_void_action<Act> >,
|
||||
Args, Code>, Open >
|
||||
{
|
||||
typedef void type;
|
||||
public:
|
||||
// pass the function to function_adaptor, and get the return type from
|
||||
// that
|
||||
typedef typename function_adaptor<plain_Func>::template sig<Args>::type type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see http://lambda.cs.utu.fi
|
||||
// For more information, see http://www.boost.org
|
||||
|
||||
|
||||
#ifndef BOOST_LAMBDA_SELECT_FUNCTIONS_HPP
|
||||
@@ -21,104 +21,29 @@ namespace boost {
|
||||
namespace lambda {
|
||||
namespace detail {
|
||||
|
||||
// selector<ArityCode>::select functions ---------------------------------
|
||||
|
||||
// called from select functions
|
||||
|
||||
template <int Code> struct selector;
|
||||
|
||||
|
||||
// The primary template covers all lambda functors with the EXCEPTION
|
||||
// placeholder as a subexpression
|
||||
template <int Code> struct selector {
|
||||
template<class RET, class Op, class A, class B, class C>
|
||||
static RET select(Op& op, A& a, B& b, C& c) {
|
||||
return op.template ret_call<RET>(a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
// The cases cover all other placeholders
|
||||
template <> struct selector<NONE> {
|
||||
template<class RET, class Op, class A, class B, class C>
|
||||
static RET select(Op& op, A& a, B& b, C& c) {
|
||||
return op.template ret_call<RET>();
|
||||
}
|
||||
};
|
||||
template <> struct selector<FIRST> {
|
||||
template<class RET, class Op, class A, class B, class C>
|
||||
static RET select(Op& op, A& a, B& b, C& c) {
|
||||
return op.template ret_call<RET>(a);
|
||||
}
|
||||
};
|
||||
template <> struct selector<SECOND> {
|
||||
template<class RET, class Op, class A, class B, class C>
|
||||
static RET select(Op& op, A& a, B& b, C& c) {
|
||||
return op.template ret_call<RET>(a, b);
|
||||
}
|
||||
};
|
||||
template <> struct selector<THIRD> {
|
||||
template<class RET, class Op, class A, class B, class C>
|
||||
static RET select(Op& op, A& a, B& b, C& c) {
|
||||
return op.template ret_call<RET>(a, b, c);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// select functions -------------------------------
|
||||
template<class Any, class A, class B, class C>
|
||||
inline Any& select(Any& any, A&, B&, C&) { return any; }
|
||||
template<class Any, CALL_TEMPLATE_ARGS>
|
||||
inline Any& select(Any& any, CALL_FORMAL_ARGS) { CALL_USE_ARGS; return any; }
|
||||
|
||||
template<class A, class B, class C>
|
||||
inline A& select(const lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
|
||||
return a;
|
||||
}
|
||||
template<class A, class B, class C>
|
||||
inline A& select(lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
|
||||
return a;
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
inline B& select(const lambda_functor<placeholder<SECOND> >&, A&, B& b, C&) {
|
||||
return b;
|
||||
template<class Arg, CALL_TEMPLATE_ARGS>
|
||||
inline typename Arg::template sig<tuple<CALL_REFERENCE_TYPES> >::type
|
||||
select ( const lambda_functor<Arg>& op, CALL_FORMAL_ARGS ) {
|
||||
return op.template call<
|
||||
typename Arg::template sig<tuple<CALL_REFERENCE_TYPES> >::type
|
||||
>(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
template<class A, class B, class C>
|
||||
inline B& select(lambda_functor<placeholder<SECOND> >&, A&, B& b, C&) {
|
||||
return b;
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
inline C& select(const lambda_functor<placeholder<THIRD> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
template<class A, class B, class C>
|
||||
inline C& select(lambda_functor<placeholder<THIRD> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
// Exception placeholder reuses the third argument position
|
||||
template<class A, class B, class C>
|
||||
inline C& select(const lambda_functor<placeholder<EXCEPTION> >&, A&, B&, C& c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
template<class A, class B, class C>
|
||||
inline C& select(lambda_functor<placeholder<EXCEPTION> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
template<class Arg, class A, class B, class C>
|
||||
inline typename return_type<lambda_functor<Arg>, open_args<A&, B&, C&> >::type
|
||||
select ( const lambda_functor<Arg>& op, A& a, B& b, C& c ) {
|
||||
return selector<dig_arity<Arg>::value>::template select<typename return_type<lambda_functor<Arg>, open_args<A&, B&, C&> >::type>(op, a, b, c);
|
||||
}
|
||||
template<class Arg, class A, class B, class C>
|
||||
inline typename return_type<lambda_functor<Arg>, open_args<A&, B&, C&> >::type
|
||||
select ( lambda_functor<Arg>& op, A& a, B& b, C& c) {
|
||||
return selector<dig_arity<Arg>::value>::template select<typename return_type<lambda_functor<Arg>, open_args<A&, B&, C&> >::type>(op, a, b, c);
|
||||
template<class Arg, CALL_TEMPLATE_ARGS>
|
||||
inline typename Arg::template sig<tuple<CALL_REFERENCE_TYPES> >::type
|
||||
select ( lambda_functor<Arg>& op, CALL_FORMAL_ARGS) {
|
||||
return op.template call<
|
||||
typename Arg::template sig<tuple<CALL_REFERENCE_TYPES> >::type
|
||||
>(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// selector functions where the return type is explicitly given
|
||||
// select functions where the return type is explicitly given
|
||||
// Note: on many functions, this return type is just discarded.
|
||||
// The select functions are inside a class template, and the return type
|
||||
// is a class template argument.
|
||||
@@ -126,62 +51,24 @@ select ( lambda_functor<Arg>& op, A& a, B& b, C& c) {
|
||||
// specified template parameter.
|
||||
// However, this resulted in ambiguous calls (at least with gcc 2.95.2
|
||||
// and edg 2.44). Not sure whether the compilers were right or wrong.
|
||||
template<class RET> struct ret_selector
|
||||
{
|
||||
|
||||
// TODO: add checks that RET is of correct type
|
||||
template<class Any, class A, class B, class C>
|
||||
static Any& select(Any& any, A&, B&, C&) { return any; }
|
||||
|
||||
template<class A, class B, class C>
|
||||
static A& select(const lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
|
||||
return a;
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
static A& select(lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
|
||||
return a;
|
||||
}
|
||||
template<class RET> struct r_select {
|
||||
|
||||
template<class A, class B, class C>
|
||||
static B& select(const lambda_functor<placeholder<SECOND> >&, A&, B& b, C&) { return b;
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
static B& select(lambda_functor<placeholder<SECOND> >&, A&, B& b, C&) {
|
||||
return b;
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
static C& select(const lambda_functor<placeholder<THIRD> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
template<class A, class B, class C>
|
||||
static C& select(lambda_functor<placeholder<THIRD> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
|
||||
// Exception placeholder reuses the third argument position
|
||||
template<class A, class B, class C>
|
||||
static inline C&
|
||||
select(const lambda_functor<placeholder<EXCEPTION> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
template<class A, class B, class C>
|
||||
static inline C&
|
||||
select(lambda_functor<placeholder<EXCEPTION> >&, A&, B&, C& c) {
|
||||
return c;
|
||||
}
|
||||
// Any == RET
|
||||
template<class Any, CALL_TEMPLATE_ARGS>
|
||||
static
|
||||
inline RET go (Any& any, CALL_FORMAL_ARGS) { CALL_USE_ARGS; return any; }
|
||||
|
||||
|
||||
template<class Arg, class A, class B, class C>
|
||||
static RET select (const lambda_functor<Arg>& op, A& a, B& b, C& c ) {
|
||||
return selector<dig_arity<Arg>::value>::template select<RET>(op, a, b, c);
|
||||
template<class Arg, CALL_TEMPLATE_ARGS>
|
||||
static
|
||||
inline RET go (const lambda_functor<Arg>& op, CALL_FORMAL_ARGS ) {
|
||||
return op.template call<RET>(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
template<class Arg, class A, class B, class C>
|
||||
static RET select (lambda_functor<Arg>& op, A& a, B& b, C& c ) {
|
||||
return selector<dig_arity<Arg>::value>::template select<RET>(op, a, b, c);
|
||||
template<class Arg, CALL_TEMPLATE_ARGS>
|
||||
static
|
||||
inline RET go (lambda_functor<Arg>& op, CALL_FORMAL_ARGS ) {
|
||||
return op.template call<RET>(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
// Boost Lambda Library -- switch.hpp -----------------------------------
|
||||
//
|
||||
// Copyright (C) 2000 Gary Powell (gary.powell@sierra.com)
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(BOOST_LAMBDA_SWITCH_HPP)
|
||||
#define BOOST_LAMBDA_SWITCH_HPP
|
||||
|
||||
#include "boost/preprocessor/enum_shifted_params.hpp"
|
||||
#include "boost/preprocessor/repeat_2nd.hpp"
|
||||
#include "boost/preprocessor/tuple.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
// Switch actions
|
||||
template <class Switch1 = null_type, class Switch2 = null_type,
|
||||
class Switch3 = null_type, class Switch4 = null_type,
|
||||
class Switch5 = null_type, class Switch6 = null_type,
|
||||
class Switch7 = null_type, class Switch8 = null_type,
|
||||
class Switch9 = null_type>
|
||||
struct switch_action {};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
// templates to represent special lambda functors for the cases in
|
||||
// switch statements
|
||||
|
||||
template <int Value> struct case_label {};
|
||||
struct default_label {};
|
||||
|
||||
template<class Type> struct switch_case_tag {};
|
||||
|
||||
// a normal case is represented as:
|
||||
// tagged_lambda_functor<switch_case_tag<case_label<N> > >, LambdaFunctor>
|
||||
|
||||
// the default case as:
|
||||
// tagged_lambda_functor<switch_case_tag<default_label> >, LambdaFunctor>
|
||||
|
||||
|
||||
} // end detail
|
||||
|
||||
|
||||
/// create switch_case_tag tagged_lambda_functors
|
||||
template <int CaseValue, class Arg>
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<Arg>
|
||||
>
|
||||
case_statement(const lambda_functor<Arg>& a) {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<Arg>
|
||||
>(a);
|
||||
}
|
||||
|
||||
// No case body case.
|
||||
template <int CaseValue>
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<0, return_void_action<do_nothing_action> >,
|
||||
null_type,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
>
|
||||
case_statement() {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<0, return_void_action<do_nothing_action> >,
|
||||
null_type,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
> () ;
|
||||
}
|
||||
|
||||
// default label
|
||||
template <class Arg>
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<Arg>
|
||||
>
|
||||
default_statement(const lambda_functor<Arg>& a) {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<Arg>
|
||||
>(a);
|
||||
}
|
||||
|
||||
// default lable, no case body case.
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<0, return_void_action<do_nothing_action> >,
|
||||
null_type,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
>
|
||||
default_statement() {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<0, return_void_action<do_nothing_action> >,
|
||||
null_type,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
> () ;
|
||||
}
|
||||
|
||||
|
||||
// Specializations for lambda_functor_base of case_statement -----------------
|
||||
|
||||
// 0 case type:
|
||||
// useless (just the condition part) but provided for completeness.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<
|
||||
action<1, return_void_action<switch_action< > > >,
|
||||
Args
|
||||
>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, class A, class B, class C>
|
||||
RET call(A& a, B& b, C& c) const {
|
||||
detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
}
|
||||
};
|
||||
|
||||
// 1 case type:
|
||||
// template<class Args, int Case1>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<
|
||||
// 2,
|
||||
// return_void_action<switch_action<detail::case_label<Case1> > >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// case Case1:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// switch with default being the sole label - doesn't make much sense but
|
||||
// it is there for completeness
|
||||
// template<class Args>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<
|
||||
// 2,
|
||||
// return_void_action<switch_action<detail::default_label> >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
//
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// default:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// // 2 case type:
|
||||
// The different specializations are generated with Vesa Karvonen's
|
||||
// preprocessor library.
|
||||
|
||||
// This is just a comment to show what the generated classes look like
|
||||
|
||||
// template<class Args, int Case1, int Case2>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<3,
|
||||
// return_void_action<
|
||||
// switch_action<
|
||||
// detail::case_label<Case1>,
|
||||
// detail::case_label<Case2>
|
||||
// >
|
||||
// >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// case Case1:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// case Case2:
|
||||
// detail::select(::boost::tuples::get<2>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// template<class Args, int Case1>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<3,
|
||||
// return_void_action<
|
||||
// switch_action<
|
||||
// detail::case_label<Case1>,
|
||||
// detail::default_label
|
||||
// >
|
||||
// >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// case Case1:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// default:
|
||||
// detail::select(::boost::tuples::get<2>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// -------------------------
|
||||
|
||||
// Some helper preprocessor macros ---------------------------------
|
||||
|
||||
// BOOST_LAMBDA_A_I_LIST(N, X) is a list of form X0, X1, ..., XN
|
||||
// BOOST_LAMBDA_A_I_B_LIST(N, X, Y) is a list of form X0 Y, X1 Y, ..., XN Y
|
||||
// BOOST_LAMBDA_A_I_B_LIST(N, X, Y) is a list of form X0 Y0, X1 Y1, ..., XN YN
|
||||
|
||||
#define BOOST_LAMBDA_A_I(i, A) \
|
||||
BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(A,i)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_B(i, T) \
|
||||
BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2,0,T),i) BOOST_PP_TUPLE_ELEM(2,1,T)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_B_I(i, A, B) \
|
||||
BOOST_PP_COMMA_IF(i) \
|
||||
BOOST_PP_CAT(A,i) \
|
||||
BOOST_PP_CAT(B,i)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_LIST(i, A) \
|
||||
BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I, A)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_B_LIST(i, A, B) \
|
||||
BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I_B, (A,B))
|
||||
|
||||
//#define BOOST_LAMBDA_A_I_B_I_LIST(i, A, B) \
|
||||
//BOOST_PP_REPEAT(i, BOOST_LAMBDA_A_I_B_I, A)
|
||||
|
||||
// Switch related macros -------------------------------------------
|
||||
#define BOOST_LAMBDA_SWITCH_CASE_BLOCK(N, A) \
|
||||
case Case##N: \
|
||||
detail::select(::boost::tuples::get<BOOST_PP_INC(N)>(args), a, b, c); \
|
||||
break;
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \
|
||||
BOOST_PP_REPEAT(N, BOOST_LAMBDA_SWITCH_CASE_BLOCK, FOO)
|
||||
// 2 case type:
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
|
||||
template<class Args, BOOST_LAMBDA_A_I_LIST(N, int Case)> \
|
||||
class \
|
||||
lambda_functor_base< \
|
||||
action<BOOST_PP_INC(N), \
|
||||
return_void_action< \
|
||||
switch_action< \
|
||||
BOOST_LAMBDA_A_I_B_LIST(N, detail::case_label<Case,>) \
|
||||
> \
|
||||
> \
|
||||
>, \
|
||||
Args \
|
||||
> \
|
||||
{ \
|
||||
public: \
|
||||
Args args; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, class A, class B, class C> \
|
||||
RET call(A& a, B& b, C& c) const { \
|
||||
switch( detail::select(::boost::tuples::get<0>(args), a, b, c) ) \
|
||||
{ \
|
||||
BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N) \
|
||||
template< \
|
||||
class Args BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
|
||||
BOOST_LAMBDA_A_I_LIST(BOOST_PP_DEC(N), int Case) \
|
||||
> \
|
||||
class \
|
||||
lambda_functor_base< \
|
||||
action<BOOST_PP_INC(N), \
|
||||
return_void_action< \
|
||||
switch_action< \
|
||||
BOOST_LAMBDA_A_I_B_LIST(BOOST_PP_DEC(N), \
|
||||
detail::case_label<Case, >) \
|
||||
BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
|
||||
detail::default_label \
|
||||
> \
|
||||
> \
|
||||
>, \
|
||||
Args \
|
||||
> \
|
||||
{ \
|
||||
public: \
|
||||
Args args; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, class A, class B, class C> \
|
||||
RET call(A& a, B& b, C& c) const { \
|
||||
switch( detail::select(::boost::tuples::get<0>(args), a, b, c) ) \
|
||||
{ \
|
||||
BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(BOOST_PP_DEC(N)) \
|
||||
default: \
|
||||
detail::select(::boost::tuples::get<N>(args), a, b, c); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// switch_statement bind functions -------------------------------------
|
||||
|
||||
// The zero argument case, for completeness sake
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<0, return_void_action<do_nothing_action> >,
|
||||
null_type,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
switch_statement() {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<0, return_void_action<do_nothing_action> >,
|
||||
null_type,
|
||||
NONE
|
||||
>
|
||||
>
|
||||
( null_type());
|
||||
}
|
||||
|
||||
// 1 argument case, this is useless as well, just the condition part
|
||||
template <class TestArg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<switch_action<> > >,
|
||||
tuple<lambda_functor<TestArg> >,
|
||||
dig_arity<TestArg>::value
|
||||
>
|
||||
>
|
||||
switch_statement(const lambda_functor<TestArg>& a1) {
|
||||
return
|
||||
lambda_functor<
|
||||
lambda_functor_args<
|
||||
action<1, return_void_action<switch_action<> > >,
|
||||
tuple< lambda_functor<TestArg> >,
|
||||
dig_arity<TestArg >::value
|
||||
>
|
||||
>
|
||||
( tuple<lambda_functor<TestArg> >(a1));
|
||||
}
|
||||
|
||||
|
||||
#define HELPER(N, FOO) \
|
||||
BOOST_PP_COMMA_IF(N) \
|
||||
BOOST_PP_CAT( \
|
||||
const tagged_lambda_functor<detail::switch_case_tag<TagData, \
|
||||
N>) \
|
||||
BOOST_PP_COMMA() Arg##N>& a##N
|
||||
|
||||
#define HELPER_LIST(N) BOOST_PP_REPEAT(N, HELPER, FOO)
|
||||
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_STATEMENT(N) \
|
||||
template <class TestArg, \
|
||||
BOOST_LAMBDA_A_I_LIST(N, class TagData), \
|
||||
BOOST_LAMBDA_A_I_LIST(N, class Arg)> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_args< \
|
||||
action<BOOST_PP_INC(N), \
|
||||
return_void_action< \
|
||||
switch_action< \
|
||||
BOOST_LAMBDA_A_I_LIST(N, TagData) \
|
||||
> \
|
||||
> \
|
||||
>, \
|
||||
tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)>, \
|
||||
combine_arities< TestArg, BOOST_LAMBDA_A_I_LIST(N, Arg)>::value \
|
||||
> \
|
||||
> \
|
||||
switch_statement( \
|
||||
const lambda_functor<TestArg>& ta, \
|
||||
HELPER_LIST(N) \
|
||||
) \
|
||||
{ \
|
||||
return \
|
||||
lambda_functor< \
|
||||
lambda_functor_args< \
|
||||
action<BOOST_PP_INC(N), \
|
||||
return_void_action< \
|
||||
switch_action< \
|
||||
BOOST_LAMBDA_A_I_LIST(N, TagData) \
|
||||
> \
|
||||
> \
|
||||
>, \
|
||||
tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)>, \
|
||||
combine_arities< TestArg, BOOST_LAMBDA_A_I_LIST(N, Arg)>::value \
|
||||
> \
|
||||
> \
|
||||
( tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
|
||||
(ta, BOOST_LAMBDA_A_I_LIST(N, a) )); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Here's the actual generation
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH(N) \
|
||||
BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
|
||||
BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N)
|
||||
|
||||
// Use this to avoid case 0, these macros work only from case 1 upwards
|
||||
#define BOOST_LAMBDA_SWITCH_HELPER(N, A) \
|
||||
BOOST_LAMBDA_SWITCH( BOOST_PP_INC(N) )
|
||||
|
||||
// Use this to avoid cases 0 and 1, these macros work only from case 2 upwards
|
||||
#define BOOST_LAMBDA_SWITCH_STATEMENT_HELPER(N, A) \
|
||||
BOOST_LAMBDA_SWITCH_STATEMENT(BOOST_PP_INC(N))
|
||||
|
||||
|
||||
|
||||
// up to 9 cases supported (counting default:)
|
||||
BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_HELPER,FOO)
|
||||
BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_STATEMENT_HELPER,FOO)
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#undef HELPER
|
||||
#undef HELPER_LIST
|
||||
|
||||
#undef BOOST_LAMBDA_SWITCH_HELPER
|
||||
#undef BOOST_LAMBDA_SWITCH
|
||||
#undef BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE
|
||||
#undef BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE
|
||||
|
||||
#undef BOOST_LAMBDA_SWITCH_CASE_BLOCK
|
||||
#undef BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST
|
||||
|
||||
#undef BOOST_LAMBDA_SWITCH_STATEMENT
|
||||
#undef BOOST_LAMBDA_SWITCH_STATEMENT_HELPER
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
494
include/boost/lambda/if.hpp
Normal file
494
include/boost/lambda/if.hpp
Normal file
@@ -0,0 +1,494 @@
|
||||
// Boost Lambda Library -- if.hpp ------------------------------------------
|
||||
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
// Copyright (C) 2000 Gary Powell (gary.powell@sierra.com)
|
||||
// Copyright (C) 2001-2002 Joel de Guzman
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(BOOST_LAMBDA_IF_HPP)
|
||||
#define BOOST_LAMBDA_IF_HPP
|
||||
|
||||
#include "boost/lambda/core.hpp"
|
||||
|
||||
// Arithmetic type promotion needed for if_then_else_return
|
||||
#include "boost/lambda/detail/operator_actions.hpp"
|
||||
#include "boost/lambda/detail/operator_return_type_traits.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
// -- if control construct actions ----------------------
|
||||
|
||||
class ifthen_action {};
|
||||
class ifthenelse_action {};
|
||||
class ifthenelsereturn_action {};
|
||||
|
||||
// Specialization for if_then.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<ifthen_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// If Then
|
||||
template <class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
ifthen_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
ifthen_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
|
||||
}
|
||||
|
||||
|
||||
// Specialization for if_then_else.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<ifthenelse_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
if (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
else
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// If then else
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
ifthenelse_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
>
|
||||
>
|
||||
if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
const lambda_functor<Arg3>& a3) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
ifthenelse_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
>
|
||||
(tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
(a1, a2, a3) );
|
||||
}
|
||||
|
||||
// Our version of operator?:()
|
||||
|
||||
template <class Arg1, class Arg2, class Arg3>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
other_action<ifthenelsereturn_action>,
|
||||
tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type,
|
||||
typename const_copy_argument<Arg3>::type>
|
||||
>
|
||||
>
|
||||
if_then_else_return(const lambda_functor<Arg1>& a1,
|
||||
const Arg2 & a2,
|
||||
const Arg3 & a3) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
other_action<ifthenelsereturn_action>,
|
||||
tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type,
|
||||
typename const_copy_argument<Arg3>::type>
|
||||
> ( tuple<lambda_functor<Arg1>,
|
||||
typename const_copy_argument<Arg2>::type,
|
||||
typename const_copy_argument<Arg3>::type> (a1, a2, a3) );
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// return type specialization for conditional expression begins -----------
|
||||
// start reading below and move upwards
|
||||
|
||||
// PHASE 6:1
|
||||
// check if A is conbertible to B and B to A
|
||||
template<int Phase, bool AtoB, bool BtoA, bool SameType, class A, class B>
|
||||
struct return_type_2_ifthenelsereturn;
|
||||
|
||||
// if A can be converted to B and vice versa -> ambiguous
|
||||
template<int Phase, class A, class B>
|
||||
struct return_type_2_ifthenelsereturn<Phase, true, true, false, A, B> {
|
||||
typedef
|
||||
detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
|
||||
// ambiguous type in conditional expression
|
||||
};
|
||||
// if A can be converted to B and vice versa and are of same type
|
||||
template<int Phase, class A, class B>
|
||||
struct return_type_2_ifthenelsereturn<Phase, true, true, true, A, B> {
|
||||
typedef A type;
|
||||
};
|
||||
|
||||
|
||||
// A can be converted to B
|
||||
template<int Phase, class A, class B>
|
||||
struct return_type_2_ifthenelsereturn<Phase, true, false, false, A, B> {
|
||||
typedef B type;
|
||||
};
|
||||
|
||||
// B can be converted to A
|
||||
template<int Phase, class A, class B>
|
||||
struct return_type_2_ifthenelsereturn<Phase, false, true, false, A, B> {
|
||||
typedef A type;
|
||||
};
|
||||
|
||||
// neither can be converted. Then we drop the potential references, and
|
||||
// try again
|
||||
template<class A, class B>
|
||||
struct return_type_2_ifthenelsereturn<1, false, false, false, A, B> {
|
||||
// it is safe to add const, since the result will be an rvalue and thus
|
||||
// const anyway. The const are needed eg. if the types
|
||||
// are 'const int*' and 'void *'. The remaining type should be 'const void*'
|
||||
typedef const typename boost::remove_reference<A>::type plainA;
|
||||
typedef const typename boost::remove_reference<B>::type plainB;
|
||||
// TODO: Add support for volatile ?
|
||||
|
||||
typedef typename
|
||||
return_type_2_ifthenelsereturn<
|
||||
2,
|
||||
boost::is_convertible<plainA,plainB>::value,
|
||||
boost::is_convertible<plainB,plainA>::value,
|
||||
boost::is_same<plainA,plainB>::value,
|
||||
plainA,
|
||||
plainB>::type type;
|
||||
};
|
||||
|
||||
// PHASE 6:2
|
||||
template<class A, class B>
|
||||
struct return_type_2_ifthenelsereturn<2, false, false, false, A, B> {
|
||||
typedef
|
||||
detail::return_type_deduction_failure<return_type_2_ifthenelsereturn> type;
|
||||
// types_do_not_match_in_conditional_expression
|
||||
};
|
||||
|
||||
|
||||
|
||||
// PHASE 5: now we know that types are not arithmetic.
|
||||
template<class A, class B>
|
||||
struct non_numeric_types {
|
||||
typedef typename
|
||||
return_type_2_ifthenelsereturn<
|
||||
1, // phase 1
|
||||
is_convertible<A,B>::value,
|
||||
is_convertible<B,A>::value,
|
||||
is_same<A,B>::value,
|
||||
A,
|
||||
B>::type type;
|
||||
};
|
||||
|
||||
// PHASE 4 :
|
||||
// the base case covers arithmetic types with differing promote codes
|
||||
// use the type deduction of arithmetic_actions
|
||||
template<int CodeA, int CodeB, class A, class B>
|
||||
struct arithmetic_or_not {
|
||||
typedef typename
|
||||
return_type_2<arithmetic_action<plus_action>, A, B>::type type;
|
||||
// plus_action is just a random pick, has to be a concrete instance
|
||||
};
|
||||
|
||||
// this case covers the case of artihmetic types with the same promote codes.
|
||||
// non numeric deduction is used since e.g. integral promotion is not
|
||||
// performed with operator ?:
|
||||
template<int CodeA, class A, class B>
|
||||
struct arithmetic_or_not<CodeA, CodeA, A, B> {
|
||||
typedef typename non_numeric_types<A, B>::type type;
|
||||
};
|
||||
|
||||
// if either A or B has promote code -1 it is not an arithmetic type
|
||||
template<class A, class B>
|
||||
struct arithmetic_or_not <-1, -1, A, B> {
|
||||
typedef typename non_numeric_types<A, B>::type type;
|
||||
};
|
||||
template<int CodeB, class A, class B>
|
||||
struct arithmetic_or_not <-1, CodeB, A, B> {
|
||||
typedef typename non_numeric_types<A, B>::type type;
|
||||
};
|
||||
template<int CodeA, class A, class B>
|
||||
struct arithmetic_or_not <CodeA, -1, A, B> {
|
||||
typedef typename non_numeric_types<A, B>::type type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// PHASE 3 : Are the types same?
|
||||
// No, check if they are arithmetic or not
|
||||
template <class A, class B>
|
||||
struct same_or_not {
|
||||
typedef typename detail::remove_reference_and_cv<A>::type plainA;
|
||||
typedef typename detail::remove_reference_and_cv<B>::type plainB;
|
||||
|
||||
typedef typename
|
||||
arithmetic_or_not<
|
||||
detail::promote_code<plainA>::value,
|
||||
detail::promote_code<plainB>::value,
|
||||
A,
|
||||
B>::type type;
|
||||
};
|
||||
// Yes, clear.
|
||||
template <class A> struct same_or_not<A, A> {
|
||||
typedef A type;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
// PHASE 2 : Perform first the potential array_to_pointer conversion
|
||||
template<class A, class B>
|
||||
struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
|
||||
|
||||
typedef typename detail::array_to_pointer<A>::type A1;
|
||||
typedef typename detail::array_to_pointer<B>::type B1;
|
||||
|
||||
typedef typename
|
||||
boost::add_const<typename detail::same_or_not<A1, B1>::type>::type type;
|
||||
};
|
||||
|
||||
// PHASE 1 : Deduction is based on the second and third operand
|
||||
|
||||
|
||||
// return type specialization for conditional expression ends -----------
|
||||
|
||||
|
||||
// Specialization of lambda_functor_base for if_then_else_return.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
|
||||
public:
|
||||
Args args;
|
||||
|
||||
template <class SigArgs> struct sig {
|
||||
private:
|
||||
typedef typename detail::nth_return_type_sig<1, Args, SigArgs>::type ret1;
|
||||
typedef typename detail::nth_return_type_sig<2, Args, SigArgs>::type ret2;
|
||||
public:
|
||||
typedef typename return_type_2<
|
||||
other_action<ifthenelsereturn_action>, ret1, ret2
|
||||
>::type type;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
return (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) ?
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS)
|
||||
:
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// The code below is from Joel de Guzman, some name changes etc.
|
||||
// has been made.
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
Copyright (c) 2001-2002 Joel de Guzman
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the copyright holder be held liable for
|
||||
any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute
|
||||
it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
URL: http://spirit.sourceforge.net/
|
||||
|
||||
==============================================================================*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// if_then_else_composite
|
||||
//
|
||||
// This composite has two (2) forms:
|
||||
//
|
||||
// if_(condition)
|
||||
// [
|
||||
// statement
|
||||
// ]
|
||||
//
|
||||
// and
|
||||
//
|
||||
// if_(condition)
|
||||
// [
|
||||
// true_statement
|
||||
// ]
|
||||
// .else_
|
||||
// [
|
||||
// false_statement
|
||||
// ]
|
||||
//
|
||||
// where condition is an lambda_functor that evaluates to bool. If condition
|
||||
// is true, the true_statement (again an lambda_functor) is executed
|
||||
// otherwise, the false_statement (another lambda_functor) is executed. The
|
||||
// result type of this is void. Note the trailing underscore after
|
||||
// if_ and the the leading dot and the trailing underscore before
|
||||
// and after .else_.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename CondT, typename ThenT, typename ElseT>
|
||||
struct if_then_else_composite {
|
||||
|
||||
typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;
|
||||
|
||||
template <class SigArgs>
|
||||
struct sig { typedef void type; };
|
||||
|
||||
if_then_else_composite(
|
||||
CondT const& cond_,
|
||||
ThenT const& then_,
|
||||
ElseT const& else__)
|
||||
: cond(cond_), then(then_), else_(else__) {}
|
||||
|
||||
template <class Ret, CALL_TEMPLATE_ARGS>
|
||||
Ret call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
if (cond.internal_call(CALL_ACTUAL_ARGS))
|
||||
then.internal_call(CALL_ACTUAL_ARGS);
|
||||
else
|
||||
else_.internal_call(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
CondT cond; ThenT then; ElseT else_; // lambda_functors
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT, typename ThenT>
|
||||
struct else_gen {
|
||||
|
||||
else_gen(CondT const& cond_, ThenT const& then_)
|
||||
: cond(cond_), then(then_) {}
|
||||
|
||||
template <typename ElseT>
|
||||
lambda_functor<if_then_else_composite<CondT, ThenT,
|
||||
typename as_lambda_functor<ElseT>::type> >
|
||||
operator[](ElseT const& else_)
|
||||
{
|
||||
typedef if_then_else_composite<CondT, ThenT,
|
||||
typename as_lambda_functor<ElseT>::type>
|
||||
result;
|
||||
|
||||
return result(cond, then, to_lambda_functor(else_));
|
||||
}
|
||||
|
||||
CondT cond; ThenT then;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT, typename ThenT>
|
||||
struct if_then_composite {
|
||||
|
||||
template <class SigArgs>
|
||||
struct sig { typedef void type; };
|
||||
|
||||
if_then_composite(CondT const& cond_, ThenT const& then_)
|
||||
: cond(cond_), then(then_), else_(cond, then) {}
|
||||
|
||||
template <class Ret, CALL_TEMPLATE_ARGS>
|
||||
Ret call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
if (cond.internal_call(CALL_ACTUAL_ARGS))
|
||||
then.internal_call(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
CondT cond; ThenT then; // lambda_functors
|
||||
else_gen<CondT, ThenT> else_;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT>
|
||||
struct if_gen {
|
||||
|
||||
if_gen(CondT const& cond_)
|
||||
: cond(cond_) {}
|
||||
|
||||
template <typename ThenT>
|
||||
lambda_functor<if_then_composite<
|
||||
typename as_lambda_functor<CondT>::type,
|
||||
typename as_lambda_functor<ThenT>::type> >
|
||||
operator[](ThenT const& then) const
|
||||
{
|
||||
typedef if_then_composite<
|
||||
typename as_lambda_functor<CondT>::type,
|
||||
typename as_lambda_functor<ThenT>::type>
|
||||
result;
|
||||
|
||||
return result(
|
||||
to_lambda_functor(cond),
|
||||
to_lambda_functor(then));
|
||||
}
|
||||
|
||||
CondT cond;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT>
|
||||
inline if_gen<CondT>
|
||||
if_(CondT const& cond)
|
||||
{
|
||||
return if_gen<CondT>(cond);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // lambda
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_LAMBDA_IF_HPP
|
||||
|
||||
|
||||
@@ -18,15 +18,22 @@
|
||||
|
||||
#include "boost/lambda/core.hpp"
|
||||
|
||||
#include "boost/lambda/detail/operator_actions.hpp"
|
||||
#include "boost/lambda/detail/operator_lambda_functor_base.hpp"
|
||||
#include "boost/lambda/detail/operator_return_type_traits.hpp"
|
||||
|
||||
#ifdef BOOST_NO_FORWARD_DECLARADED_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMETERS
|
||||
#ifdef BOOST_NO_FDECL_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMS
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#endif
|
||||
|
||||
#include "boost/lambda/detail/operator_actions.hpp"
|
||||
#include "boost/lambda/detail/operator_lambda_func_base.hpp"
|
||||
#include "boost/lambda/detail/operator_return_type_traits.hpp"
|
||||
|
||||
|
||||
#include "boost/lambda/detail/operators.hpp"
|
||||
|
||||
#ifndef BOOST_LAMBDA_FAILS_IN_TEMPLATE_KEYWORD_AFTER_SCOPE_OPER
|
||||
// sorry, member ptr does not work with gcc2.95
|
||||
#include "boost/lambda/detail/member_ptr.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
538
include/boost/lambda/loops.hpp
Normal file
538
include/boost/lambda/loops.hpp
Normal file
@@ -0,0 +1,538 @@
|
||||
// Boost Lambda Library -- loops.hpp ----------------------------------------
|
||||
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
// Copyright (C) 2000 Gary Powell (gary.powell@sierra.com)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(BOOST_LAMBDA_LOOPS_HPP)
|
||||
#define BOOST_LAMBDA_LOOPS_HPP
|
||||
|
||||
#include "boost/lambda/core.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
// -- loop control structure actions ----------------------
|
||||
|
||||
class forloop_action {};
|
||||
class forloop_no_body_action {};
|
||||
class whileloop_action {};
|
||||
class whileloop_no_body_action {};
|
||||
class dowhileloop_action {};
|
||||
class dowhileloop_no_body_action {};
|
||||
|
||||
|
||||
// For loop
|
||||
template <class Arg1, class Arg2, class Arg3, class Arg4>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
forloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >
|
||||
>
|
||||
>
|
||||
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
const lambda_functor<Arg3>& a3, const lambda_functor<Arg4>& a4) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
forloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3>, lambda_functor<Arg4> >(a1, a2, a3, a4)
|
||||
);
|
||||
}
|
||||
|
||||
// No body case.
|
||||
template <class Arg1, class Arg2, class Arg3>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
forloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
|
||||
>
|
||||
>
|
||||
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
|
||||
const lambda_functor<Arg3>& a3) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
forloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
|
||||
lambda_functor<Arg3> >(a1, a2, a3) );
|
||||
}
|
||||
|
||||
// While loop
|
||||
template <class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
whileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
whileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
}
|
||||
|
||||
// No body case.
|
||||
template <class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
whileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
while_loop(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
whileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1> >(a1) );
|
||||
}
|
||||
|
||||
|
||||
// Do While loop
|
||||
template <class Arg1, class Arg2>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
dowhileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
>
|
||||
do_while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
dowhileloop_action,
|
||||
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
|
||||
}
|
||||
|
||||
// No body case.
|
||||
template <class Arg1>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
dowhileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
>
|
||||
do_while_loop(const lambda_functor<Arg1>& a1) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
dowhileloop_no_body_action,
|
||||
tuple<lambda_functor<Arg1> >
|
||||
>
|
||||
( tuple<lambda_functor<Arg1> >(a1));
|
||||
}
|
||||
|
||||
|
||||
// Control loop lambda_functor_base specializations.
|
||||
|
||||
// Specialization for for_loop.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<forloop_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
for(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS))
|
||||
|
||||
detail::select(boost::tuples::get<3>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// No body case
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<forloop_no_body_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
for(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS)) {}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Specialization for while_loop.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<whileloop_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
while(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS))
|
||||
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// No body case
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<whileloop_no_body_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
while(detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS)) {}
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for do_while_loop.
|
||||
// Note that the first argument is the condition.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<dowhileloop_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
do {
|
||||
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
|
||||
}
|
||||
};
|
||||
|
||||
// No body case
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<dowhileloop_no_body_action, Args> {
|
||||
public:
|
||||
Args args;
|
||||
template <class T> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
do {} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
|
||||
}
|
||||
};
|
||||
|
||||
// The code below is from Joel de Guzman, some name changes etc.
|
||||
// has been made.
|
||||
|
||||
/*=============================================================================
|
||||
Statements
|
||||
|
||||
Phoenix V0.9
|
||||
Copyright (c) 2001-2002 Joel de Guzman
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the copyright holder be held liable for
|
||||
any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute
|
||||
it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
URL: http://spirit.sourceforge.net/
|
||||
|
||||
==============================================================================*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// while_composite
|
||||
//
|
||||
// This composite has the form:
|
||||
//
|
||||
// while_(condition)
|
||||
// [
|
||||
// statement
|
||||
// ]
|
||||
//
|
||||
// While the condition (an lambda_functor) evaluates to true, statement
|
||||
// (another lambda_functor) is executed. The result type of this is void.
|
||||
// Note the trailing underscore after while_.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename CondT, typename DoT>
|
||||
struct while_composite {
|
||||
|
||||
typedef while_composite<CondT, DoT> self_t;
|
||||
|
||||
template <class SigArgs>
|
||||
struct sig { typedef void type; };
|
||||
|
||||
while_composite(CondT const& cond_, DoT const& do__)
|
||||
: cond(cond_), do_(do__) {}
|
||||
|
||||
template <class Ret, CALL_TEMPLATE_ARGS>
|
||||
Ret call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
while (cond.internal_call(CALL_ACTUAL_ARGS))
|
||||
do_.internal_call(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
CondT cond;
|
||||
DoT do_;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT>
|
||||
struct while_gen {
|
||||
|
||||
while_gen(CondT const& cond_)
|
||||
: cond(cond_) {}
|
||||
|
||||
template <typename DoT>
|
||||
lambda_functor<while_composite<
|
||||
typename as_lambda_functor<CondT>::type,
|
||||
typename as_lambda_functor<DoT>::type> >
|
||||
operator[](DoT const& do_) const
|
||||
{
|
||||
typedef while_composite<
|
||||
typename as_lambda_functor<CondT>::type,
|
||||
typename as_lambda_functor<DoT>::type>
|
||||
result;
|
||||
|
||||
return result(
|
||||
to_lambda_functor(cond),
|
||||
to_lambda_functor(do_));
|
||||
}
|
||||
|
||||
CondT cond;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename CondT>
|
||||
inline while_gen<CondT>
|
||||
while_(CondT const& cond)
|
||||
{
|
||||
return while_gen<CondT>(cond);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// do_composite
|
||||
//
|
||||
// This composite has the form:
|
||||
//
|
||||
// do_
|
||||
// [
|
||||
// statement
|
||||
// ]
|
||||
// .while_(condition)
|
||||
//
|
||||
// While the condition (an lambda_functor) evaluates to true, statement
|
||||
// (another lambda_functor) is executed. The statement is executed at least
|
||||
// once. The result type of this is void. Note the trailing
|
||||
// underscore after do_ and the the leading dot and the trailing
|
||||
// underscore before and after .while_.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename DoT, typename CondT>
|
||||
struct do_composite {
|
||||
|
||||
typedef do_composite<DoT, CondT> self_t;
|
||||
|
||||
template <class SigArgs>
|
||||
struct sig { typedef void type; };
|
||||
|
||||
do_composite(DoT const& do__, CondT const& cond_)
|
||||
: do_(do__), cond(cond_) {}
|
||||
|
||||
template <class Ret, CALL_TEMPLATE_ARGS>
|
||||
Ret call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
do
|
||||
do_.internal_call(CALL_ACTUAL_ARGS);
|
||||
while (cond.internal_call(CALL_ACTUAL_ARGS));
|
||||
}
|
||||
|
||||
DoT do_;
|
||||
CondT cond;
|
||||
};
|
||||
|
||||
////////////////////////////////////
|
||||
template <typename DoT>
|
||||
struct do_gen2 {
|
||||
|
||||
do_gen2(DoT const& do__)
|
||||
: do_(do__) {}
|
||||
|
||||
template <typename CondT>
|
||||
lambda_functor<do_composite<
|
||||
typename as_lambda_functor<DoT>::type,
|
||||
typename as_lambda_functor<CondT>::type> >
|
||||
while_(CondT const& cond) const
|
||||
{
|
||||
typedef do_composite<
|
||||
typename as_lambda_functor<DoT>::type,
|
||||
typename as_lambda_functor<CondT>::type>
|
||||
result;
|
||||
|
||||
return result(
|
||||
to_lambda_functor(do_),
|
||||
to_lambda_functor(cond));
|
||||
}
|
||||
|
||||
DoT do_;
|
||||
};
|
||||
|
||||
////////////////////////////////////
|
||||
struct do_gen {
|
||||
|
||||
template <typename DoT>
|
||||
do_gen2<DoT>
|
||||
operator[](DoT const& do_) const
|
||||
{
|
||||
return do_gen2<DoT>(do_);
|
||||
}
|
||||
};
|
||||
|
||||
do_gen const do_ = do_gen();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// for_composite
|
||||
//
|
||||
// This statement has the form:
|
||||
//
|
||||
// for_(init, condition, step)
|
||||
// [
|
||||
// statement
|
||||
// ]
|
||||
//
|
||||
// Where init, condition, step and statement are all lambda_functors. init
|
||||
// is executed once before entering the for-loop. The for-loop
|
||||
// exits once condition evaluates to false. At each loop iteration,
|
||||
// step and statement is called. The result of this statement is
|
||||
// void. Note the trailing underscore after for_.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename InitT, typename CondT, typename StepT, typename DoT>
|
||||
struct for_composite {
|
||||
|
||||
template <class SigArgs>
|
||||
struct sig { typedef void type; };
|
||||
|
||||
for_composite(
|
||||
InitT const& init_,
|
||||
CondT const& cond_,
|
||||
StepT const& step_,
|
||||
DoT const& do__)
|
||||
: init(init_), cond(cond_), step(step_), do_(do__) {}
|
||||
|
||||
template <class Ret, CALL_TEMPLATE_ARGS>
|
||||
Ret
|
||||
call(CALL_FORMAL_ARGS) const
|
||||
{
|
||||
for (init.internal_call(CALL_ACTUAL_ARGS); cond.internal_call(CALL_ACTUAL_ARGS); step.internal_call(CALL_ACTUAL_ARGS))
|
||||
do_.internal_call(CALL_ACTUAL_ARGS);
|
||||
}
|
||||
|
||||
InitT init; CondT cond; StepT step; DoT do_; // lambda_functors
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename InitT, typename CondT, typename StepT>
|
||||
struct for_gen {
|
||||
|
||||
for_gen(
|
||||
InitT const& init_,
|
||||
CondT const& cond_,
|
||||
StepT const& step_)
|
||||
: init(init_), cond(cond_), step(step_) {}
|
||||
|
||||
template <typename DoT>
|
||||
lambda_functor<for_composite<
|
||||
typename as_lambda_functor<InitT>::type,
|
||||
typename as_lambda_functor<CondT>::type,
|
||||
typename as_lambda_functor<StepT>::type,
|
||||
typename as_lambda_functor<DoT>::type> >
|
||||
operator[](DoT const& do_) const
|
||||
{
|
||||
typedef for_composite<
|
||||
typename as_lambda_functor<InitT>::type,
|
||||
typename as_lambda_functor<CondT>::type,
|
||||
typename as_lambda_functor<StepT>::type,
|
||||
typename as_lambda_functor<DoT>::type>
|
||||
result;
|
||||
|
||||
return result(
|
||||
to_lambda_functor(init),
|
||||
to_lambda_functor(cond),
|
||||
to_lambda_functor(step),
|
||||
to_lambda_functor(do_));
|
||||
}
|
||||
|
||||
InitT init; CondT cond; StepT step;
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
template <typename InitT, typename CondT, typename StepT>
|
||||
inline for_gen<InitT, CondT, StepT>
|
||||
for_(InitT const& init, CondT const& cond, StepT const& step)
|
||||
{
|
||||
return for_gen<InitT, CondT, StepT>(init, cond, step);
|
||||
}
|
||||
|
||||
} // lambda
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_LAMBDA_LOOPS_HPP
|
||||
124
include/boost/lambda/numeric.hpp
Normal file
124
include/boost/lambda/numeric.hpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// -- numeric.hpp -- Boost Lambda Library -----------------------------------
|
||||
// Copyright (C) 2002 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
// Copyright (C) 2002 Gary Powell (gwpowell@hotmail.com)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see http://www.boost.org
|
||||
|
||||
#ifndef BOOST_LAMBDA_NUMERIC_HPP
|
||||
#define BOOST_LAMBDA_NUMERIC_HPP
|
||||
|
||||
#include "boost/lambda/core.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
namespace ll {
|
||||
|
||||
// accumulate ---------------------------------
|
||||
|
||||
struct accumulate {
|
||||
|
||||
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()(A a, B b, C c) const
|
||||
{ return ::std::accumulate(a, b, c); }
|
||||
|
||||
template <class A, class B, class C, class D>
|
||||
C
|
||||
operator()(A a, B b, C c, D d) const
|
||||
{ return ::std::accumulate(a, b, c, d); }
|
||||
};
|
||||
|
||||
// inner_product ---------------------------------
|
||||
|
||||
struct inner_product {
|
||||
|
||||
template <class Args>
|
||||
struct sig {
|
||||
typedef typename boost::remove_const<
|
||||
typename boost::tuples::element<4, Args>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class A, class B, class C, class D>
|
||||
D
|
||||
operator()(A a, B b, C c, D d) const
|
||||
{ return ::std::inner_product(a, b, c, d); }
|
||||
|
||||
template <class A, class B, class C, class D, class E, class F>
|
||||
D
|
||||
operator()(A a, B b, C c, D d, E e, F f) const
|
||||
{ return ::std::inner_product(a, b, c, d, e, f); }
|
||||
};
|
||||
|
||||
|
||||
// partial_sum ---------------------------------
|
||||
|
||||
struct partial_sum {
|
||||
|
||||
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()(A a, B b, C c) const
|
||||
{ return ::std::partial_sum(a, b, c); }
|
||||
|
||||
template <class A, class B, class C, class D>
|
||||
C
|
||||
operator()(A a, B b, C c, D d) const
|
||||
{ return ::std::partial_sum(a, b, c, d); }
|
||||
};
|
||||
|
||||
// adjacent_difference ---------------------------------
|
||||
|
||||
struct adjacent_difference {
|
||||
|
||||
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()(A a, B b, C c) const
|
||||
{ return ::std::adjacent_difference(a, b, c); }
|
||||
|
||||
template <class A, class B, class C, class D>
|
||||
C
|
||||
operator()(A a, B b, C c, D d) const
|
||||
{ return ::std::adjacent_difference(a, b, c, d); }
|
||||
};
|
||||
|
||||
} // end of ll namespace
|
||||
|
||||
} // end of lambda namespace
|
||||
} // end of boost namespace
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
507
include/boost/lambda/switch.hpp
Normal file
507
include/boost/lambda/switch.hpp
Normal file
@@ -0,0 +1,507 @@
|
||||
// Boost Lambda Library -- switch.hpp -----------------------------------
|
||||
//
|
||||
// Copyright (C) 2000 Gary Powell (gary.powell@sierra.com)
|
||||
// Copyright (C) 1999, 2000 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
|
||||
//
|
||||
// Permission to copy, use, sell and distribute this software is granted
|
||||
// provided this copyright notice appears in all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted
|
||||
// provided this copyright notice appears in all copies, and a notice
|
||||
// that the code was modified is included with the copyright notice.
|
||||
//
|
||||
// This software is provided "as is" without express or implied warranty,
|
||||
// and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// For more information, see www.boost.org
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if !defined(BOOST_LAMBDA_SWITCH_HPP)
|
||||
#define BOOST_LAMBDA_SWITCH_HPP
|
||||
|
||||
#include "boost/lambda/core.hpp"
|
||||
#include "boost/lambda/detail/control_constructs_common.hpp"
|
||||
|
||||
#include "boost/preprocessor/enum_shifted_params.hpp"
|
||||
#include "boost/preprocessor/repeat_2nd.hpp"
|
||||
#include "boost/preprocessor/tuple.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
// Switch actions
|
||||
template <int N, class Switch1 = null_type, class Switch2 = null_type,
|
||||
class Switch3 = null_type, class Switch4 = null_type,
|
||||
class Switch5 = null_type, class Switch6 = null_type,
|
||||
class Switch7 = null_type, class Switch8 = null_type,
|
||||
class Switch9 = null_type>
|
||||
struct switch_action {};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
// templates to represent special lambda functors for the cases in
|
||||
// switch statements
|
||||
|
||||
template <int Value> struct case_label {};
|
||||
struct default_label {};
|
||||
|
||||
template<class Type> struct switch_case_tag {};
|
||||
|
||||
// a normal case is represented as:
|
||||
// tagged_lambda_functor<switch_case_tag<case_label<N> > >, LambdaFunctor>
|
||||
|
||||
// the default case as:
|
||||
// tagged_lambda_functor<switch_case_tag<default_label> >, LambdaFunctor>
|
||||
|
||||
|
||||
} // end detail
|
||||
|
||||
|
||||
/// create switch_case_tag tagged_lambda_functors
|
||||
template <int CaseValue, class Arg>
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<Arg>
|
||||
>
|
||||
case_statement(const lambda_functor<Arg>& a) {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<Arg>
|
||||
>(a);
|
||||
}
|
||||
|
||||
// No case body case.
|
||||
template <int CaseValue>
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
do_nothing_action,
|
||||
null_type
|
||||
>
|
||||
>
|
||||
>
|
||||
case_statement() {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::case_label<CaseValue> >,
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
do_nothing_action,
|
||||
null_type
|
||||
>
|
||||
>
|
||||
> () ;
|
||||
}
|
||||
|
||||
// default label
|
||||
template <class Arg>
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<Arg>
|
||||
>
|
||||
default_statement(const lambda_functor<Arg>& a) {
|
||||
return
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<Arg>
|
||||
>(a);
|
||||
}
|
||||
|
||||
// default lable, no case body case.
|
||||
inline const
|
||||
tagged_lambda_functor<
|
||||
detail::switch_case_tag<detail::default_label>,
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
do_nothing_action,
|
||||
null_type
|
||||
>
|
||||
>
|
||||
>
|
||||
default_statement() {
|
||||
return
|
||||
lambda_functor_base<
|
||||
do_nothing_action,
|
||||
null_type
|
||||
> () ;
|
||||
}
|
||||
|
||||
|
||||
// Specializations for lambda_functor_base of case_statement -----------------
|
||||
|
||||
// 0 case type:
|
||||
// useless (just the condition part) but provided for completeness.
|
||||
template<class Args>
|
||||
class
|
||||
lambda_functor_base<
|
||||
switch_action<1>,
|
||||
Args
|
||||
>
|
||||
{
|
||||
public:
|
||||
Args args;
|
||||
template <class SigArgs> struct sig { typedef void type; };
|
||||
public:
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
template<class RET, CALL_TEMPLATE_ARGS>
|
||||
RET call(CALL_FORMAL_ARGS) const {
|
||||
detail::select(::boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
|
||||
}
|
||||
};
|
||||
|
||||
// 1 case type:
|
||||
// template<class Args, int Case1>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<
|
||||
// 2,
|
||||
// return_void_action<switch_action<detail::case_label<Case1> > >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// case Case1:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// switch with default being the sole label - doesn't make much sense but
|
||||
// it is there for completeness
|
||||
// template<class Args>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<
|
||||
// 2,
|
||||
// return_void_action<switch_action<detail::default_label> >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
//
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// default:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// // 2 case type:
|
||||
// The different specializations are generated with Vesa Karvonen's
|
||||
// preprocessor library.
|
||||
|
||||
// This is just a comment to show what the generated classes look like
|
||||
|
||||
// template<class Args, int Case1, int Case2>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<3,
|
||||
// return_void_action<
|
||||
// switch_action<
|
||||
// detail::case_label<Case1>,
|
||||
// detail::case_label<Case2>
|
||||
// >
|
||||
// >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// case Case1:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// case Case2:
|
||||
// detail::select(::boost::tuples::get<2>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// template<class Args, int Case1>
|
||||
// class
|
||||
// lambda_functor_base<
|
||||
// action<3,
|
||||
// return_void_action<
|
||||
// switch_action<
|
||||
// detail::case_label<Case1>,
|
||||
// detail::default_label
|
||||
// >
|
||||
// >
|
||||
// >,
|
||||
// Args
|
||||
// >
|
||||
// {
|
||||
// Args args;
|
||||
// public:
|
||||
// explicit lambda_functor_base(const Args& a) : args(a) {}
|
||||
|
||||
// template<class RET, class A, class B, class C>
|
||||
// RET call(A& a, B& b, C& c) const {
|
||||
// switch( detail::select(::boost::tuples::get<0>(args), a, b, c) )
|
||||
// {
|
||||
// case Case1:
|
||||
// detail::select(::boost::tuples::get<1>(args), a, b, c);
|
||||
// break;
|
||||
// default:
|
||||
// detail::select(::boost::tuples::get<2>(args), a, b, c);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// -------------------------
|
||||
|
||||
// Some helper preprocessor macros ---------------------------------
|
||||
|
||||
// BOOST_LAMBDA_A_I_LIST(N, X) is a list of form X0, X1, ..., XN
|
||||
// BOOST_LAMBDA_A_I_B_LIST(N, X, Y) is a list of form X0 Y, X1 Y, ..., XN Y
|
||||
|
||||
#define BOOST_LAMBDA_A_I(i, A) \
|
||||
BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(A,i)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_B(i, T) \
|
||||
BOOST_PP_COMMA_IF(i) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2,0,T),i) BOOST_PP_TUPLE_ELEM(2,1,T)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_LIST(i, A) \
|
||||
BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I, A)
|
||||
|
||||
#define BOOST_LAMBDA_A_I_B_LIST(i, A, B) \
|
||||
BOOST_PP_REPEAT(i,BOOST_LAMBDA_A_I_B, (A,B))
|
||||
|
||||
|
||||
// Switch related macros -------------------------------------------
|
||||
#define BOOST_LAMBDA_SWITCH_CASE_BLOCK(N, A) \
|
||||
case Case##N: \
|
||||
detail::select(::boost::tuples::get<BOOST_PP_INC(N)>(args), CALL_ACTUAL_ARGS); \
|
||||
break;
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \
|
||||
BOOST_PP_REPEAT(N, BOOST_LAMBDA_SWITCH_CASE_BLOCK, FOO)
|
||||
// 2 case type:
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
|
||||
template<class Args, BOOST_LAMBDA_A_I_LIST(N, int Case)> \
|
||||
class \
|
||||
lambda_functor_base< \
|
||||
switch_action<BOOST_PP_INC(N), \
|
||||
BOOST_LAMBDA_A_I_B_LIST(N, detail::case_label<Case,>) \
|
||||
>, \
|
||||
Args \
|
||||
> \
|
||||
{ \
|
||||
public: \
|
||||
Args args; \
|
||||
template <class SigArgs> struct sig { typedef void type; }; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, CALL_TEMPLATE_ARGS> \
|
||||
RET call(CALL_FORMAL_ARGS) const { \
|
||||
switch( detail::select(::boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \
|
||||
{ \
|
||||
BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(N) \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N) \
|
||||
template< \
|
||||
class Args BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
|
||||
BOOST_LAMBDA_A_I_LIST(BOOST_PP_DEC(N), int Case) \
|
||||
> \
|
||||
class \
|
||||
lambda_functor_base< \
|
||||
switch_action<BOOST_PP_INC(N), \
|
||||
BOOST_LAMBDA_A_I_B_LIST(BOOST_PP_DEC(N), \
|
||||
detail::case_label<Case, >) \
|
||||
BOOST_PP_COMMA_IF(BOOST_PP_DEC(N)) \
|
||||
detail::default_label \
|
||||
>, \
|
||||
Args \
|
||||
> \
|
||||
{ \
|
||||
public: \
|
||||
Args args; \
|
||||
template <class SigArgs> struct sig { typedef void type; }; \
|
||||
public: \
|
||||
explicit lambda_functor_base(const Args& a) : args(a) {} \
|
||||
\
|
||||
template<class RET, CALL_TEMPLATE_ARGS> \
|
||||
RET call(CALL_FORMAL_ARGS) const { \
|
||||
switch( detail::select(::boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) ) \
|
||||
{ \
|
||||
BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST(BOOST_PP_DEC(N)) \
|
||||
default: \
|
||||
detail::select(::boost::tuples::get<N>(args), CALL_ACTUAL_ARGS); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// switch_statement bind functions -------------------------------------
|
||||
|
||||
// The zero argument case, for completeness sake
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
do_nothing_action,
|
||||
null_type
|
||||
>
|
||||
>
|
||||
switch_statement() {
|
||||
return
|
||||
lambda_functor_base<
|
||||
do_nothing_action,
|
||||
null_type
|
||||
>
|
||||
();
|
||||
}
|
||||
|
||||
// 1 argument case, this is useless as well, just the condition part
|
||||
template <class TestArg>
|
||||
inline const
|
||||
lambda_functor<
|
||||
lambda_functor_base<
|
||||
switch_action<1>,
|
||||
tuple<lambda_functor<TestArg> >
|
||||
>
|
||||
>
|
||||
switch_statement(const lambda_functor<TestArg>& a1) {
|
||||
return
|
||||
lambda_functor_base<
|
||||
switch_action<1>,
|
||||
tuple< lambda_functor<TestArg> >
|
||||
>
|
||||
( tuple<lambda_functor<TestArg> >(a1));
|
||||
}
|
||||
|
||||
|
||||
#define HELPER(N, FOO) \
|
||||
BOOST_PP_COMMA_IF(N) \
|
||||
BOOST_PP_CAT( \
|
||||
const tagged_lambda_functor<detail::switch_case_tag<TagData, \
|
||||
N>) \
|
||||
BOOST_PP_COMMA() Arg##N>& a##N
|
||||
|
||||
#define HELPER_LIST(N) BOOST_PP_REPEAT(N, HELPER, FOO)
|
||||
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH_STATEMENT(N) \
|
||||
template <class TestArg, \
|
||||
BOOST_LAMBDA_A_I_LIST(N, class TagData), \
|
||||
BOOST_LAMBDA_A_I_LIST(N, class Arg)> \
|
||||
inline const \
|
||||
lambda_functor< \
|
||||
lambda_functor_base< \
|
||||
switch_action<BOOST_PP_INC(N), \
|
||||
BOOST_LAMBDA_A_I_LIST(N, TagData) \
|
||||
>, \
|
||||
tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
|
||||
> \
|
||||
> \
|
||||
switch_statement( \
|
||||
const lambda_functor<TestArg>& ta, \
|
||||
HELPER_LIST(N) \
|
||||
) \
|
||||
{ \
|
||||
return \
|
||||
lambda_functor_base< \
|
||||
switch_action<BOOST_PP_INC(N), \
|
||||
BOOST_LAMBDA_A_I_LIST(N, TagData) \
|
||||
>, \
|
||||
tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
|
||||
> \
|
||||
( tuple<lambda_functor<TestArg>, BOOST_LAMBDA_A_I_LIST(N, Arg)> \
|
||||
(ta, BOOST_LAMBDA_A_I_LIST(N, a) )); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Here's the actual generation
|
||||
|
||||
#define BOOST_LAMBDA_SWITCH(N) \
|
||||
BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE(N) \
|
||||
BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE(N)
|
||||
|
||||
// Use this to avoid case 0, these macros work only from case 1 upwards
|
||||
#define BOOST_LAMBDA_SWITCH_HELPER(N, A) \
|
||||
BOOST_LAMBDA_SWITCH( BOOST_PP_INC(N) )
|
||||
|
||||
// Use this to avoid cases 0 and 1, these macros work only from case 2 upwards
|
||||
#define BOOST_LAMBDA_SWITCH_STATEMENT_HELPER(N, A) \
|
||||
BOOST_LAMBDA_SWITCH_STATEMENT(BOOST_PP_INC(N))
|
||||
|
||||
|
||||
|
||||
// up to 9 cases supported (counting default:)
|
||||
BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_HELPER,FOO)
|
||||
BOOST_PP_REPEAT_2ND(9,BOOST_LAMBDA_SWITCH_STATEMENT_HELPER,FOO)
|
||||
|
||||
|
||||
} // namespace lambda
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#undef HELPER
|
||||
#undef HELPER_LIST
|
||||
|
||||
#undef BOOST_LAMBDA_SWITCH_HELPER
|
||||
#undef BOOST_LAMBDA_SWITCH
|
||||
#undef BOOST_LAMBDA_SWITCH_NO_DEFAULT_CASE
|
||||
#undef BOOST_LAMBDA_SWITCH_WITH_DEFAULT_CASE
|
||||
|
||||
#undef BOOST_LAMBDA_SWITCH_CASE_BLOCK
|
||||
#undef BOOST_LAMBDA_SWITCH_CASE_BLOCK_LIST
|
||||
|
||||
#undef BOOST_LAMBDA_SWITCH_STATEMENT
|
||||
#undef BOOST_LAMBDA_SWITCH_STATEMENT_HELPER
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -23,17 +23,18 @@ AR = ar
|
||||
|
||||
SOURCES = \
|
||||
is_instance_of_test.cpp \
|
||||
operator_tests_simple.cpp \
|
||||
member_pointer_test.cpp \
|
||||
control_structures.cpp \
|
||||
switch_construct.cpp \
|
||||
cast_test.cpp \
|
||||
operator_tests_simple.cpp \
|
||||
bind_tests_simple.cpp \
|
||||
bind_tests_advanced.cpp \
|
||||
bll_and_function.cpp \
|
||||
constructor_tests.cpp \
|
||||
extending_return_type_traits.cpp \
|
||||
bind_tests_simple_function_references.cpp \
|
||||
extending_rt_traits.cpp \
|
||||
bind_tests_simple_f_refs.cpp \
|
||||
cast_test.cpp \
|
||||
phoenix_control_structures.cpp \
|
||||
exception_test.cpp \
|
||||
|
||||
|
||||
@@ -69,13 +70,14 @@ run:
|
||||
./operator_tests_simple.exe
|
||||
./control_structures.exe
|
||||
./switch_construct.exe
|
||||
./extending_return_type_traits.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_function_references.exe
|
||||
./bind_tests_simple_f_refs.exe
|
||||
./phoenix_control_structures.exe
|
||||
./exception_test.exe
|
||||
|
||||
|
||||
@@ -85,4 +87,3 @@ run:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
|
||||
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
|
||||
|
||||
#include "boost/lambda/bind.hpp"
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
#include "boost/lambda/bind.hpp"
|
||||
|
||||
|
||||
#include "boost/any.hpp"
|
||||
|
||||
@@ -33,6 +34,8 @@ fptr_type sum_or_product(bool x) {
|
||||
// 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; }
|
||||
};
|
||||
|
||||
@@ -86,31 +89,32 @@ int call_with_100(const F& f) {
|
||||
template<class F>
|
||||
int call_with_101(const F& f) {
|
||||
|
||||
return bind(unlambda(ret<int>(f)), _1)(make_const(101));
|
||||
return bind(unlambda(f), _1)(make_const(101));
|
||||
|
||||
// the ret must be inside of unlambda, since unlambda requires its argument
|
||||
// to define result_type.
|
||||
// if F is not a lambda functor ret<int>(f) fails at compile time!
|
||||
}
|
||||
|
||||
|
||||
void test_unlambda() {
|
||||
|
||||
BOOST_TEST(call_with_100(ret<int>(_1 + 1)) == 101);
|
||||
// note, that the functor must define the result_type typedef, as the bind
|
||||
// int the called function does not do that.
|
||||
int i = 1;
|
||||
|
||||
BOOST_TEST(unlambda(_1 + _2)(i, i) == 2);
|
||||
BOOST_TEST(unlambda(++var(i))() == 2);
|
||||
BOOST_TEST(call_with_100(_1 + 1) == 101);
|
||||
|
||||
|
||||
BOOST_TEST(call_with_101(_1 + 1) == 102);
|
||||
// This one leaves the return type to be specified by the bind in the
|
||||
// called function, and that makes things kind of hard in the called
|
||||
// function
|
||||
|
||||
BOOST_TEST(call_with_100(std::bind1st(std::plus<int>(), 1)) == 101);
|
||||
|
||||
// BOOST_TEST(call_with_101(std::bind1st(std::plus<int>(), 1)) == 102);
|
||||
// this would fail, as it would lead to ret being called with other than
|
||||
// a lambda functor
|
||||
BOOST_TEST(call_with_100(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.
|
||||
bind(std_functor(std::plus<int>()), _1, _2)(i, i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// protect ------------------------------------------------------------
|
||||
|
||||
// protect protects a lambda functor from argument substitution.
|
||||
@@ -118,21 +122,14 @@ void test_unlambda() {
|
||||
|
||||
namespace ll {
|
||||
|
||||
struct for_each : public has_sig {
|
||||
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.
|
||||
// The basic mechanism (provide a result_type typedef) does not
|
||||
// work.
|
||||
|
||||
// There is an alternative for this kind of situations, which LL
|
||||
// borrows from FC++ (by Yannis Smaragdakis and Brian McNamara).
|
||||
|
||||
// If you want to use this mechanism, your function object class needs to
|
||||
// 1. inhertit publicly from has_sig
|
||||
// 2. Provide a sig class member template:
|
||||
// 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
|
||||
@@ -148,17 +145,14 @@ struct for_each : public has_sig {
|
||||
// if the functor has several operator()'s, even if they have different
|
||||
// number of arguments.
|
||||
|
||||
// Note, that the argument types in Args can be arbitrary types, particularly
|
||||
// they can be reference types and can have qualifiers or both.
|
||||
// So some care will be needed in this respect.
|
||||
|
||||
template <class Args>
|
||||
// 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::remove_reference<
|
||||
typename boost::tuples::element<3, Args>::type
|
||||
>::type
|
||||
>::type type;
|
||||
typename boost::tuples::element<3, Args>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class A, class B, class C>
|
||||
@@ -178,21 +172,21 @@ void test_protect()
|
||||
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))));
|
||||
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)
|
||||
// )
|
||||
// << protect(_1)
|
||||
// )
|
||||
// );
|
||||
|
||||
int sum = 0;
|
||||
|
||||
std::for_each(a, a+3,
|
||||
bind(ll::for_each(), _1, _1 + 5,
|
||||
bind(ll::for_each(), _1, _1 + 5,
|
||||
protect(sum += _1))
|
||||
);
|
||||
BOOST_TEST(sum == (1+15)*15/2);
|
||||
@@ -200,11 +194,12 @@ void test_protect()
|
||||
sum = 0;
|
||||
|
||||
std::for_each(a, a+3,
|
||||
bind(ll::for_each(), _1, _1 + 5,
|
||||
bind(ll::for_each(), _1, _1 + 5,
|
||||
sum += 1 + protect(_1)) // add element count
|
||||
);
|
||||
BOOST_TEST(sum == (1+15)*15/2 + 15);
|
||||
|
||||
(1 + protect(_1))(sum);
|
||||
|
||||
int k = 0;
|
||||
((k += constant(1)) += protect(constant(2)))();
|
||||
@@ -232,10 +227,15 @@ void test_protect()
|
||||
// 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);
|
||||
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&
|
||||
@@ -243,7 +243,10 @@ void test_protect()
|
||||
// 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
|
||||
(boost::ref(std::cout << 1), std::cout << constant(2))(); // this does
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -254,17 +257,22 @@ void test_lambda_functors_as_arguments_to_lambda_functors() {
|
||||
|
||||
// Note however, that the argument/type substitution is not entered again.
|
||||
// This means, that something like this will not work:
|
||||
(_1 + _2)(bind(&sum_0), make_const(7));
|
||||
|
||||
(_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_TEST((_1 + _2)(bind(&sum_0), make_const(7))() == 7);
|
||||
|
||||
int i = 3, j = 12;
|
||||
BOOST_TEST((_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
|
||||
// either define the result_type typedef, have the sig template, or then
|
||||
// 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
|
||||
@@ -272,55 +280,19 @@ void test_lambda_functors_as_arguments_to_lambda_functors() {
|
||||
|
||||
int a = 5, b = 6;
|
||||
|
||||
// Let type deduction take find out the return type
|
||||
BOOST_TEST(bind(_1, _2, _3)(_1 + _2, a, b) == 11);
|
||||
// Let type deduction find out the return type
|
||||
BOOST_TEST(bind(_1, _2, _3)(unlambda(_1 + _2), a, b) == 11);
|
||||
|
||||
//specify it yourself:
|
||||
BOOST_TEST(bind(_1, _2, _3)(ret<int>(_1 + _2), a, b) == 11);
|
||||
BOOST_TEST(ret<int>(bind(_1, _2, _3))(_1 + _2, a, b) == 11);
|
||||
BOOST_TEST(bind<int>(_1, _2, _3)(_1 + _2, a, b) == 11);
|
||||
|
||||
|
||||
bind(_1,1.0)(_1+_1);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void test_currying() {
|
||||
|
||||
int a = 1, b = 2, c = 3;
|
||||
|
||||
// lambda functors support currying:
|
||||
// binary functor can be called with just one argument, the result is
|
||||
// a unary lambda functor.
|
||||
// 3-ary functor can be called with one or two arguments (and with 3
|
||||
// of course)
|
||||
|
||||
BOOST_TEST((_1 + _2)(a)(b) == 3);
|
||||
|
||||
BOOST_TEST((_1 + _2 + _3)(a, b)(c) == 6);
|
||||
BOOST_TEST((_1 + _2 + _3)(a)(b, c) == 6);
|
||||
BOOST_TEST((_1 + _2 + _3)(a)(b)(c) == 6);
|
||||
|
||||
// Also, lambda functors passed as arguments end up being curryable
|
||||
|
||||
BOOST_TEST(bind(_1, _2, _3)(_1 + _2 + _3, a, b)(c) == 6);
|
||||
BOOST_TEST(bind(_1, _2)(_1 + _2 + _3, a)(b, c) == 6);
|
||||
BOOST_TEST(bind(_1, _2)(_1 + _2 + _3, a)(b)(c) == 6);
|
||||
|
||||
bind(_1, _2)(_1 += (_2 + _3), a)(b)(c);
|
||||
BOOST_TEST(a == 6);
|
||||
|
||||
bind(_1, _2)(a += (_1 + _2 + _3), c)(c)(c);
|
||||
BOOST_TEST(a == 6+3*c);
|
||||
|
||||
a = 1, b = 2, c = 3;
|
||||
// and protecting should work as well
|
||||
BOOST_TEST(bind(_1, _2)(_1 + _2 + _3 + protect(_1), a)(b)(c)(a) == 7);
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void test_const_parameters() {
|
||||
|
||||
@@ -357,7 +329,6 @@ int test_main(int, char *[]) {
|
||||
test_unlambda();
|
||||
test_protect();
|
||||
test_lambda_functors_as_arguments_to_lambda_functors();
|
||||
test_currying();
|
||||
test_const_parameters();
|
||||
test_break_const();
|
||||
return 0;
|
||||
|
||||
@@ -39,10 +39,13 @@ void test_member_functions()
|
||||
A a(10);
|
||||
int i = 1;
|
||||
|
||||
BOOST_TEST(bind(&A::add, ref(a), _1)(i) == 11);
|
||||
BOOST_TEST(bind(&A::add, &a, _1)(i) == 11);
|
||||
BOOST_TEST(bind(&A::add, _1, 1)(a) == 11);
|
||||
BOOST_TEST(bind(&A::add, _1, 1)(make_const(&a)) == 11);
|
||||
|
||||
|
||||
|
||||
BOOST_TEST(bind(&A::add, ref(a), _1)(i) == 11);
|
||||
BOOST_TEST(bind(&A::add, &a, _1)(i) == 11);
|
||||
BOOST_TEST(bind(&A::add, _1, 1)(a) == 11);
|
||||
BOOST_TEST(bind(&A::add, _1, 1)(make_const(&a)) == 11);
|
||||
|
||||
// This should fail, as lambda functors store arguments as const
|
||||
// bind(&A::add, a, _1);
|
||||
@@ -120,14 +123,14 @@ int test_main(int, char *[]) {
|
||||
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)
|
||||
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_TEST(result == 12);
|
||||
|
||||
|
||||
@@ -121,14 +121,14 @@ int test_main(int, char *[]) {
|
||||
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)
|
||||
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_TEST(result == 12);
|
||||
|
||||
@@ -22,16 +22,12 @@ using namespace std;
|
||||
void test_function() {
|
||||
|
||||
boost::function<int, int, int> f;
|
||||
f = unlambda(_1 + _2);
|
||||
|
||||
// unlambda must be used, because boost::function tries to take the
|
||||
// address of the function object that is assigned. However, the
|
||||
// operator& is overloaded for lambda functors, which creates a conflict
|
||||
f = _1 + _2;
|
||||
|
||||
BOOST_TEST(f(1, 2)== 3);
|
||||
|
||||
int i=1; int j=2;
|
||||
boost::function<int&, int&, int> g = unlambda(_1 += _2);
|
||||
boost::function<int&, int&, int> g = _1 += _2;
|
||||
g(i, j);
|
||||
BOOST_TEST(i==3);
|
||||
|
||||
@@ -39,7 +35,7 @@ void test_function() {
|
||||
|
||||
int* sum = new int();
|
||||
*sum = 0;
|
||||
boost::function<int&, int> counter = unlambda(*sum += _1);
|
||||
boost::function<int&, int> counter = *sum += _1;
|
||||
counter(5); // ok, sum* = 5;
|
||||
BOOST_TEST(*sum == 5);
|
||||
delete sum;
|
||||
|
||||
@@ -234,7 +234,7 @@ void delayed_construction()
|
||||
vector<pair<int, int> > v;
|
||||
|
||||
transform(x.begin(), x.end(), y.begin(), back_inserter(v),
|
||||
bind(constructor<pair<int, int> >(), _1, _2) );
|
||||
bind(constructor<pair<int, int> >(), _1, _2) );
|
||||
}
|
||||
|
||||
int test_main(int, char *[]) {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
|
||||
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
#include "boost/lambda/control_structures.hpp"
|
||||
#include "boost/lambda/if.hpp"
|
||||
#include "boost/lambda/loops.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -33,11 +33,11 @@ void erroneous_exception_related_lambda_expressions() {
|
||||
// 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);
|
||||
// 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 (_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));
|
||||
@@ -512,6 +512,19 @@ void test_different_number_of_catch_blocks() {
|
||||
BOOST_TEST(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() {
|
||||
|
||||
@@ -531,7 +544,7 @@ void return_type_matching() {
|
||||
try_catch(
|
||||
_1 + 1,
|
||||
catch_exception<int>((&_1, rethrow())), // no match, but ok since throws
|
||||
catch_exception<char>(_E) // ok, char convertible to int
|
||||
catch_exception<char>(_e) // ok, char convertible to int
|
||||
)(i)
|
||||
|
||||
== 2
|
||||
@@ -542,19 +555,19 @@ void return_type_matching() {
|
||||
|
||||
// try_catch(
|
||||
// _1 += 1,
|
||||
// catch_exception<char>(_E) // NOT ok, char not convertible to int&
|
||||
// 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
|
||||
catch_exception<char>(_e) // since try is void, catch can return anything
|
||||
)(i);
|
||||
BOOST_TEST(i == 2);
|
||||
|
||||
try_catch(
|
||||
(_1 += 1, throw_exception('a')),
|
||||
catch_exception<char>(_E) // since try throws, it is void,
|
||||
catch_exception<char>(_e) // since try throws, it is void,
|
||||
// so catch can return anything
|
||||
)(i);
|
||||
BOOST_TEST(i == 3);
|
||||
@@ -565,7 +578,7 @@ void return_type_matching() {
|
||||
throw_exception(1),
|
||||
catch_exception<int>(throw_exception('b'))
|
||||
),
|
||||
catch_exception<char>( _1 = _E )
|
||||
catch_exception<char>( _1 = _e )
|
||||
)(a);
|
||||
BOOST_TEST(a == 'b');
|
||||
}
|
||||
@@ -576,6 +589,7 @@ int test_main(int, char *[]) {
|
||||
{
|
||||
test_different_number_of_catch_blocks();
|
||||
return_type_matching();
|
||||
test_empty_catch_blocks();
|
||||
}
|
||||
catch (int x)
|
||||
{
|
||||
@@ -593,46 +607,3 @@ int test_main(int, char *[]) {
|
||||
|
||||
|
||||
|
||||
// cout << "Before make void call. i ="<< i << "\n";
|
||||
// (make_void(free1 += 3))(i);
|
||||
// cout << "After make void call, should be += 3 i = " << i << "\n";
|
||||
|
||||
// int j =0;
|
||||
// var_type<int>::type vj(var(j));
|
||||
// (make_void(for_loop(vj = 0, vj < free1, ++vj, cout << vj << "\n")))(i);
|
||||
|
||||
// try_catch( make_void(free1 += 3 + free2),
|
||||
// catch_exception<int>( cout << constant("Should work: ") << free1 + free2 << "\n" )
|
||||
// )
|
||||
// (i, i);
|
||||
|
||||
// try_catch( make_void(free1 += 3),
|
||||
// catch_exception<int>( cout << constant("Should work: ") << free1 + free2 << "\n" )
|
||||
// )
|
||||
// (i, i);
|
||||
|
||||
// try_catch( throw_exception(1),
|
||||
// catch_exception<int>(
|
||||
// throw_exception(2) )
|
||||
// )
|
||||
// ();
|
||||
|
||||
// try_catch( throw_exception(1),
|
||||
// catch_exception<int>(
|
||||
// ((cout << constant("caught int: ") << free1 + free2 << "\n")
|
||||
// ,throw_exception(2) )
|
||||
// ),
|
||||
// catch_all(
|
||||
// ((cout << constant("catch all: ") << free1 + free2 << "\n")
|
||||
// ,rethrow())
|
||||
// )
|
||||
// )(i,i);
|
||||
|
||||
// // try_catch which returns (10 is added, so that the try return type is int
|
||||
// cout << "\n -------------- \n" <<
|
||||
// try_catch( (throw_exception(5), 10),
|
||||
// catch_exception<int>( free1 + free2 + freeE ) // returns int
|
||||
// )
|
||||
// (i, i) << "\n";
|
||||
|
||||
|
||||
|
||||
@@ -188,19 +188,19 @@ struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
|
||||
// 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&> {
|
||||
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&> {
|
||||
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&> {
|
||||
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&> {
|
||||
struct return_type_2<arithmetic_action<multiply_action>, volatile const XX, const volatile YY> {
|
||||
typedef VV type;
|
||||
};
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
#include "boost/lambda/bind.hpp"
|
||||
|
||||
#include "boost/lambda/detail/member_ptr.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace boost::lambda;
|
||||
@@ -119,30 +117,33 @@ bool operator->*(B b, A a) {
|
||||
|
||||
// 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
|
||||
// references :(
|
||||
// or use the plain_return_type_2 template.
|
||||
namespace boost {
|
||||
namespace lambda {
|
||||
|
||||
template <>
|
||||
struct return_type_2<other_action<member_pointer_action>, B&, A&> {
|
||||
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&> {
|
||||
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&> {
|
||||
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&> {
|
||||
struct return_type_2<other_action<member_pointer_action>, const B, const A> {
|
||||
typedef bool type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // lambda
|
||||
} // boost
|
||||
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifndef BOOST_NO_STRINGSTREAM
|
||||
#include <sstream>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
using namespace boost::lambda;
|
||||
|
||||
@@ -17,6 +25,44 @@ 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_TEST(os.str() == std::string("10FOO"));
|
||||
|
||||
|
||||
istringstream is("ABC 1");
|
||||
std::string s;
|
||||
int k;
|
||||
|
||||
is >> s;
|
||||
is >> k;
|
||||
|
||||
BOOST_TEST(s == std::string("ABC"));
|
||||
BOOST_TEST(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_TEST((ci)() == 5);
|
||||
BOOST_TEST(i == 100);
|
||||
|
||||
int a;
|
||||
constant_ref_type<int>::type cr(constant_ref(i));
|
||||
(++vi, var(a) = cr)();
|
||||
BOOST_TEST(i == 101);
|
||||
#endif
|
||||
}
|
||||
|
||||
void arithmetic_operators() {
|
||||
int i = 1; int j = 2; int k = 3;
|
||||
|
||||
@@ -49,7 +95,7 @@ void bitwise_operators() {
|
||||
BOOST_TEST((_1 & 1)(ui)==(2 & 1));
|
||||
BOOST_TEST((_1 | 1)(ui)==(2 | 1));
|
||||
BOOST_TEST((_1 ^ 1)(ui)==(2 ^ 1));
|
||||
BOOST_TEST((~_1)(ui)==~2);
|
||||
BOOST_TEST((~_1)(ui)==~2u);
|
||||
}
|
||||
|
||||
void comparison_operators() {
|
||||
@@ -330,7 +376,7 @@ int test_main(int, char *[]) {
|
||||
address_of_and_dereference();
|
||||
comma();
|
||||
pointer_arithmetic();
|
||||
|
||||
cout_tests();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
139
test/phoenix_control_structures.cpp
Normal file
139
test/phoenix_control_structures.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
// phoenix_style_control_structures.cpp --------------------------------
|
||||
|
||||
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
|
||||
#include <boost/test/test_tools.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 tatements
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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_TEST(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_TEST(lt==4);
|
||||
BOOST_TEST(eq==1);
|
||||
BOOST_TEST(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_TEST(counta == 55);
|
||||
BOOST_TEST(countb == 10);
|
||||
|
||||
|
||||
v = t;
|
||||
|
||||
counta = 0; countb = 0;
|
||||
//////////////////////////////////
|
||||
for_each(v.begin(), v.end(),
|
||||
(
|
||||
do_
|
||||
[
|
||||
++var(counta)
|
||||
]
|
||||
.while_(_1--),
|
||||
++var(countb)
|
||||
)
|
||||
);
|
||||
|
||||
BOOST_TEST(counta == (2+11)*10/2);
|
||||
BOOST_TEST(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_TEST(counta == (1+10)*10/2);
|
||||
BOOST_TEST(countb == 10);
|
||||
|
||||
v = t;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
#include "boost/lambda/control_structures.hpp"
|
||||
#include "boost/lambda/if.hpp"
|
||||
#include "boost/lambda/switch.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@@ -350,11 +351,30 @@ void do_switch_yes_defaults_tests() {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user