2
0
mirror of https://github.com/boostorg/lambda.git synced 2026-01-21 04:52:25 +00:00

Compare commits

..

91 Commits

Author SHA1 Message Date
Jaakko Järvi
aa52de0931 replaced by algorithm.hpp
[SVN r12939]
2002-02-25 22:06:38 +00:00
Jaakko Järvi
b335b7cf30 f
[SVN r12906]
2002-02-22 21:13:29 +00:00
Jaakko Järvi
f54bbdc1a7 added test coverage
[SVN r12904]
2002-02-22 19:43:42 +00:00
Jaakko Järvi
f404313f16 fix
[SVN r12900]
2002-02-22 15:25:15 +00:00
Jaakko Järvi
d86ebf9f1a spacing
[SVN r12899]
2002-02-22 15:24:53 +00:00
Jaakko Järvi
1a698677ad added workarounds for gcc2.96
[SVN r12898]
2002-02-22 15:21:17 +00:00
Jaakko Järvi
b57fe61901 fixed a comment
[SVN r12885]
2002-02-21 22:29:52 +00:00
Jaakko Järvi
1d33face98 removed some extra consts
[SVN r12884]
2002-02-21 22:29:29 +00:00
Jaakko Järvi
e36b3e7c7a removed ;
[SVN r12883]
2002-02-21 22:28:54 +00:00
Jaakko Järvi
ce9d859823 docs in smaller chunks
[SVN r12882]
2002-02-21 22:27:28 +00:00
Jaakko Järvi
9eaab4dbc6 added definitions for logical_action<or/and_action> as KCC needs them
[SVN r12881]
2002-02-21 21:01:28 +00:00
Jaakko Järvi
8e2c7efc1e added test file bll_and_function.cpp
[SVN r12880]
2002-02-21 21:00:31 +00:00
Jaakko Järvi
65fe870596 test file for using boost::function and BLL together
[SVN r12877]
2002-02-21 16:03:12 +00:00
Jaakko Järvi
027c6bf563 changed placheolder typedef names
[SVN r12812]
2002-02-14 20:11:19 +00:00
Jaakko Järvi
02cd3b5453 changed placeholder typedef names
[SVN r12811]
2002-02-14 20:10:52 +00:00
Jaakko Järvi
be8e0e3cd3 progress
[SVN r12809]
2002-02-14 20:09:30 +00:00
Jaakko Järvi
5933a21c2d contains only a small subset of STL algs at this point
[SVN r12789]
2002-02-12 21:54:59 +00:00
Jaakko Järvi
098bdd80c9 still a draft but should now include all sections
[SVN r12788]
2002-02-12 21:53:36 +00:00
Jaakko Järvi
b330716694 nested stl algorithms, for_each and transform for just now
[SVN r12784]
2002-02-11 21:53:26 +00:00
Jaakko Järvi
96bccbf4b7 added #include <iterators>
[SVN r12759]
2002-02-08 15:27:17 +00:00
Jaakko Järvi
11c0b6a2f0 added text for constructors and destructors, fixed a few typos,
added comment about function objects with side-effects in non-modifyin
sequence algorithms like for_each


[SVN r12750]
2002-02-07 22:39:18 +00:00
Jaakko Järvi
af371a4ae0 control construct docs added
[SVN r12734]
2002-02-05 22:26:30 +00:00
Jaakko Järvi
4c1ba44195 bugfix
[SVN r12716]
2002-02-04 23:20:33 +00:00
Jaakko Järvi
93a8e679a7 a draft documentation, still incomplete
[SVN r12714]
2002-02-04 22:32:43 +00:00
Jaakko Järvi
5cd4705a3a reordering
[SVN r12713]
2002-02-04 22:30:58 +00:00
Jaakko Järvi
5659b120aa compile with gcc3.x.x, KCC with edg 2.43.
some files do not compile with gcc2.9x


[SVN r12711]
2002-02-04 21:52:54 +00:00
Jaakko Järvi
e11111073a gcc 2.9{5,6} fail to compile bind calls with function references,
hence created a separate test for that.
bind_test_simple.cpp now does all calls as function pointers


[SVN r12704]
2002-02-04 20:14:32 +00:00
Jaakko Järvi
beadc914b1 changes to make return type deduction extensions easier, fixed --strict
compilation warnings and errors


[SVN r12536]
2002-01-28 16:15:09 +00:00
Jaakko Järvi
276a81f517 Compile and run with gcc3.0.2. and KCC (edg.2.43.1)
[SVN r12535]
2002-01-28 16:13:33 +00:00
Jaakko Järvi
3aeaf08362 comment change
[SVN r12349]
2002-01-18 19:28:10 +00:00
Jaakko Järvi
64b7d3f97a bugfix
[SVN r12321]
2002-01-14 22:44:35 +00:00
Jaakko Järvi
640ab42a5e going forward
[SVN r12320]
2002-01-14 22:44:06 +00:00
Jaakko Järvi
98ca7523d3 added const_parameters
[SVN r12312]
2002-01-14 16:22:35 +00:00
Jaakko Järvi
6a0ab1ad04 added tests for break_const and const_parameters
[SVN r12311]
2002-01-14 16:21:38 +00:00
Jaakko Järvi
1ce4f8fb57 added test for break_const
[SVN r12278]
2002-01-10 22:05:59 +00:00
Jaakko Järvi
fd0c89cdc5 bug fixes to const_incorrect_lambda_functor
[SVN r12277]
2002-01-10 22:05:13 +00:00
Jaakko Järvi
7236002954 removed constify_rvalues as not used anymore
[SVN r12276]
2002-01-10 21:08:37 +00:00
Jaakko Järvi
31390192ee is_instance_of templates moved from detail to lambda.
Added a test to make sure that is_instance_of<...>::value is a compile
time constant


[SVN r12275]
2002-01-10 20:57:26 +00:00
Jaakko Järvi
b13e8f403d some tidying up and more tests
[SVN r12274]
2002-01-10 20:55:12 +00:00
Jaakko Järvi
afaacdc785 a lot of changes:
support for FC++ style sig templates for return type deduction
support for currying lambda functors
proper protect support
if lambda functors are bound, return type deduction works


[SVN r12273]
2002-01-10 20:54:11 +00:00
Jaakko Järvi
682939bf35 tests for currying, protect, unlambda, ...
[SVN r12269]
2002-01-10 18:58:03 +00:00
Jaakko Järvi
be14866425 is_instance_of was moved from detail namespace to boost::lambda
[SVN r12220]
2002-01-04 21:33:48 +00:00
Jaakko Järvi
5789f3d98a moved comma from operator_actions.hpp to actions.hpp
added leftshift_action_no_stream and rightshift_action_no_stream


[SVN r12219]
2002-01-04 21:32:57 +00:00
Jaakko Järvi
286dc4bdd3 all types sent down to return_type_N templates are now references.
This makes it easier to provide user defined specializations.
Added a specialization for comma operator for return_type<> level, as
it is an exception to the above rule.


[SVN r12218]
2002-01-04 21:31:30 +00:00
Jaakko Järvi
2eb62a137d added specializations for subscripting standard containers,
support for << >> with templated streams, plus other small fixes


[SVN r12217]
2002-01-04 21:29:06 +00:00
Jaakko Järvi
006d968e5a implementation now uses is_convertible to deal with bugs in different
compilers


[SVN r12216]
2002-01-04 21:00:10 +00:00
Jaakko Järvi
cd6db4a38c removed lambda_functor_sub as obsolete
[SVN r12182]
2001-12-31 18:31:15 +00:00
Jaakko Järvi
dd50c9ad38 added the ability to copy compatible lambda functors (same aritycode,
same action and compatible argument tuples). Removed lambda_functor_sub,
as it became obsolete


[SVN r12181]
2001-12-31 18:29:40 +00:00
Jaakko Järvi
c2f3f1cf5d changed to use the new boost preprocessor library
[SVN r12180]
2001-12-31 18:26:12 +00:00
Jaakko Järvi
8421704962 some comment changed
[SVN r12179]
2001-12-31 18:23:41 +00:00
Jaakko Järvi
40a8126a62 removed the local copy of preprocessor, as it is now part of boost
[SVN r12176]
2001-12-31 16:30:45 +00:00
Jaakko Järvi
2762e6c8cd minor changes
[SVN r12154]
2001-12-27 15:07:03 +00:00
Jaakko Järvi
4e607bc493 still very much a draft
[SVN r12152]
2001-12-26 21:59:18 +00:00
Jaakko Järvi
3dff7d970d removed some old commented code
[SVN r12151]
2001-12-26 15:42:13 +00:00
Jaakko Järvi
cb2c689df7 added support for protect, unlambda, currying and break_const
[SVN r12139]
2001-12-21 19:28:31 +00:00
Jaakko Järvi
2c8b1949ec added support for protect and currying (lambda functor return types)
[SVN r12138]
2001-12-21 19:27:26 +00:00
Jaakko Järvi
2ef4480a3f added a really old draft of a user's guide. Not ready and not even
correct in many places, don't read yet.


[SVN r12137]
2001-12-21 19:26:25 +00:00
Jaakko Järvi
99260b26b6 added an accompanying example file for users guide
[SVN r12136]
2001-12-21 19:25:13 +00:00
Jaakko Järvi
d52a33ac2a support for currying
[SVN r12135]
2001-12-21 19:22:59 +00:00
Jaakko Järvi
aa715e88d4 return type deduction should not fail now
[SVN r12111]
2001-12-18 16:23:53 +00:00
Jaakko Järvi
1f583d7b3a a test file for member pointer operators
[SVN r12110]
2001-12-18 16:22:54 +00:00
Jaakko Järvi
aef38586e2 adding bind<ret>(...) syntax
[SVN r12095]
2001-12-17 22:44:14 +00:00
Jaakko Järvi
08bdbd1b69 making return type deduction system not to fail at compile time
[SVN r12094]
2001-12-17 22:43:43 +00:00
Jaakko Järvi
d364221497 removed an unneeded definition
[SVN r12093]
2001-12-17 22:41:53 +00:00
Jaakko Järvi
9c7429a513 added bind<ret>(... syntax, trying to make the return type deduction
never to fail at compile time (still not quite there)


[SVN r12092]
2001-12-17 22:40:45 +00:00
Jaakko Järvi
60fc136bfa complete rewrite of member pointer operator
[SVN r12017]
2001-12-11 22:06:07 +00:00
Jaakko Järvi
38e589d0db stylistic changes
[SVN r12016]
2001-12-11 22:04:07 +00:00
Jaakko Järvi
9a8290de00 pointer to member stuff moved into a separate header
[SVN r12015]
2001-12-11 22:03:42 +00:00
Jaakko Järvi
072cd1d47c helper templates for bind lambda functors
[SVN r12014]
2001-12-11 22:02:29 +00:00
Jaakko Järvi
183b3a6445 changed a conflicting macro name
[SVN r11941]
2001-12-05 22:06:10 +00:00
Jaakko Järvi
37833a292d moved member_ptr return type deductions to member_ptr.hpp
[SVN r11939]
2001-12-05 21:50:46 +00:00
Jaakko Järvi
cc91943c2e moved member pointer action class to member_ptr.hpp
[SVN r11938]
2001-12-05 21:48:33 +00:00
Jaakko Järvi
d36cab6276 moved member_ptr_action to another file
[SVN r11936]
2001-12-05 21:44:00 +00:00
Jaakko Järvi
5018d11428 removed unnecessary using declaration
[SVN r11881]
2001-12-03 21:13:34 +00:00
Jaakko Järvi
0b81a44df5 added some helper traits to make lambda functor types shorter
[SVN r11765]
2001-11-21 22:04:37 +00:00
Jaakko Järvi
41d84d6c08 changed the include order
[SVN r11764]
2001-11-21 22:03:17 +00:00
Jaakko Järvi
621887af2b one test function wasn't called at all
[SVN r11763]
2001-11-21 22:00:36 +00:00
Jaakko Järvi
87b9c4f66d added ll_sizeof tests
[SVN r11750]
2001-11-20 22:03:25 +00:00
Jaakko Järvi
347cfc8436 added ll_sizeof to casts.hpp
[SVN r11749]
2001-11-20 22:02:04 +00:00
Jaakko Järvi
b456eaf07c all the stuff moved to other files
[SVN r11745]
2001-11-20 17:04:06 +00:00
Jaakko Järvi
242c5c8127 typo in comments, added copyright
[SVN r11744]
2001-11-20 16:17:34 +00:00
Jaakko Järvi
cb21ef5863 removed a testing function
[SVN r11742]
2001-11-19 22:30:04 +00:00
Jaakko Järvi
7dd0e88f2b RET static -> static RET
[SVN r11735]
2001-11-19 22:11:10 +00:00
Jaakko Järvi
273f83d01d added missing typenames to avoid errors in strict mode
[SVN r11734]
2001-11-19 22:09:44 +00:00
Jaakko Järvi
4d49196c48 removed weird linebreaks
[SVN r11733]
2001-11-19 22:09:01 +00:00
Jaakko Järvi
bcc486c8e6 lambda_development branch activites
[SVN r11714]
2001-11-15 21:20:43 +00:00
Jaakko Järvi
d6af6a54fd creating the lambda_development branch
[SVN r11713]
2001-11-15 21:18:10 +00:00
Jaakko Järvi
5d37469865 removed a dummy file
[SVN r11712]
2001-11-15 21:04:44 +00:00
Jaakko Järvi
b376ba2fcf lambda_development branch creation
[SVN r11711]
2001-11-15 20:47:16 +00:00
nobody
e6525e8694 This commit was manufactured by cvs2svn to create branch
'lambda_development'.

[SVN r11710]
2001-11-15 20:42:38 +00:00
Jaakko Järvi
44ae5a9a80 lambda_development branch creation
[SVN r11708]
2001-11-15 20:38:57 +00:00
66 changed files with 5339 additions and 11904 deletions

View File

@@ -1,61 +0,0 @@
<!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>

View File

@@ -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="id2790109"></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="id2790112"></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,11 +20,7 @@
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/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>.
<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>).
</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>
@@ -36,7 +32,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> 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>.
<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>.
</p></li></ul></div>
Any other header files in the package are for internal use.
@@ -44,7 +40,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="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.
</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.
Implicit using declarations
<pre class="programlisting">
using namespace std;

View File

@@ -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="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)
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)
[<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&amp; i) : _i(i) {}
int operator()(const int&amp; j) { return _i + j; }
int operator(const int&amp; 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="id2742784"></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="id2741408"></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,19 +133,15 @@ 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.
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>
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>
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.
@@ -169,7 +165,16 @@ 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:terminology"></a>3.2.2. Terminology</h4></div></div><p>
</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>
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>

View File

@@ -20,7 +20,7 @@ There are quite a lot of exceptions and special cases, but discussion of them is
list&lt;int&gt; v(10);
for_each(v.begin(), v.end(), _1 = 1);</pre>
The expression <tt>_1 = 1</tt> creates a lambda functor which assigns the value <tt>1</tt> to every element in <tt>v</tt>.<sup>[<a name="id2739587" href="#ftn.id2739587">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="id2739690" href="#ftn.id2739690">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 &lt;&lt; '\n' &lt;&lt; *_1);
</pre>
the subexpression <tt>cout &lt;&lt; '\n'</tt> is evaluated immediately and the effect is to output a single line break, followed by the elements of <tt>vp</tt>.
The BLL provides functions <tt>constant</tt> and <tt>var</tt> to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions:
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:
<pre class="programlisting">
for_each(vp.begin(), vp.end(), cout &lt;&lt; constant('\n') &lt;&lt; *_1);
</pre>
@@ -115,86 +115,37 @@ 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>
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:
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:
<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.
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:
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>&lt;&lt;</tt> or <tt>&gt;&gt;</tt> operator is derived from an instantiation of <tt>basic_ostream</tt> or respectively from <tt>basic_istream</tt>, the argument is stored as a reference to non-const.
@@ -206,7 +157,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.id2739587" href="#id2739587">1</a>] </sup>
</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>
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.

View File

@@ -10,6 +10,7 @@ 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>.
@@ -38,24 +39,6 @@ _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.
@@ -69,7 +52,27 @@ int i = 1;
(_1 += 2)(i); // i is now 3
(++_1, cout &lt;&lt; _1)(i) // i is now 4, outputs 4
</pre>
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:operator_expressions"></a>5.2. Operator expressions</h3></div></div><p>
</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>
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:
@@ -77,9 +80,8 @@ For example, the following is a valid lambda expression:
<pre class="programlisting">cout &lt;&lt; _1, _2[_3] = _1 &amp;&amp; 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="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.
</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.
These operators are <tt>-&gt;.</tt>, <tt>-&gt;</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.
@@ -117,14 +119,14 @@ Without the extra parenthesis around <tt>++_1, cout &lt;&lt; _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>
The function call operators have the effect of evaluating the lambda
functor.
Calls with too few arguments lead to a compile time error.
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.
</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-&gt;*</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.
@@ -179,7 +181,7 @@ The return type of the lambda functor created by the bind expression can be give
<pre class="programlisting">
bind&lt;<span class="emphasis"><i>RET</i></span>&gt;(<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:
@@ -193,7 +195,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);
@@ -222,7 +224,7 @@ find_if(ints.begin(), ints.end(), bind(&amp;A::foo, a, _1));
find_if(ints.begin(), ints.end(), bind(&amp;A::foo, &amp;a, _1));
</pre>
Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference:
Similarly, if the object argument is unbound, the resulting binder object can be called both via a pointer or a reference:
<pre class="programlisting">
bool A::foo(int);
@@ -236,16 +238,15 @@ find_if(pointers.begin(), pointers.end(), bind(&amp;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 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.
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.
This creates some asymmetry between the lambda functor and the original member function, and between seemingly similar lambda functors. For example:
<pre class="programlisting">
class A {
int i; mutable int j;
public:
A(int ii, int jj) : i(ii), j(jj) {};
void set_i(int x) { i = x; };
void set_j(int x) const { j = x; };
void set_j(int x) { j = x; };
};
</pre>
@@ -268,90 +269,62 @@ bind(&amp;A::set_i, a, _1)(k); // error; a const copy of a is stored.
bind(&amp;A::set_j, a, _1)(k); // a.j == 0, as a copy of a is modified
</pre>
</p><p>
To prevent the copying from taking place, one can use the <tt>ref</tt> or <tt>cref</tt> wrappers (<tt>var</tt> and <tt>constant_ref</tt> would do as well):
To prevent the copying from taking place, one can use the <tt>ref</tt> or <tt>cref</tt> wrappers:
<pre class="programlisting">
bind(&amp;A::set_i, ref(a), _1)(k); // a.j == 1
bind(&amp;A::set_j, cref(a), _1)(k); // a.j == 1
</pre>
</p><p>Note that the preceding discussion is relevant only for bound arguments.
If the object argument is unbound, the parameter passing mode is always by reference.
Hence, the argument <tt>a</tt> is not copied in the calls to the two lambda functors below:
Hence, no copying occurs for the actual arguments of the lambda functor:
<pre class="programlisting">
A a(0,0);
bind(&amp;A::set_i, _1, 1)(a); // a.i == 1
bind(&amp;A::set_j, _1, 1)(a); // a.j == 1
</pre>
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:members_variables_as_targets"></a>5.3.3. Member variables as targets</h4></div></div><p>
A pointer to a member variable is not really a function, but
the first argument to the <tt>bind</tt> function can nevertheless
be a pointer to a member variable.
Invoking such a bind expression returns a reference to the data member.
For example:
<pre class="programlisting">
struct A { int data; };
A a;
bind(&amp;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(&amp;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.
</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 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&lt;Args&gt;</tt> with a typedef
<tt>type</tt> that specifies the return type.
Here is a simple example:
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.
For example:
<pre class="programlisting">
struct A {
template &lt;class Args&gt; struct sig { typedef B type; }
typedef B result_type;
B operator()(X, Y, Z);
};
</pre>
The template argument <tt>Args</tt> is a
<tt>tuple</tt> (or more precisely a <tt>cons</tt> list)
type [<a href="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:
Function objects in the standard library adhere to this convention.
</p><p>
There are two significant restrictions with this scheme:
<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.
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&lt;Args&gt;</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&amp;</tt>.
</p></li></ol></div>
The following code shows an example, where the return type depends on the type
of one of the arguments, and how that dependency can be expressed with the
<tt>sig</tt> template:
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:
<pre class="programlisting">
struct A {
struct A : public has_sig {
// the return type equals the third argument type:
template&lt;class T1, T2, T3&gt;
@@ -361,60 +334,21 @@ struct A {
class sig {
// get the third argument type (4th element)
typedef typename
boost::tuples::element&lt;3, Args&gt;::type T3;
boost::tuples::get&lt;3, Args&gt;::type T3;
typedef typename
boost::remove_reference&lt;T3&gt;::type T3_non_ref;
public:
typedef typename
boost::remove_cv&lt;T3&gt;::type type;
boost::remove_const&lt;T3_non_ref&gt;::type type;
}
};
</pre>
The elements of the <tt>Args</tt> tuple are always
non-reference types.
Moreover, the element types can have a const or volatile qualifier
(jointly referred to as <span class="emphasis"><i>cv-qualifiers</i></span>), or both.
This is since the cv-qualifiers in the arguments can affect the return type.
The reason for including the potentially cv-qualified function object
type itself into the <tt>Args</tt> tuple, is that the function
object class can contain both const and non-const (or volatile, even
const volatile) function call operators, and they can each have a different
return type.
</p><p>
The <tt>sig</tt> template can be seen as a
<span class="emphasis"><i>meta-function</i></span> that maps the argument type tuple to
the result type of the call made with arguments of the types in the tuple.
As the example above demonstrates, the template can end up being somewhat
complex.
Typical tasks to be performed are the extraction of the relevant types
from the tuple, removing cv-qualifiers etc.
See the Boost type_traits [<a href="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&lt;int&gt;(), _1, 1)(i); // error, no sig template
bind(std_functor(plus&lt;int&gt;()), _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 <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 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.
@@ -436,22 +370,21 @@ ret&lt;C&gt;(_1 + _2)(a, b); // ok
ret&lt;float&gt;(_1 * _2)(a, b); // ok (int can be converted to float)
...
struct X {
Y operator(int)();
typedef Y result_type;
Y operator()(); // #1
Z operator(int)(); // #2
};
...
X x; int i;
bind(x, _1)(i); // error, return type cannot be deduced
ret&lt;Y&gt;(bind(x, _1))(i); // ok
bind(x)(); // ok, call #1
bind(x, _1)(i); // try to call #2: error, deduction gives Y
ret&lt;Z&gt;(bind(x, _1))(i); // ok, call #2
</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&lt;Z&gt;(x, _1)(i);</pre>
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.
</p><p>Note that within nested lambda expressions, the <tt>ret</tt> must be used at each invocation where the deduction would otherwise fail.
For example:
<pre class="programlisting">
A a; B b;
@@ -490,9 +423,8 @@ The lambda functors created with
<tt>bind&lt;<i><tt>T</tt></i>&gt;(<i><tt>arg-list</tt></i>)</tt> have the exact same functionality &#8212;
apart from the fact that for some nullary lambda functors the former does not work while the latter does.
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:delaying_constants_and_variables"></a>5.5. Delaying constants and variables</h3></div></div><p>
The unary functions <tt>constant</tt>,
<tt>constant_ref</tt> and <tt>var</tt> turn their argument into a lambda functor, that implements an identity mapping.
The former two are for constants, the latter for variables.
The 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 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">
@@ -509,13 +441,8 @@ This is accomplished with the <tt>constant</tt> function:
for_each(a.begin(), a.end(), cout &lt;&lt; constant(' ') &lt;&lt; _1);
</pre>
The call <tt>constant(' ')</tt> creates a nullary lambda functor which stores the character constant <tt>' '</tt>
and returns a reference to it when invoked.
The function <tt>constant_ref</tt> is similar, except that it
stores a constant reference to its argument.
The <tt>constant</tt> and <tt>consant_ref</tt> are only
needed when the operator call has side effects, like in the above example.
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.
</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:
@@ -528,15 +455,13 @@ for_each(a.begin(), a.end(), cout &lt;&lt; ++var(index) &lt;&lt; ':' &lt;&lt; _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="id2804083"></a>Naming delayed constants and variables</h4></div></div><p>
</p><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="id2803927"></a>Naming delayed constants and variables</h4></div></div><p>
It is possible to predefine and name a delayed variable or constant outside a lambda expression.
The templates <tt>var_type</tt>, <tt>constant_type</tt>
and <tt>constant_ref_type</tt> serve for this purpose.
The templates <tt>var_type</tt> and <tt>constant_type</tt> serve for this purpose.
They are used as:
<pre class="programlisting">
var_type&lt;T&gt;::type delayed_i(var(i));
@@ -562,7 +487,7 @@ Here is an example of naming a delayed constant:
constant_type&lt;char&gt;::type space(constant(' '));
for_each(a.begin(),a.end(), cout &lt;&lt; space &lt;&lt; _1);
</pre>
</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>
</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>
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.
@@ -594,7 +519,6 @@ 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)
@@ -603,21 +527,6 @@ 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.
@@ -631,29 +540,6 @@ 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 &lt;&lt; _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:
@@ -717,16 +603,10 @@ 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&lt;T&gt;(...)</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&lt;T&gt;(...)</tt> results in the catch block:
<pre class="programlisting">
catch(T&amp; e) { ... }
@@ -740,38 +620,24 @@ 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(&amp;std::exception::what, _e)</tt> creates the lambda
function for making that call.
<tt>bind(&amp;std::exception::what, _E)</tt> creates the lambda function for making that call.
Note that <tt>_e</tt> cannot be used outside of an exception handler lambda expression.
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.
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(),
@@ -783,7 +649,7 @@ for_each(
),
catch_exception&lt;std::exception&gt;(
cout &lt;&lt; constant(&quot;Caught std::exception: &quot;)
&lt;&lt; bind(&amp;std::exception::what, _e),
&lt;&lt; bind(&amp;std::exception::what, _E),
throw_exception(bind(constructor&lt;bar_exception&gt;(), _1)))
),
catch_all(
@@ -791,25 +657,13 @@ 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><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></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">
@@ -818,25 +672,12 @@ for_each(a, a+10, _1 = bind(new_ptr&lt;int&gt;()));
for_each(a, a+10, bind(delete_ptr(), _1));
</pre>
The <tt>new_ptr&lt;int&gt;()</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&lt;<i><tt>T</tt></i>&gt;()</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&lt;int&gt;()</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&lt;<i><tt>T</tt></i>&gt;()</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&lt;pair&lt;int, int&gt; &gt; v;
@@ -844,21 +685,15 @@ transform(x.begin(), x.end(), y.begin(), back_inserter(v),
bind(constructor&lt;pair&lt;int, int&gt; &gt;(), _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&lt;T&gt;()(<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.-&gt;A()</tt>, where <tt>pa</tt> is of type <tt>A*</tt></td></tr><tr><td><tt>new_ptr&lt;T&gt;()(<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&lt;T&gt;()(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.
This section describes the tools to prevent the substitution and
evaluation of a subexpression, and explains when these tools should be used.
</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&lt;T&gt;()(<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.-&gt;A()</tt>, where <tt>pa</tt> is of type <tt>A*</tt></td></tr><tr><td><tt>new_ptr&lt;T&gt;()(<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&lt;T&gt;()(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.
</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">
@@ -870,15 +705,9 @@ 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; }
@@ -893,13 +722,8 @@ bool condition; int i; int j;
bind(bind(&amp;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:
@@ -915,56 +739,31 @@ int nested(const F&amp; 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(&amp;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&lt;class F&gt;
int nested(const F&amp; f) {
@@ -975,40 +774,24 @@ int nested(const F&amp; f) {
}
</pre>
</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>
</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>
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;
@@ -1017,46 +800,27 @@ 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;
@@ -1066,38 +830,25 @@ 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="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.
</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.
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 {};
@@ -1109,15 +860,10 @@ int count = 0;
for_each(a.begin(), a.end(),
if_then(ll_dynamic_cast&lt;derived*&gt;(_1), ++var(count)));
</pre>
</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>.
</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>.
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">
@@ -1127,19 +873,12 @@ for_each(a.begin(), a.end(),
cout &lt;&lt; bind(&amp;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];
@@ -1151,15 +890,10 @@ 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">
@@ -1168,13 +902,7 @@ 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(),
@@ -1183,4 +911,4 @@ std::for_each(a.begin(), a.end(),
protect(sum += _1)));
</pre>
</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>
</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>

View File

@@ -7,108 +7,52 @@
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&lt;Action, A&gt;
</tt>
and
<tt>
return_type_1&lt;Action, A&gt;
</tt>, and
<tt>
plain_return_type_2&lt;Action, A, B&gt;
</tt>
and
<tt>
return_type_2&lt;Action, A, B&gt;
</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&lt;plus_action&gt;</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 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&lt;plus_action&gt;</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>.
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.
</p><p>
The latter parameters, <tt>A</tt> in the unary case,
or <tt>A</tt> and <tt>B</tt> in the binary case,
stand for the argument types of the operator call.
The two sets of templates,
<tt>plain_return_type_<i><tt>n</tt></i></tt> and
<tt>return_type_<i><tt>n</tt></i></tt>
(<i><tt>n</tt></i> is 1 or 2) differ in the way how parameter types
are presented to them.
For the former templates, the parameter types are always provided as
non-reference types, and do not have const or volatile qualifiers.
This makes specializing easy, as commonly one specialization for each
user defined operator, or operator group, is enough.
On the other hand, if a particular operator is overloaded for different
cv-qualifications of the same argument types,
and the return types of these overloaded versions differ, a more fine-grained control is needed.
Hence, for the latter templates, the parameter types preserve the
cv-qualifiers, and are non-reference types as well.
The downside is, that for an overloaded set of operators of the
kind described above, one may end up needing up to
16 <tt>return_type_2</tt> specializations.
</p><p>
Suppose the user has overloaded the following operators for some user defined
types <tt>X</tt>, <tt>Y</tt> and <tt>Z</tt>:
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&amp;, const Y&amp;);
Z operator-(const X&amp;, const Y&amp;);
</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 {
@@ -123,26 +67,17 @@ struct plain_return_type_2&lt;arithmetic_action&lt;Act&gt;, X, Y&gt; {
}
</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&amp;, const Y&amp;);
</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">
@@ -152,56 +87,38 @@ struct plain_return_type_2&lt;arithmetic_action&lt;multiply_action&gt;, X, Y&gt;
};
</pre>
</p><p>
The specializations can define arbitrary mappings from the argument types
to the return type.
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 &lt;class T&gt; class my_vector;</pre>
<pre class="programlisting">
template &lt;class T&gt; 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&lt;int&gt;</tt> and
<tt>my_vector&lt;double&gt;</tt> results in
<tt>my_vector&lt;double&gt;</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&lt;int&gt;</tt> and <tt>my_vector&lt;double&gt;</tt> results in <tt>my_vector&lt;double&gt;</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&lt;class A, class B&gt;
my_vector&lt;typename return_type_2&lt;arithmetic_action&lt;plus_action&gt;, A, B&gt;::type&gt;
my_vector&lt;typename return_type_2&lt;arithmetic_action&lt;plus_action&gt;, A&amp;, B&amp;&gt;::type&gt;
operator+(const my_vector&lt;A&gt;&amp; a, const my_vector&lt;B&gt;&amp; b)
{
typedef typename
return_type_2&lt;arithmetic_action&lt;plus_action&gt;, A, B&gt;::type res_type;
return_type_2&lt;arithmetic_action&lt;plus_action&gt;, A&amp;, B&amp;&gt;::type res_type;
return my_vector&lt;res_type&gt;();
}
</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&lt;class A, class B&gt;
class plain_return_type_2&lt;arithmetic_action&lt;plus_action&gt;,
my_vector&lt;A&gt;, my_vector&lt;B&gt; &gt; {
typedef typename
return_type_2&lt;arithmetic_action&lt;plus_action&gt;, A, B&gt;::type res_type;
return_type_2&lt;arithmetic_action&lt;plus_action&gt;, A&amp;, B&amp;&gt;::type res_type;
public:
typedef my_vector&lt;res_type&gt; type;
};
</pre>
Note, that we are reusing the existing specializations for the
BLL <tt>return_type_2</tt> template,
which require that the argument types are references.
</p><div class="table"><p><a name="table:actions"></a><b>Table 2. Action types</b></p><table summary="Action types" border="1"><colgroup><col><col></colgroup><tbody><tr><td><tt>+</tt></td><td><tt>arithmetic_action&lt;plus_action&gt;</tt></td></tr><tr><td><tt>-</tt></td><td><tt>arithmetic_action&lt;minus_action&gt;</tt></td></tr><tr><td><tt>*</tt></td><td><tt>arithmetic_action&lt;multiply_action&gt;</tt></td></tr><tr><td><tt>/</tt></td><td><tt>arithmetic_action&lt;divide_action&gt;</tt></td></tr><tr><td><tt>%</tt></td><td><tt>arithmetic_action&lt;remainder_action&gt;</tt></td></tr><tr><td><tt>+</tt></td><td><tt>unary_arithmetic_action&lt;plus_action&gt;</tt></td></tr><tr><td><tt>-</tt></td><td><tt>unary_arithmetic_action&lt;minus_action&gt;</tt></td></tr><tr><td><tt>&amp;</tt></td><td><tt>bitwise_action&lt;and_action&gt;</tt></td></tr><tr><td><tt>|</tt></td><td><tt>bitwise_action&lt;or_action&gt;</tt></td></tr><tr><td><tt>~</tt></td><td><tt>bitwise_action&lt;not_action&gt;</tt></td></tr><tr><td><tt>^</tt></td><td><tt>bitwise_action&lt;xor_action&gt;</tt></td></tr><tr><td><tt>&lt;&lt;</tt></td><td><tt>bitwise_action&lt;leftshift_action_no_stream&gt;</tt></td></tr><tr><td><tt>&gt;&gt;</tt></td><td><tt>bitwise_action&lt;rightshift_action_no_stream&gt;</tt></td></tr><tr><td><tt>&amp;&amp;</tt></td><td><tt>logical_action&lt;and_action&gt;</tt></td></tr><tr><td><tt>||</tt></td><td><tt>logical_action&lt;or_action&gt;</tt></td></tr><tr><td><tt>!</tt></td><td><tt>logical_action&lt;not_action&gt;</tt></td></tr><tr><td><tt>&lt;</tt></td><td><tt>relational_action&lt;less_action&gt;</tt></td></tr><tr><td><tt>&gt;</tt></td><td><tt>relational_action&lt;greater_action&gt;</tt></td></tr><tr><td><tt>&lt;=</tt></td><td><tt>relational_action&lt;lessorequal_action&gt;</tt></td></tr><tr><td><tt>&gt;=</tt></td><td><tt>relational_action&lt;greaterorequal_action&gt;</tt></td></tr><tr><td><tt>==</tt></td><td><tt>relational_action&lt;equal_action&gt;</tt></td></tr><tr><td><tt>!=</tt></td><td><tt>relational_action&lt;notequal_action&gt;</tt></td></tr><tr><td><tt>+=</tt></td><td><tt>arithmetic_assignment_action&lt;plus_action&gt;</tt></td></tr><tr><td><tt>-=</tt></td><td><tt>arithmetic_assignment_action&lt;minus_action&gt;</tt></td></tr><tr><td><tt>*=</tt></td><td><tt>arithmetic_assignment_action&lt;multiply_action&gt;</tt></td></tr><tr><td><tt>/=</tt></td><td><tt>arithmetic_assignment_action&lt;divide_action&gt;</tt></td></tr><tr><td><tt>%=</tt></td><td><tt>arithmetic_assignment_action&lt;remainder_action&gt;</tt></td></tr><tr><td><tt>&amp;=</tt></td><td><tt>bitwise_assignment_action&lt;and_action&gt;</tt></td></tr><tr><td><tt>=|</tt></td><td><tt>bitwise_assignment_action&lt;or_action&gt;</tt></td></tr><tr><td><tt>^=</tt></td><td><tt>bitwise_assignment_action&lt;xor_action&gt;</tt></td></tr><tr><td><tt>&lt;&lt;=</tt></td><td><tt>bitwise_assignment_action&lt;leftshift_action&gt;</tt></td></tr><tr><td><tt>&gt;&gt;=</tt></td><td><tt>bitwise_assignment_action&lt;rightshift_action&gt;</tt></td></tr><tr><td><tt>++</tt></td><td><tt>pre_increment_decrement_action&lt;increment_action&gt;</tt></td></tr><tr><td><tt>--</tt></td><td><tt>pre_increment_decrement_action&lt;decrement_action&gt;</tt></td></tr><tr><td><tt>++</tt></td><td><tt>post_increment_decrement_action&lt;increment_action&gt;</tt></td></tr><tr><td><tt>--</tt></td><td><tt>post_increment_decrement_action&lt;decrement_action&gt;</tt></td></tr><tr><td><tt>&amp;</tt></td><td><tt>other_action&lt;address_of_action&gt;</tt></td></tr><tr><td><tt>*</tt></td><td><tt>other_action&lt;contents_of_action&gt;</tt></td></tr><tr><td><tt>,</tt></td><td><tt>other_action&lt;comma_action&gt;</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 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&lt;plus_action&gt;</tt></td></tr><tr><td><tt>-</tt></td><td><tt>arithmetic_action&lt;minus_action&gt;</tt></td></tr><tr><td><tt>*</tt></td><td><tt>arithmetic_action&lt;multiply_action&gt;</tt></td></tr><tr><td><tt>/</tt></td><td><tt>arithmetic_action&lt;divide_action&gt;</tt></td></tr><tr><td><tt>%</tt></td><td><tt>arithmetic_action&lt;remainder_action&gt;</tt></td></tr><tr><td><tt>+</tt></td><td><tt>unary_arithmetic_action&lt;plus_action&gt;</tt></td></tr><tr><td><tt>-</tt></td><td><tt>unary_arithmetic_action&lt;minus_action&gt;</tt></td></tr><tr><td><tt>&amp;</tt></td><td><tt>bitwise_action&lt;and_action&gt;</tt></td></tr><tr><td><tt>|</tt></td><td><tt>bitwise_action&lt;or_action&gt;</tt></td></tr><tr><td><tt>~</tt></td><td><tt>bitwise_action&lt;not_action&gt;</tt></td></tr><tr><td><tt>^</tt></td><td><tt>bitwise_action&lt;xor_action&gt;</tt></td></tr><tr><td><tt>&lt;&lt;</tt></td><td><tt>bitwise_action&lt;leftshift_action_no_stream&gt;</tt></td></tr><tr><td><tt>&gt;&gt;</tt></td><td><tt>bitwise_action&lt;rightshift_action_no_stream&gt;</tt></td></tr><tr><td><tt>&amp;&amp;</tt></td><td><tt>logical_action&lt;and_action&gt;</tt></td></tr><tr><td><tt>||</tt></td><td><tt>logical_action&lt;or_action&gt;</tt></td></tr><tr><td><tt>!</tt></td><td><tt>logical_action&lt;not_action&gt;</tt></td></tr><tr><td><tt>&lt;</tt></td><td><tt>relational_action&lt;less_action&gt;</tt></td></tr><tr><td><tt>&gt;</tt></td><td><tt>relational_action&lt;greater_action&gt;</tt></td></tr><tr><td><tt>&lt;=</tt></td><td><tt>relational_action&lt;lessorequal_action&gt;</tt></td></tr><tr><td><tt>&gt;=</tt></td><td><tt>relational_action&lt;greaterorequal_action&gt;</tt></td></tr><tr><td><tt>==</tt></td><td><tt>relational_action&lt;equal_action&gt;</tt></td></tr><tr><td><tt>!=</tt></td><td><tt>relational_action&lt;notequal_action&gt;</tt></td></tr><tr><td><tt>+=</tt></td><td><tt>arithmetic_assignment_action&lt;plus_action&gt;</tt></td></tr><tr><td><tt>-=</tt></td><td><tt>arithmetic_assignment_action&lt;minus_action&gt;</tt></td></tr><tr><td><tt>*=</tt></td><td><tt>arithmetic_assignment_action&lt;multiply_action&gt;</tt></td></tr><tr><td><tt>/=</tt></td><td><tt>arithmetic_assignment_action&lt;divide_action&gt;</tt></td></tr><tr><td><tt>%=</tt></td><td><tt>arithmetic_assignment_action&lt;remainder_action&gt;</tt></td></tr><tr><td><tt>&amp;=</tt></td><td><tt>bitwise_assignment_action&lt;and_action&gt;</tt></td></tr><tr><td><tt>=|</tt></td><td><tt>bitwise_assignment_action&lt;or_action&gt;</tt></td></tr><tr><td><tt>^=</tt></td><td><tt>bitwise_assignment_action&lt;xor_action&gt;</tt></td></tr><tr><td><tt>&lt;&lt;=</tt></td><td><tt>bitwise_assignment_action&lt;leftshift_action&gt;</tt></td></tr><tr><td><tt>&gt;&gt;=</tt></td><td><tt>bitwise_assignment_action&lt;rightshift_action&gt;</tt></td></tr><tr><td><tt>++</tt></td><td><tt>pre_increment_decrement_action&lt;increment_action&gt;</tt></td></tr><tr><td><tt>--</tt></td><td><tt>pre_increment_decrement_action&lt;decrement_action&gt;</tt></td></tr><tr><td><tt>++</tt></td><td><tt>post_increment_decrement_action&lt;increment_action&gt;</tt></td></tr><tr><td><tt>--</tt></td><td><tt>post_increment_decrement_action&lt;decrement_action&gt;</tt></td></tr><tr><td><tt>&amp;</tt></td><td><tt>other_action&lt;address_of_action&gt;</tt></td></tr><tr><td><tt>*</tt></td><td><tt>other_action&lt;contents_of_action&gt;</tt></td></tr><tr><td><tt>,</tt></td><td><tt>other_action&lt;comma_action&gt;</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>

View File

@@ -5,99 +5,15 @@
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="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.
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.
Depending on the compiler, this can also be true in practice.
We ran two tests with the GCC 3.0.4 compiler on 1.5 GHz Intel Pentium 4.
The optimization flag -03 was used.
</p><p>
In the first test we compared lambda functors against explicitly written
function objects.
We used both of these styles to define unary functions which multiply the
argument repeatedly by itself.
We started with the identity function, going up to
x<sup>5</sup>.
The expressions were called inside a <tt>std::transform</tt> loop,
reading the argument from one <tt>std::vector&lt;int&gt;</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.
</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.
Note however, that evaluating a lambda functor consist of a sequence of calls to small functions that are declared inline.
If the compiler fails to actually expand these functions inline,
the performance can suffer.
The running time can more than double if this happens.
Although the above tests do not include such an expression, we have experiensed
this for some seemingly simple expressions.
<div class="table"><p><a name="table:increasing_arithmetic_test"></a><b>Table 3. Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
The running times are expressed in arbitrary units.</b></p><table summary="Test 1. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
The running times are expressed in arbitrary units." border="1"><colgroup><col><col><col></colgroup><thead><tr><th>expression</th><th>lambda expression</th><th>hand-coded function object</th></tr></thead><tbody><tr><td>x</td><td>240</td><td>230</td></tr><tr><td>x*x</td><td>340</td><td>350</td></tr><tr><td>x*x*x</td><td>770</td><td>760</td></tr><tr><td>x*x*x*x</td><td>1180</td><td>1210</td></tr><tr><td>x*x*x*x*x</td><td>1950</td><td>1910</td></tr></tbody></table></div>
</p><p>
<div class="table"><p><a name="table:ll_vs_stl_test"></a><b>Table 4. Test 2. CPU time of arithmetic expressions written as lambda
expressions, as classic STL unnamed functions (using <tt>compose2</tt>, <tt>bind1st</tt> etc.) and as traditional hand-coded function object classes.
Using BLL terminology,
<tt>a</tt> and <tt>b</tt> are bound arguments in the expressions, and <tt>x</tt> is open.
All variables were of types <tt>double</tt>.
The running times are expressed in arbitrary units.</b></p><table summary="Test 2. CPU time of arithmetic expressions written as lambda
expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional hand-coded function object classes.
Using BLL terminology,
a and b are bound arguments in the expressions, and x is open.
All variables were of types double.
The running times are expressed in arbitrary units." border="1"><colgroup><col><col><col><col></colgroup><thead><tr><th>expression</th><th>lambda expression</th><th>classic STL expression</th><th>hand-coded function object</th></tr></thead><tbody><tr><td>ax</td><td>330</td><td>370</td><td>290</td></tr><tr><td>-ax</td><td>350</td><td>370</td><td>310</td></tr><tr><td>ax-(a+x)</td><td>470</td><td>500</td><td>420</td></tr><tr><td>(ax-(a+x))(a+x)</td><td>620</td><td>670</td><td>600</td></tr><tr><td>((ax) - (a+x))(bx - (b+x))(ax - (b+x))(bx - (a+x))</td><td>1660</td><td>1660</td><td>1460</td></tr></tbody></table></div>
</p><p>Some additional performance testing with an earlier version of the
library is described
[<a href="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.
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.
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.
@@ -111,16 +27,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="id2808118"></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="id2807495"></a>7.3. Portability</h3></div></div><p>
The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL:
<div class="itemizedlist"><ul type="disc"><li>GCC 3.0.4
<div class="itemizedlist"><ul type="disc"><li>GCC 3.0.2
</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="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:
</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:
<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.

View File

@@ -5,68 +5,71 @@
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="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.
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.
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 arbitrary function objects, for example
lambda functors; 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 (almost) arbitrary function objects; and these wrappers have types that are easy to type out.
For example:
<pre class="programlisting">
boost::function&lt;int, int, int&gt; f = _1 + _2;
boost::function&lt;int&amp;, int&amp;&gt; g = unlambda(_1 += 10);
int i = 1, j = 2;
f(i); // returns 3
g(i); // sets i to = 11;
int foo(float, char);
boost::function&lt;int, float, char&gt; f = foo;
boost::function&lt;int, int, int&gt; g = std::plus&lt;int&gt;();
</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.
Note that storing lambda functors inside <tt>boost::function</tt>
introduces a danger.
Certain types of lambda functors may store references to the bound
arguments, instead as taking copies of the arguments of the lambda expression.
When temporary lambda functor objects are used
in STL algorithm invocations this is always safe, as the lambda functor gets
destructed immediately after the STL algortihm invocation is completed.
However, a lambda functor wrapped inside <tt>boost::function</tt>
may continue to exist longer, creating the possibility of dangling references.
</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&lt;int, int, int&gt; f = unlambda(_1 + _2);
f(1, 2); // returns 3
</pre>
<pre class="programlisting">
int i = 1;
boost::function&lt;int&amp;, int&amp;&gt; 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.
When temporary lambda functor objects are used
in STL algorithm invocations this is always safe, as the lambda functor gets destructed immediately after the STL algortihm invocation is completed.
However, a lambda functor wrapped inside <tt>boost::function</tt> may continue to exist longer, creating the possibility of dangling references.
For example:
<pre class="programlisting">
int* sum = new int();
*sum = 0;
boost::function&lt;int&amp;, int&gt; counter = *sum += _1;
boost::function&lt;int&amp;, int&gt; counter = unlambda(*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="id2808614"></a>8.2. Boost Bind</h3></div></div><p>
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2808050"></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 with
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 witha 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="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,
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,
as no argument substitution takes place within that argument.
In BLL the first argument is not a special case in this respect.
@@ -105,20 +108,36 @@ 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><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>
</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>

View File

@@ -5,12 +5,9 @@
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="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 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 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="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>
</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>

View File

@@ -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="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">
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">
<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 &#8211; 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,5 +15,4 @@
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::ref"></a><p>[ref] <span class="title"><I>Boost ref</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/ref.html" target="_top">www.boost.org/libs/bind/ref.html</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::bind"></a><p>[bind] <span class="title"><I>Boost Bind Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/bind.html" target="_top">www.boost.org/libs/bind/bind.html</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::function"></a><p>[function] <span class="title"><I>Boost Function Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/function/" target="_top">www.boost.org/libs/function/</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:fc++"></a><p>[fc++] <span class="title"><I>The FC++ library: Functional Programming in C++</I>. </span><span class="author">Yannis Smaragdakis. </span><span class="author">Brian McNamara. </span><span class="bibliomisc"><a href="http://www.cc.gatech.edu/~yannis/fc++/" target="_top">www.cc.gatech.edu/~yannis/fc++/</a>
. </span><span class="pubdate">2002. </span></p></div></div><div class="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>
. </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>

View File

@@ -1,7 +0,0 @@
- 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)

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
<?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>

View File

@@ -1,19 +0,0 @@
<?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>

View File

@@ -8,16 +8,14 @@
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="id2733457"></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="id2733458"></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#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>
</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>
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

View File

@@ -0,0 +1,82 @@
#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

View File

@@ -20,5 +20,5 @@
#include "boost/lambda/core.hpp"
#include "boost/lambda/detail/bind_functions.hpp"
#endif

View File

@@ -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,21 +91,28 @@ public:
// return types of casting lambda_functors (all "T" type.)
template<template <class> class cast_type, class T, class A>
struct return_type_N<cast_action< cast_type<T> >, A> {
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>
{
typedef T type;
};
// return type of typeid_action
template<class A>
struct return_type_N<typeid_action, A> {
template<class Args, int Code, class Open>
struct return_type<lambda_functor_args<action<1, typeid_action >, Args, Code>,
Open>
{
typedef std::type_info const & type;
};
// return type of sizeof_action
template<class A>
struct return_type_N<sizeof_action, A> {
template<class Args, int Code, class Open>
struct return_type<lambda_functor_args<action<1, sizeof_action >, Args, Code>,
Open >
{
typedef std::size_t type;
};
@@ -116,69 +123,85 @@ struct return_type_N<sizeof_action, A> {
// static_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_base<
action<1, cast_action<static_cast_action<T> > >,
tuple<typename const_copy_argument <const Arg1>::type>
lambda_functor_args<
action<1,
cast_action<static_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_static_cast(const Arg1& 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));
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));
}
// dynamic_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_base<
action<1, cast_action<dynamic_cast_action<T> > >,
tuple<typename const_copy_argument <const Arg1>::type>
lambda_functor_args<
action<1,
cast_action<dynamic_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_dynamic_cast(const Arg1& 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));
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));
}
// const_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_base<
action<1, cast_action<const_cast_action<T> > >,
tuple<typename const_copy_argument <const Arg1>::type>
lambda_functor_args<
action<1,
cast_action<const_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_const_cast(const Arg1& 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));
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));
}
// reinterpret_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_base<
action<1, cast_action<reinterpret_cast_action<T> > >,
tuple<typename const_copy_argument <const Arg1>::type>
lambda_functor_args<
action<1,
cast_action<reinterpret_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_reinterpret_cast(const Arg1& 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));
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));
}
// typeid
@@ -186,36 +209,44 @@ ll_reinterpret_cast(const Arg1& a1) {
// class object)
template <class Arg1>
inline const lambda_functor<
lambda_functor_base<
action<1, typeid_action>,
tuple<typename const_copy_argument <const Arg1>::type>
lambda_functor_args<
action<1,
typeid_action
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_typeid(const Arg1& 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));
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));
}
// sizeof(expression)
// Always takes a lambda expression (if not, built in sizeof will do)
template <class Arg1>
inline const lambda_functor<
lambda_functor_base<
lambda_functor_args<
action<1, sizeof_action>,
tuple<lambda_functor<Arg1> >
tuple<lambda_functor<Arg1> >,
dig_arity<Arg1>::value
>
>
ll_sizeof(const lambda_functor<Arg1>& a1) {
return
lambda_functor_base<
lambda_functor<
lambda_functor_args<
action<1, sizeof_action>,
tuple<lambda_functor<Arg1> >
tuple<lambda_functor<Arg1> >,
dig_arity<Arg1>::value
>
( tuple<lambda_functor<Arg1> >(a1));
>
( tuple<lambda_functor<Arg1> >(a1));
}
} // namespace lambda

View File

@@ -1,289 +0,0 @@
/*=============================================================================
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

View File

@@ -28,7 +28,7 @@ namespace lambda {
template<class T> struct constructor {
template <class U> struct sig { typedef T type; };
typedef T result_type;
T operator()() const {
return T();
@@ -120,8 +120,8 @@ struct destructor_helper<true> {
// destructor funtion object
struct destructor {
template <class T> struct sig { typedef void type; };
typedef void result_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 {
template <class U> struct sig { typedef T* type; };
typedef T* result_type;
T* operator()() const {
return new T();
@@ -199,7 +199,7 @@ template<class T> struct new_ptr {
struct delete_ptr {
template <class U> struct sig { typedef void type; };
typedef void result_type;
template <class A1>
void operator()(A1& a1) const {
@@ -213,7 +213,7 @@ struct delete_ptr {
template<class T> struct new_array {
template <class U> struct sig { typedef T* type; };
typedef T* result_type;
T* operator()(int size) const {
return new T[size];
@@ -225,7 +225,7 @@ template<class T> struct new_array {
struct delete_array {
template <class U> struct sig { typedef void type; };
typedef void result_type;
template <class A1>
void operator()(A1& a1) const {

View File

@@ -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

View File

@@ -36,6 +36,7 @@ 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"
@@ -46,20 +47,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 {
// 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 free1;
boost::lambda::placeholder2_type free2;
boost::lambda::placeholder3_type free3;
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

View File

@@ -23,7 +23,7 @@ namespace lambda {
template<int Arity, class Act> class action;
template<int Arity, class Act> struct action;
// these need to be defined here, since the corresponding lambda
// functions are members of lambda_functor classes
@@ -31,38 +31,27 @@ template<int Arity, class Act> class 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 {};
}
@@ -72,15 +61,18 @@ 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_cv<A1>::type>::
template apply<RET>(a1);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>(a1);
}
};
@@ -88,17 +80,23 @@ 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_cv<A1>::type>::
template apply<RET>(a1, a2);
return function_adaptor<typename boost::remove_const<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_cv<A1>::type>::
template apply<RET>(a1, a2, a3);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3);
}
};
@@ -106,8 +104,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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4);
}
};
@@ -115,8 +113,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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4, a5);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5);
}
};
@@ -125,8 +123,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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4, a5, a6);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6);
}
};
@@ -135,8 +133,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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4, a5, a6, a7);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7);
}
};
@@ -146,8 +144,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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4, a5, a6, a7, a8);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7, a8);
}
};
@@ -157,8 +155,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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4, a5, a6, a7, a8, a9);
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
};
@@ -168,11 +166,32 @@ 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_cv<A1>::type>::
template apply<RET>(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
return function_adaptor<typename boost::remove_const<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

View File

@@ -32,80 +32,93 @@ 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};
template<class T>
struct get_tuple_arity;
// -- dig the arity from lambda_functor_args;
template <class T> struct dig_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);
};
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);
// The implementation template, do not instantiate this directly
template <class Arg> struct dig_arity_ {
static const int value = NONE;
};
template<>
struct get_tuple_arity<null_type> {
BOOST_STATIC_CONSTANT(int, value = 0);
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
};
// 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 <class Act, class Args, int ArityCode>
struct dig_arity_<lambda_functor_args<Act, Args, ArityCode> >{
static const int value = ArityCode;
};
template<int I, int J>
struct lacks_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);
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +0,0 @@
// 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

View File

@@ -25,35 +25,36 @@ 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 ----------------------
// -- nonvoid return control actions ----------------------
class ifthenelsereturn_action {};
// For loop
template <class Arg1, class Arg2, class Arg3, class Arg4>
inline const
lambda_functor<
lambda_functor_base<
forloop_action,
lambda_functor_args<
action<4, return_void_action<forloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3>, lambda_functor<Arg4> >
lambda_functor<Arg3>, lambda_functor<Arg4> >,
combine_arities<Arg1, Arg2, Arg3, Arg4>::value
>
>
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,
lambda_functor<
lambda_functor_args<
action<4, return_void_action<forloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3>, lambda_functor<Arg4> >
lambda_functor<Arg3>, lambda_functor<Arg4> >,
combine_arities<Arg1, Arg2, Arg3, Arg4>::value
>
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3>, lambda_functor<Arg4> >(a1, a2, a3, a4)
);
@@ -63,20 +64,23 @@ 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_base<
forloop_no_body_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
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
>
>
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,
lambda_functor<
lambda_functor_args<
action<3, return_void_action<forloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3> >
lambda_functor<Arg3> >,
combine_arities<Arg1, Arg2, Arg3>::value
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
lambda_functor<Arg3> >(a1, a2, a3) );
}
@@ -84,36 +88,42 @@ for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_base<
whileloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
lambda_functor_args<
action<2, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
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> >
lambda_functor<
lambda_functor_args<
action<2, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
( 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_base<
whileloop_no_body_action,
tuple<lambda_functor<Arg1> >
lambda_functor_args<
action<1, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
>
while_loop(const lambda_functor<Arg1>& a1) {
return
lambda_functor_base<
whileloop_no_body_action,
tuple<lambda_functor<Arg1> >
lambda_functor<
lambda_functor_args<
action<1, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
( tuple<lambda_functor<Arg1> >(a1) );
> ( tuple<lambda_functor<Arg1> >(a1) );
}
@@ -121,36 +131,42 @@ while_loop(const lambda_functor<Arg1>& a1) {
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_base<
dowhileloop_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
lambda_functor_args<
action<2, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
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> >
lambda_functor<
lambda_functor_args<
action<2, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
( 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_base<
dowhileloop_no_body_action,
tuple<lambda_functor<Arg1> >
lambda_functor_args<
action<1, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
>
do_while_loop(const lambda_functor<Arg1>& a1) {
return
lambda_functor_base<
dowhileloop_no_body_action,
tuple<lambda_functor<Arg1> >
lambda_functor<
lambda_functor_args<
action<1, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
( tuple<lambda_functor<Arg1> >(a1));
> ( tuple<lambda_functor<Arg1> >(a1));
}
@@ -158,18 +174,20 @@ do_while_loop(const lambda_functor<Arg1>& a1) {
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_base<
ifthen_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
lambda_functor_args<
action<2, return_void_action<ifthen_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
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> >
lambda_functor<
lambda_functor_args<action<2, return_void_action<ifthen_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
}
// If then else
@@ -177,17 +195,21 @@ 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_base<
ifthenelse_action,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
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
>
>
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> >
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
>
>
(tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >
(a1, a2, a3) );
@@ -198,25 +220,28 @@ 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_base<
other_action<ifthenelsereturn_action>,
tuple<lambda_functor<Arg1>,
lambda_functor_args<action<3, other_action<ifthenelsereturn_action> >,
tuple<lambda_functor<Arg1>,
typename const_copy_argument<Arg2>::type,
typename const_copy_argument<Arg3>::type>
typename const_copy_argument<Arg3>::type>,
combine_arities<Arg1, Arg2, Arg3>::value
>
>
if_then_else_return(const lambda_functor<Arg1>& a1,
const Arg2 & a2,
const Arg3 & a3) {
const Arg2 & a2,
const Arg3 & a3) {
return
lambda_functor_base<
other_action<ifthenelsereturn_action>,
lambda_functor<
lambda_functor_args<
action<3, 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<Arg3>::type>,
combine_arities<Arg1, Arg2, Arg3>::value
>
> ( 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 {
@@ -271,7 +296,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;
};
@@ -367,6 +392,25 @@ 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 -----------
@@ -379,38 +423,36 @@ struct return_type_2<other_action<ifthenelsereturn_action>, A, B> {
// Specialization for for_loop.
template<class Args>
class
lambda_functor_base<forloop_action, Args> {
lambda_functor_base<action<4, return_void_action<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))
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))
detail::select(boost::tuples::get<3>(args), CALL_ACTUAL_ARGS);
detail::select(boost::tuples::get<3>(args), a, b, c);
}
};
// No body case
template<class Args>
class
lambda_functor_base<forloop_no_body_action, Args> {
lambda_functor_base<action<3, return_void_action<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)) {}
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)) {}
}
};
@@ -418,34 +460,32 @@ public:
// Specialization for while_loop.
template<class Args>
class
lambda_functor_base<whileloop_action, Args> {
lambda_functor_base<action<2, return_void_action<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))
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))
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
detail::select(boost::tuples::get<1>(args), a, b, c);
}
};
// No body case
template<class Args>
class
lambda_functor_base<whileloop_no_body_action, Args> {
lambda_functor_base<action<1, return_void_action<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)) {}
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)) {}
}
};
@@ -453,34 +493,32 @@ public:
// Note that the first argument is the condition.
template<class Args>
class
lambda_functor_base<dowhileloop_action, Args> {
lambda_functor_base<action<2, return_void_action<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 {
template<class RET, class A, class B, class C>
RET call(A& a, B& b, C& c) const {
do {
detail::select(boost::tuples::get<1>(args), CALL_ACTUAL_ARGS);
} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
detail::select(boost::tuples::get<1>(args), a, b, c);
} while (detail::select(boost::tuples::get<0>(args), a, b, c) );
}
};
// No body case
template<class Args>
class
lambda_functor_base<dowhileloop_no_body_action, Args> {
lambda_functor_base<action<1, return_void_action<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 {} while (detail::select(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS) );
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) );
}
};
@@ -488,64 +526,51 @@ public:
// Specialization for if_then.
template<class Args>
class
lambda_functor_base<ifthen_action, Args> {
lambda_functor_base<action<2, return_void_action<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);
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);
}
};
// Specialization for if_then_else.
template<class Args>
class
lambda_functor_base<ifthenelse_action, Args> {
lambda_functor_base<action<3, return_void_action<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);
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);
else
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
detail::select(boost::tuples::get<2>(args), a, b, c);
}
};
// Specialization of lambda_functor_base for if_then_else_return.
template<class Args>
class
lambda_functor_base<other_action<ifthenelsereturn_action>, Args> {
lambda_functor_base<action<3, 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)
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)
:
detail::select(boost::tuples::get<2>(args), CALL_ACTUAL_ARGS);
detail::select(boost::tuples::get<2>(args), a, b, c);
}
};

View File

@@ -24,18 +24,7 @@ namespace lambda {
template <class Func> struct function_adaptor {
// 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;
};
typedef detail::unspecified type;
template<class RET, class A1>
static RET apply(A1& a1) {
@@ -87,77 +76,11 @@ 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)> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET>
static Result apply(Result (*func)()) {
return func();
@@ -166,8 +89,7 @@ struct function_adaptor<Result (void)> {
template <class Result>
struct function_adaptor<Result (*)(void)> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET>
static Result apply(Result (*func)()) {
return func();
@@ -178,8 +100,7 @@ struct function_adaptor<Result (*)(void)> {
// -- function adaptors with 2 argument apply
template <class Object, class Result>
struct function_adaptor<Result (Object::*)() const> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET>
static Result apply( Result (Object::*func)() const, const Object* o) {
return (o->*func)();
@@ -192,8 +113,7 @@ struct function_adaptor<Result (Object::*)() const> {
template <class Object, class Result>
struct function_adaptor<Result (Object::*)()> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET>
static Result apply( Result (Object::*func)(), Object* o) {
return (o->*func)();
@@ -206,8 +126,7 @@ struct function_adaptor<Result (Object::*)()> {
template <class Arg1, class Result>
struct function_adaptor<Result (Arg1)> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET, class A1>
static Result apply(Result (*func)(Arg1), A1& a1) {
return func(a1);
@@ -216,8 +135,7 @@ struct function_adaptor<Result (Arg1)> {
template <class Arg1, class Result>
struct function_adaptor<Result (*)(Arg1)> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET, class A1>
static Result apply(Result (*func)(Arg1), A1& a1) {
return func(a1);
@@ -228,24 +146,20 @@ 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> {
template<class T> struct sig { typedef Result type; };
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)> {
template<class T> struct sig { typedef Result type; };
typedef Result type;
template <class RET, class A1>
static Result apply( Result (Object::*func)(Arg1), Object* o, A1& a1) {
return (o->*func)(a1);
@@ -258,8 +172,7 @@ struct function_adaptor<Result (Object::*)(Arg1)> {
template <class Arg1, class Arg2, class Result>
struct function_adaptor<Result (Arg1, Arg2)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -268,8 +181,7 @@ struct function_adaptor<Result (Arg1, Arg2)> {
template <class Arg1, class Arg2, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -280,8 +192,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -294,8 +205,7 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2) const> {
template <class Object, class Arg1, class Arg2, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -308,8 +218,7 @@ struct function_adaptor<Result (Object::*)(Arg1, Arg2)> {
template <class Arg1, class Arg2, class Arg3, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -318,8 +227,7 @@ struct function_adaptor<Result (Arg1, Arg2, Arg3)> {
template <class Arg1, class Arg2, class Arg3, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -330,8 +238,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -344,7 +251,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);
@@ -357,8 +264,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -367,8 +273,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -379,8 +284,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -393,8 +297,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -407,8 +310,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -417,8 +319,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -429,8 +330,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -443,8 +343,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -457,8 +356,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -467,8 +365,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -479,8 +376,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -493,8 +389,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -507,8 +402,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -517,8 +411,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -529,8 +422,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -543,8 +435,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -557,8 +448,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -567,8 +457,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -579,8 +468,7 @@ 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> {
template<class T> struct sig { typedef Result type; };
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);
@@ -593,8 +481,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -607,8 +494,7 @@ 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)> {
template<class T> struct sig { typedef Result type; };
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);
@@ -617,13 +503,83 @@ 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

View File

@@ -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); \
};

View File

@@ -27,15 +27,12 @@
#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
#define BOOST_NO_FDECL_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMS
# if defined __KCC
#define BOOST_NO_FORWARD_DECLARADED_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMETERS
#endif // __KCC

View File

@@ -21,239 +21,32 @@
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 constify_rvals<T>::go(x)
// x should be of type T. If T is a non-reference type, do
// In a call make_rvalues_const<T>::exec(x)
// x should be of type T. If T is a non-reference type, exec
// 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 constify_rvals {
template <class T> struct make_rvalues_const {
template<class U>
static inline const U& go(const U& u) { return u; }
static const U& exec(const U& u) { return u; }
};
template <class T> struct constify_rvals<T&> {
template <class T> struct make_rvalues_const<T&> {
template<class U>
static inline U& go(U& u) { return u; }
static U& exec(U& u) { return u; }
};
// 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 <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;
};
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
@@ -262,26 +55,28 @@ template<int N> struct element_or_null<N, null_type> {
// the explicit_return_type_action case -----------------------------------
template<class RET, class Args>
class lambda_functor_base<explicit_return_type_action<RET>, Args>
class lambda_functor_base<action<1, 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 SigArgs> struct sig { typedef RET type; };
template<class RET_, CALL_TEMPLATE_ARGS>
RET call(CALL_FORMAL_ARGS) const
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?
{
return detail::constify_rvals<RET>::go(
detail::r_select<RET>::go(boost::tuples::get<0>(args), CALL_ACTUAL_ARGS));
return detail::make_rvalues_const<RET>::exec(
detail::ret_selector<RET>::select(boost::tuples::get<0>(args), a, b, c));
}
};
// the protect_action case -----------------------------------
template<class Args>
class lambda_functor_base<protect_action, Args>
class lambda_functor_base<action<1, protect_action >, Args>
{
public:
Args args;
@@ -289,308 +84,280 @@ public:
explicit lambda_functor_base(const Args& a) : args(a) {}
template<class RET, CALL_TEMPLATE_ARGS>
RET call(CALL_FORMAL_ARGS) const
template<class RET, class A, class B, class C>
RET call(A& a, B& b, C& c) 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<do_nothing_action, Args> {
// Args args;
class lambda_functor_base<action<3, curry_action<1> >, Args>
{
public:
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, CALL_TEMPLATE_ARGS> RET call(CALL_FORMAL_ARGS) const {
CALL_USE_ARGS;
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 SigArgs> struct sig { typedef void type; };
};
// 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:
explicit lambda_functor_base(const Args& a) : args(a) {}
// 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
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);
}
};
// The return type is queried as:
// return_type_N<X, EvaluatedArgumentTypes>::type
// for which there must be a specialization.
// 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:
// Function actions, casts, throws,... all go via these classes.
explicit lambda_functor_base(const Args& a) : 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>();
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);
}
};
#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;
#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>(
);
}
};
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(1)
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 detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
return Act::template apply<RET>(
constify_rvals<rt0>::go(r_select<rt0>::go(get<0>(args), CALL_ACTUAL_ARGS))
return Act::template apply<RET>(
detail::make_rvalues_const<ret0>::exec(detail::ret_selector<ret0>::select(boost::tuples::get<0>(args), a, b, c))
);
}
};
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;
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))
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))
);
}
};
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;
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))
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))
);
}
};
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(4)
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 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;
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))
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))
);
}
};
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(5)
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 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;
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))
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))
);
}
};
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(6)
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 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;
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))
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))
);
}
};
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(7)
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 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;
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))
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))
);
}
};
BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART(8)
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 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;
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))
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))
);
}
};
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;
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))
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))
);
}
};
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;
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))
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))
);
}
};

View File

@@ -34,180 +34,554 @@ namespace {
} // unnamed
} // detail
class unused {};
#define const_null_type() detail::constant_null_type
#define cnull_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
};
// -- free variables types --------------------------------------------------
// 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 {
// 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
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;
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;
};
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;
// 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));
}
};
template<> struct placeholder<SECOND> {
// ------------------------------------------------------------------------
// 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 SigArgs> struct sig {
typedef typename detail::get_element_or_null_type<1, SigArgs>::type type;
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;
};
template<class RET, CALL_TEMPLATE_ARGS>
RET call(CALL_FORMAL_ARGS) const { CALL_USE_ARGS; return b; }
// 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);
}
};
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; }
};
// -- free variables types --------------------------------------------------
template <int I> class placeholder {};
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;
// -- lambda_functor NONE ------------------------------------------------
template <class T>
class lambda_functor : public T
template<class Tag, class Args>
class tagged_lambda_functor<Tag, lambda_functor<Args> >
: public lambda_functor<Args>
{
BOOST_STATIC_CONSTANT(int, arity_bits = get_arity<T>::value);
public:
typedef T inherited;
template<class T>
tagged_lambda_functor(const lambda_functor<T>& a)
: lambda_functor<Args>(a) {}
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 ) );
}
// only works for the no body case.
explicit tagged_lambda_functor() : lambda_functor<Args>( null_type() ) {}
};
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_ADDRESSOF
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
} // namespace lambda
} // namespace boost

View File

@@ -28,16 +28,26 @@ template<class T> struct generate_error;
}
// -- placeholders --------------------------------------------
template <int I> struct placeholder;
template <int I> class 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 Base>
class lambda_functor;
template <class BinderArgs>
struct lambda_functor;
template <class Action,
class Args,
int ArityCode>
class lambda_functor_args;
template <class Act, class Args>
class lambda_functor_base;
@@ -46,34 +56,4 @@ 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

View File

@@ -58,9 +58,6 @@ 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
@@ -106,11 +103,13 @@ 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
>::non_const_type type;
>::const_type type;
};
// returns the cv and reverence stripped type of a tuple element
@@ -168,8 +167,7 @@ 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
@@ -216,28 +214,6 @@ 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
@@ -276,27 +252,15 @@ template<class T, int n> struct const_copy_argument <volatile T[n]> {
};
template<class T>
struct const_copy_argument<T&> {};
// do not instantiate with references
// typedef typename detail::generate_error<T&>::references_not_allowed type;
struct const_copy_argument<T&> {
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&,
@@ -509,9 +473,10 @@ class bind_type_generator {
public:
typedef
lambda_functor<
lambda_functor_base<
lambda_functor_args<
action_type,
args_t
args_t,
combine_arities<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value
>
> type;
@@ -529,4 +494,4 @@ template <class T> inline const T& make_const(const T& t) { return t; }
#endif // BOOST_LAMBDA_TRAITS_HPP
#endif // BOOST_LAMBDA_TRAITS_HPP

View File

@@ -0,0 +1,117 @@
// -- 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

View File

@@ -22,10 +22,6 @@
namespace boost {
namespace lambda {
class member_pointer_action {};
namespace detail {
// the boost type_traits member_pointer traits are not enough,
@@ -511,7 +507,6 @@ 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;
@@ -519,22 +514,14 @@ 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 type0;
// we remove the reference now, as we may have to add cv:s
typedef typename boost::remove_reference<type0>::type type1;
typedef typename detail::member_pointer<plainB>::type type1;
// 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
typedef typename ::boost::remove_pointer<A>::type non_pointer_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
@@ -549,7 +536,6 @@ public:
typename ::boost::add_volatile<type2>::type,
type2
>::RET type3;
// add reference back
typedef typename ::boost::add_reference<type3>::type type;
};
};
@@ -565,14 +551,9 @@ 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 typename plain_return_type_2<
other_action<member_pointer_action>, A, B
>::type type;
typedef detail::unspecified type;
};
};
@@ -593,30 +574,21 @@ struct member_pointer_action_helper<false, true> {
typedef typename ::boost::remove_cv<B>::type plainB;
typedef typename detail::member_pointer<plainB>::type ret_t;
// 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);
return detail::member_pointer_caller<ret_t, A&, 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;
// 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;
typedef detail::member_pointer_caller<ret_t, A, B> type;
};
};
} // detail
class member_pointer_action {};
template<> class other_action<member_pointer_action> {
public:
template<class RET, class A, class B>
@@ -650,13 +622,14 @@ 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;
public:
typedef typename
detail::member_pointer<plainB>::qualified_class_type B_class;
typedef typename
detail::member_pointer_action_helper<
detail::member_pointer<plainB>::is_data_member,
@@ -664,74 +637,69 @@ public:
>::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_base<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>,
combine_arities<Arg1, Arg2>::value
>
>
operator->*(const lambda_functor<Arg1>& a1, const Arg2& a2)
{
return
lambda_functor_base<
lambda_functor<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>,
combine_arities<Arg1, Arg2>::value
>
(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_base<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
operator->*(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2)
{
return
lambda_functor_base<
lambda_functor<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
(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_base<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
operator->*(const Arg1& a1, const lambda_functor<Arg2>& a2)
{
return
lambda_functor_base<
lambda_functor<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
(tuple<typename const_copy_argument<Arg1>::type,
> (tuple<typename const_copy_argument<Arg1>::type,
lambda_functor<Arg2> >(a1, a2));
}

View File

@@ -57,6 +57,8 @@ class decrement_action {};
// -- void return ------------------------------
class do_nothing_action {};
// -- other ------------------------------
class addressof_action {};
@@ -78,67 +80,122 @@ 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
// actions, for which the existence of protect is checked in return type
// deduction.
#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; }\
};\
\
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);
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 <> 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);
// 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<subscript_action> > {
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<> struct is_protectable<other_action<assignment_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)
// NOTE: comma action is also protectable, but the specialization is
// in actions.hpp
#if defined BOOST_LAMBDA_PREFIX_UNARY_ACTION
#error "Multiple defines of BOOST_LAMBDA_PREFIX_UNARY_ACTION"
#endif
#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

View File

@@ -1,276 +0,0 @@
// 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

View File

@@ -0,0 +1,77 @@
// 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

View File

@@ -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,9 +139,14 @@ 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
// their argument by default as a non-const reference
// prefix increment and decrement operators return the default is
// a non-const reference
template<class Act, class A>
struct plain_return_type_1<pre_increment_decrement_action<Act>, A> {
typedef A& type;
@@ -224,12 +229,6 @@ 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
@@ -298,7 +297,6 @@ 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>,
@@ -313,7 +311,10 @@ struct return_type_1<other_action<contentsof_action>, A> {
detail::contentsof_type<
typename boost::remove_reference<A>::type
>,
detail::identity_mapping<type1>
plain_return_type_1<
other_action<contentsof_action>,
typename detail::remove_reference_and_cv<A>::type
>
>::type type;
};
@@ -490,22 +491,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;
};
@@ -562,17 +563,22 @@ 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,
std::ostream&,
>::value,
#else
is_instance_of_2<
typename boost::remove_reference<A>::type,
std::basic_ostream
>::value,
#endif
A, //reference to the stream
typename detail::remove_reference_and_cv<A>::type
>::RET type;
};
@@ -581,55 +587,22 @@ 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,
std::istream&,
#else
is_instance_of_2<
typename boost::remove_reference<A>::type,
std::basic_istream
>::value,
#endif
A, //reference to the stream
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
@@ -709,8 +682,8 @@ struct return_type_2<relational_action<Act>, A, B> {
};
// Assingment actions -----------------------------------------------
// return type is the type of the first argument as reference
// return type is the type of the first argument
// (note: other templates guarantee that it is a referece).
// note that cv-qualifiers are preserved.
// Yes, assignment operator can be const!
@@ -730,7 +703,7 @@ struct return_type_2<arithmetic_assignment_action<Act>, A, B> {
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
typename boost::add_reference<A>::type,
A,
type1
>::RET type;
};
@@ -749,7 +722,7 @@ struct return_type_2<bitwise_assignment_action<Act>, A, B> {
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
typename boost::add_reference<A>::type,
A,
type1
>::RET type;
};
@@ -767,7 +740,7 @@ struct return_type_2<other_action<assignment_action>, A, B> {
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
typename boost::add_reference<A>::type,
A,
type1
>::RET type;
};
@@ -777,22 +750,26 @@ 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! 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)
// NOTE! A and B in comma_action can be non-reference types 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 type;
};
>::type type1;
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
B,
type1
>::RET type;
};
// subscript action -----------------------------------------------

View File

@@ -15,121 +15,117 @@
// ---------------------------------------------------------------
#ifndef BOOST_LAMBDA_OPERATORS_HPP
#define BOOST_LAMBDA_OPERATORS_HPP
#ifndef BOOST_LAMBDA_BINARY_EXPRESSIONS_HPP
#define BOOST_LAMBDA_BINARY_EXPRESSIONS_HPP
#include "boost/lambda/detail/is_instance_of.hpp"
namespace boost {
namespace lambda {
#if defined BOOST_LAMBDA_BE1
#error "Multiple defines of BOOST_LAMBDA_BE1"
#if defined BOOST_LAMBDA_BINARY_EXPRESSION1
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION1"
#endif
#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)); \
}
#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)\
);\
}\
\
#if defined BOOST_LAMBDA_BE2
#error "Multiple defines of BOOST_LAMBDA_BE2"
#if defined BOOST_LAMBDA_BINARY_EXPRESSION2
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION2"
#endif
#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)); \
}
#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)\
);\
}\
\
#if defined BOOST_LAMBDA_BE3
#error "Multiple defines of BOOST_LAMBDA_BE3"
#if defined BOOST_LAMBDA_BINARY_EXPRESSION3
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION3"
#endif
#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)); \
}
#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)\
);\
}\
\
#if defined BOOST_LAMBDA_BE
#error "Multiple defines of BOOST_LAMBDA_BE"
#if defined BOOST_LAMBDA_BINARY_EXPRESSION
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION"
#endif
#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)
#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)
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_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_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)
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)
// A special trick for comma operator for correct preprocessing
@@ -139,9 +135,9 @@ BOOST_LAMBDA_BE(operator^=, bitwise_assignment_action<xor_action>, , const, refe
#define BOOST_LAMBDA_COMMA_OPERATOR_NAME operator,
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)
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)
@@ -197,8 +193,8 @@ template<class T> struct convert_istream_to_ref_others_to_c_plain_by_default {
} // detail
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)
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)
// special case for io_manipulators.
@@ -209,37 +205,43 @@ BOOST_LAMBDA_BE2(operator>>, bitwise_action< rightshift_action>, , const, detail
template<class Arg, class Ret, class ManipArg>
inline const
lambda_functor<
lambda_functor_base<
bitwise_action<leftshift_action>,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
lambda_functor_args<
action<2, bitwise_action<leftshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
>
operator<<(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
{
return
lambda_functor_base<
bitwise_action<leftshift_action>,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
lambda_functor<
lambda_functor_args<
action<2, bitwise_action<leftshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
( 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_base<
bitwise_action<rightshift_action>,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
lambda_functor_args<
action<2, bitwise_action<rightshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
>
operator>>(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
{
return
lambda_functor_base<
bitwise_action<rightshift_action>,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>
lambda_functor<
lambda_functor_args<
action<2, bitwise_action<rightshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
> ( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
}
@@ -249,115 +251,123 @@ 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_E1
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_E1"
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1"
#endif
#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)); \
}
#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)\
);\
}\
\
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_E2
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_E2"
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2"
#endif
#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)); \
}
#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)
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>)
//BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(operator-, arithmetic_action<minus_action>)
// This is not needed, since the result of ptr-ptr is an rvalue anyway
BOOST_LAMBDA_PTR_ARITHMETIC_E2(operator-, arithmetic_action<minus_action>, )
BOOST_LAMBDA_PTR_ARITHMETIC_E2(operator-, arithmetic_action<minus_action>, const)
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator-, arithmetic_action< minus_action>, )
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator-, arithmetic_action< minus_action>, const)
#undef BOOST_LAMBDA_BE1
#undef BOOST_LAMBDA_BE2
#undef BOOST_LAMBDA_BE3
#undef BOOST_LAMBDA_BE
#undef BOOST_LAMBDA_BINARY_EXPRESSION1
#undef BOOST_LAMBDA_BINARY_EXPRESSION2
#undef BOOST_LAMBDA_BINARY_EXPRESSION3
#undef BOOST_LAMBDA_BINARY_EXPRESSION
#undef BOOST_LAMBDA_COMMA_OPERATOR_NAME
#undef BOOST_LAMBDA_PTR_ARITHMETIC_E1
#undef BOOST_LAMBDA_PTR_ARITHMETIC_E2
#undef BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1
#undef BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2
// ---------------------------------------------------------------------
// unary operators -----------------------------------------------------
// ---------------------------------------------------------------------
#if defined BOOST_LAMBDA_UE
#error "Multiple defines of BOOST_LAMBDA_UE"
#if defined BOOST_LAMBDA_UNARY_EXPRESSION
#error "Multiple defines of BOOST_LAMBDA_UNARY_EXPRESSION"
#endif
#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) ); \
}
#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) );\
}\
\
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>)
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"
#if defined BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION
#error "Multiple defines of BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION"
#endif
#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) ); \
}
#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) );\
}\
\
BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(operator++, post_increment_decrement_action<increment_action>)
BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(operator--, post_increment_decrement_action<decrement_action>)
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
#undef BOOST_LAMBDA_UNARY_EXPRESSION
#undef BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION
} // namespace lambda
} // namespace boost

View File

@@ -43,19 +43,22 @@ namespace lambda {
template<class RET, class Arg>
inline const
lambda_functor<
lambda_functor_base<
explicit_return_type_action<RET>,
tuple<lambda_functor<Arg> >
lambda_functor_args<
action<1, explicit_return_type_action<RET> >,
tuple<lambda_functor<Arg> >,
dig_arity<Arg>::value
>
>
ret(const lambda_functor<Arg>& a1)
{
return
lambda_functor_base<
explicit_return_type_action<RET>,
tuple<lambda_functor<Arg> >
>
(tuple<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));
}
// protect ------------------
@@ -67,21 +70,101 @@ inline const T& protect(const T& t) { return t; }
template<class Arg>
inline const
lambda_functor<
lambda_functor_base<
protect_action,
tuple<lambda_functor<Arg> >
lambda_functor_args<
action<1, protect_action>,
tuple<lambda_functor<Arg> >,
NONE
>
>
protect(const lambda_functor<Arg>& a1)
{
return
lambda_functor_base<
protect_action,
tuple<lambda_functor<Arg> >
return lambda_functor<
lambda_functor_args<
action<1, protect_action>,
tuple<lambda_functor<Arg> >,
NONE
>
>
(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.
@@ -92,46 +175,51 @@ protect(const lambda_functor<Arg>& a1)
// note, unlambda and protect are different things. Protect hides the lambda
// functor for one application, unlambda for good.
template <class LambdaFunctor>
class non_lambda_functor
{
LambdaFunctor lf;
template <class Arg>
class non_lambda_functor : public has_sig {
lambda_functor<Arg> lf; // a lambda functor
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
LambdaFunctor::inherited::
template sig<typename SigArgs::tail_type>::type type;
lambda_functor<Arg>::template sig<SigArgs>::type type;
};
explicit non_lambda_functor(const LambdaFunctor& a) : lf(a) {}
non_lambda_functor(const lambda_functor<Arg>& a) : lf(a) {}
typename LambdaFunctor::nullary_return_type
typename sig<tuple<lambda_functor<Arg> > >::type
operator()() const {
return lf.template
call<typename LambdaFunctor::nullary_return_type>
(cnull_type(), cnull_type(), cnull_type(), cnull_type());
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg> > >::type>();
}
template<class A>
typename sig<tuple<const non_lambda_functor, A&> >::type
typename sig<tuple<lambda_functor<Arg>, A&> >::type
operator()(A& a) const {
return lf.template call<typename sig<tuple<const non_lambda_functor, A&> >::type >(a, cnull_type(), cnull_type(), cnull_type());
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&> >::type >(a);
}
template<class A, class B>
typename sig<tuple<const non_lambda_functor, A&, B&> >::type
typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type
operator()(A& a, B& b) const {
return lf.template call<typename sig<tuple<const non_lambda_functor, A&, B&> >::type >(a, b, cnull_type(), cnull_type());
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type >(a, b);
}
template<class A, class B, class C>
typename sig<tuple<const non_lambda_functor, A&, B&, C&> >::type
typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type
operator()(A& a, B& b, C& c) const {
return lf.template call<typename sig<tuple<const non_lambda_functor, A&, B&, C&> >::type>(a, b, c, cnull_type());
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type>(a, b, c);
}
};
@@ -139,10 +227,9 @@ template <class Arg>
inline const Arg& unlambda(const Arg& a) { return a; }
template <class Arg>
inline const non_lambda_functor<lambda_functor<Arg> >
unlambda(const lambda_functor<Arg>& a)
inline const non_lambda_functor<Arg> unlambda(const lambda_functor<Arg>& a)
{
return non_lambda_functor<lambda_functor<Arg> >(a);
return non_lambda_functor<Arg>(a);
}
// Due to a language restriction, lambda functors cannot be made to
@@ -150,173 +237,21 @@ 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!
// 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_incorrect_lambda_functor<lambda_functor<Arg> >
inline const const_incorrect_lambda_functor<Arg>
break_const(const lambda_functor<Arg>& lf)
{
return const_incorrect_lambda_functor<lambda_functor<Arg> >(lf);
}
return const_incorrect_lambda_functor<Arg>(lf);
}
template <class Arg>
inline const const_parameter_lambda_functor<lambda_functor<Arg> >
inline const const_parameter_lambda_functor<Arg>
const_parameters(const lambda_functor<Arg>& lf)
{
return const_parameter_lambda_functor<lambda_functor<Arg> >(lf);
return const_parameter_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

View File

@@ -22,27 +22,6 @@
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
@@ -58,45 +37,43 @@ template<class> class return_type_deduction_failure {};
// 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
// 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;
template<class A, class B, class C>
struct open_args {
typedef A type1;
typedef B type2;
typedef C type3;
};
// take care of the unavoidable instantiation for nullary case
template<class Act> struct return_type_1_prot<Act, null_type> {
typedef null_type 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;
};
// 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 {
@@ -105,27 +82,55 @@ template<class Act, class A> struct return_type_1 {
};
// read the comments for return_type_2_protect
namespace detail {
template <class T>
class protect_conversion {
typedef typename boost::remove_reference<T>::type non_ref_T;
public:
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;
// 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
};
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;
};
} // end detail
template <class Act, class A, class B> struct return_type_2_prot {
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;
// experimental feature
// We may have a lambda functor as a result type of a subexpression
@@ -135,8 +140,8 @@ template <class Act, class A, class B> struct return_type_2_prot {
// 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 a const open argument, a bound
// argument stored as a const reference, or a function returning a
// 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
// 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)
@@ -146,112 +151,460 @@ template <class Act, class A, class B> struct return_type_2_prot {
// action type and code, and a copy compatible argument tuple.
typedef typename boost::remove_reference<A>::type non_ref_A;
typedef typename boost::remove_reference<B>::type non_ref_B;
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
detail::IF<
// 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,
is_lambda_functor<A>::value || is_lambda_functor<B>::value,
lambda_functor<
lambda_functor_base<
Act,
lambda_functor_args<
action<2, Act>,
tuple<typename detail::protect_conversion<A>::type,
typename detail::protect_conversion<B>::type>
typename detail::protect_conversion<B>::type>,
combine_arities<A, B>::value
>
>,
typename return_type_2<Act, non_ref_A, non_ref_B>::type
typename return_type_2<Act, A, B>::type
>::RET 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;
// // 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, class Other> struct return_type_2_prot<Act, Other, 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, null_type, Other> {
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;
};
// 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;
// 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;
};
// 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<FIRST>, Open> {
typedef typename Open::type1 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;
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;
};
// 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;
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;
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;
};

View File

@@ -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://www.boost.org
// For more information, see http://lambda.cs.utu.fi
#ifndef BOOST_LAMBDA_SELECT_FUNCTIONS_HPP
@@ -21,29 +21,104 @@ 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, CALL_TEMPLATE_ARGS>
inline Any& select(Any& any, CALL_FORMAL_ARGS) { CALL_USE_ARGS; return any; }
template<class Any, class A, class B, class C>
inline Any& select(Any& any, A&, B&, C&) { return any; }
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 A& select(const lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
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);
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 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);
}
// ------------------------------------------------------------------------
// select functions where the return type is explicitly given
// selector 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.
@@ -51,24 +126,62 @@ select ( lambda_functor<Arg>& op, CALL_FORMAL_ARGS) {
// 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 r_select {
template<class RET> struct ret_selector
{
// Any == RET
template<class Any, CALL_TEMPLATE_ARGS>
static
inline RET go (Any& any, CALL_FORMAL_ARGS) { CALL_USE_ARGS; return any; }
// 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 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 A, class B, class C>
static A& select(const lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
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);
template<class A, class B, class C>
static A& select(lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
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;
}
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, 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);
}
};

View File

@@ -0,0 +1,539 @@
// 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

View File

@@ -1,494 +0,0 @@
// 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

View File

@@ -18,22 +18,15 @@
#include "boost/lambda/core.hpp"
#ifdef BOOST_NO_FDECL_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMS
#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
#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

View File

@@ -1,538 +0,0 @@
// 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

View File

@@ -1,124 +0,0 @@
// -- 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

View File

@@ -1,507 +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/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

View File

@@ -23,18 +23,17 @@ 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_rt_traits.cpp \
bind_tests_simple_f_refs.cpp \
cast_test.cpp \
phoenix_control_structures.cpp \
extending_return_type_traits.cpp \
bind_tests_simple_function_references.cpp \
exception_test.cpp \
@@ -70,14 +69,13 @@ run:
./operator_tests_simple.exe
./control_structures.exe
./switch_construct.exe
./extending_rt_traits.exe
./extending_return_type_traits.exe
./constructor_tests.exe
./cast_test.exe
./bind_tests_simple.exe
./bind_tests_advanced.exe
./bll_and_function.exe
./bind_tests_simple_f_refs.exe
./phoenix_control_structures.exe
./bind_tests_simple_function_references.exe
./exception_test.exe
@@ -87,3 +85,4 @@ run:

View File

@@ -3,9 +3,8 @@
#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/bind.hpp"
#include "boost/lambda/lambda.hpp"
#include "boost/any.hpp"
@@ -34,8 +33,6 @@ 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; }
};
@@ -89,32 +86,31 @@ int call_with_100(const F& f) {
template<class F>
int call_with_101(const F& f) {
return bind(unlambda(f), _1)(make_const(101));
return bind(unlambda(ret<int>(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() {
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_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.
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_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);
// 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
}
// protect ------------------------------------------------------------
// protect protects a lambda functor from argument substitution.
@@ -122,14 +118,21 @@ void test_unlambda() {
namespace ll {
struct for_each {
struct for_each : public has_sig {
// 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).
// 1. Provide a sig class member template:
// 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:
// The return type deduction system instantiate this class as:
// sig<Args>::type, where Args is a boost::tuples::cons-list
@@ -145,14 +148,17 @@ struct for_each {
// if the functor has several operator()'s, even if they have different
// number of arguments.
// Note, that the argument types in Args are guaranteed to be non-reference
// types, but they can have cv-qualifiers.
template <class Args>
// 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>
struct sig {
typedef typename boost::remove_const<
typename boost::tuples::element<3, Args>::type
>::type type;
typename boost::remove_reference<
typename boost::tuples::element<3, Args>::type
>::type
>::type type;
};
template <class A, class B, class C>
@@ -172,21 +178,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);
@@ -194,12 +200,11 @@ 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)))();
@@ -227,15 +232,10 @@ 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,10 +243,7 @@ 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
#endif
// (boost::ref(std::cout << 1), std::cout << constant(2))(); // this does
}
@@ -257,22 +254,17 @@ 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)(_1, make_const(7));
(_1 + _2)(bind(&sum_0), 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
// defint the sig template, or then
// either define the result_type typedef, have 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
@@ -280,19 +272,55 @@ void test_lambda_functors_as_arguments_to_lambda_functors() {
int a = 5, b = 6;
// Let type deduction find out the return type
BOOST_TEST(bind(_1, _2, _3)(unlambda(_1 + _2), a, b) == 11);
// Let type deduction take find out the return type
BOOST_TEST(bind(_1, _2, _3)(_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() {
@@ -329,6 +357,7 @@ 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;

View File

@@ -39,13 +39,10 @@ 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);
@@ -123,14 +120,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);

View File

@@ -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);

View File

@@ -22,12 +22,16 @@ using namespace std;
void test_function() {
boost::function<int, int, int> f;
f = _1 + _2;
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
BOOST_TEST(f(1, 2)== 3);
int i=1; int j=2;
boost::function<int&, int&, int> g = _1 += _2;
boost::function<int&, int&, int> g = unlambda(_1 += _2);
g(i, j);
BOOST_TEST(i==3);
@@ -35,7 +39,7 @@ void test_function() {
int* sum = new int();
*sum = 0;
boost::function<int&, int> counter = *sum += _1;
boost::function<int&, int> counter = unlambda(*sum += _1);
counter(5); // ok, sum* = 5;
BOOST_TEST(*sum == 5);
delete sum;

View File

@@ -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 *[]) {

View File

@@ -2,8 +2,7 @@
#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 "boost/lambda/control_structures.hpp"
#include <iostream>
#include <algorithm>

View File

@@ -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,19 +512,6 @@ 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() {
@@ -544,7 +531,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
@@ -555,19 +542,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);
@@ -578,7 +565,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');
}
@@ -589,7 +576,6 @@ int test_main(int, char *[]) {
{
test_different_number_of_catch_blocks();
return_type_matching();
test_empty_catch_blocks();
}
catch (int x)
{
@@ -607,3 +593,46 @@ 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";

View File

@@ -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;
};

View File

@@ -7,6 +7,8 @@
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/bind.hpp"
#include "boost/lambda/detail/member_ptr.hpp"
#include <string>
using namespace boost::lambda;
@@ -117,33 +119,30 @@ 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
// or use the plain_return_type_2 template.
// references :(
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

View File

@@ -10,14 +10,6 @@
#include <set>
#include <string>
#include <iostream>
#ifndef BOOST_NO_STRINGSTREAM
#include <sstream>
#endif
using namespace std;
using namespace boost;
using namespace boost::lambda;
@@ -25,44 +17,6 @@ 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;
@@ -95,7 +49,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)==~2u);
BOOST_TEST((~_1)(ui)==~2);
}
void comparison_operators() {
@@ -376,7 +330,7 @@ int test_main(int, char *[]) {
address_of_and_dereference();
comma();
pointer_arithmetic();
cout_tests();
return 0;
}

View File

@@ -1,139 +0,0 @@
// 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;
}

View File

@@ -5,8 +5,7 @@
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/if.hpp"
#include "boost/lambda/switch.hpp"
#include "boost/lambda/control_structures.hpp"
#include <iostream>
#include <algorithm>
@@ -351,30 +350,11 @@ 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;
}