2
0
mirror of https://github.com/boostorg/lambda.git synced 2026-01-21 17:02:36 +00:00

Compare commits

...

117 Commits

Author SHA1 Message Date
Jaakko Järvi
8d46420cf3 adding tests for phoenix style control constructs
[SVN r13537]
2002-04-19 19:46:41 +00:00
Jaakko Järvi
cbe0189caa include file changes
[SVN r13535]
2002-04-19 19:44:43 +00:00
Jaakko Järvi
cd4f8c008d addedd var, constant, constant_ref tests, and cout << _1 etc. tests
[SVN r13534]
2002-04-19 19:44:05 +00:00
Jaakko Järvi
e8def54ef0 changes in include files
[SVN r13533]
2002-04-19 19:43:08 +00:00
Jaakko Järvi
52ef1b9bac some changes in the return_type_2 traits
[SVN r13532]
2002-04-19 19:42:05 +00:00
Jaakko Järvi
f83f913fd7 changed _E to _e (_E is a reserved identifier name)
[SVN r13531]
2002-04-19 19:40:39 +00:00
Jaakko Järvi
39eda970d5 no need to use unlambda anymore
[SVN r13530]
2002-04-19 19:39:44 +00:00
Jaakko Järvi
03f92e2081 no comment
[SVN r13529]
2002-04-19 19:38:55 +00:00
Jaakko Järvi
521b1be1ac changes after making sig template the default
[SVN r13528]
2002-04-19 19:38:12 +00:00
Jaakko Järvi
cf577450e8 added a few tests
[SVN r13527]
2002-04-19 19:34:59 +00:00
Jaakko Järvi
f6708ffe6b fixed a bug in transform return type deductions
[SVN r13299]
2002-03-28 19:19:53 +00:00
Jaakko Järvi
808b2dd7f0 removed a duplicate line
[SVN r13298]
2002-03-28 18:29:44 +00:00
Jaakko Järvi
eac09d219b added default consturctors to placeholders (back)
[SVN r13238]
2002-03-21 22:45:48 +00:00
Jaakko Järvi
1879db42b6 forced KCC to include istrem/ostream since there is a bug
if only iosfwd is included


[SVN r13237]
2002-03-21 16:36:20 +00:00
Jaakko Järvi
fe183e216f removed old commented out code
[SVN r13236]
2002-03-21 16:34:57 +00:00
Jaakko Järvi
2c407cf775 fixed bug in return type deduction
[SVN r13235]
2002-03-21 16:34:02 +00:00
Jaakko Järvi
032b82de7d added function call operators for placeholder
[SVN r13234]
2002-03-21 03:55:06 +00:00
Jaakko Järvi
ff2c6018a3 added initializers for placeholder constants
[SVN r13233]
2002-03-21 03:52:09 +00:00
Jaakko Järvi
a9276b49ec removed one unneeded include
[SVN r13228]
2002-03-19 18:19:04 +00:00
Peter Dimov
5211282185 MSVC 7.01a fix.
[SVN r13219]
2002-03-18 18:23:51 +00:00
Jaakko Järvi
9ae841ecf2 removed parameter names (just the types are left) to
prevent unused parameter warnings with some compilers


[SVN r13218]
2002-03-18 17:01:19 +00:00
Jaakko Järvi
8cdf08bc6c removed code that was already commented away
[SVN r13193]
2002-03-14 16:02:32 +00:00
Jaakko Järvi
f96e5a404c changed lambda functor from struct to class, so it's similarly
defined and declared


[SVN r13133]
2002-03-08 14:29:48 +00:00
Jaakko Järvi
145cc3e7e8 include member_ptr.hpp by default as well
[SVN r13132]
2002-03-08 14:27:12 +00:00
Jaakko Järvi
57d827ad82 changed action from struct to class so they're similarly declared and defined
[SVN r13131]
2002-03-08 14:26:29 +00:00
Jaakko Järvi
5fbbc843dd removed some macro defs that were not used
[SVN r13130]
2002-03-08 14:22:14 +00:00
nobody
da31648a61 This commit was manufactured by cvs2svn to create branch
'lambda_development_during_review'.

[SVN r12907]
2002-02-22 21:13:30 +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
59 changed files with 18594 additions and 0 deletions

53
doc/ar01s02.html Normal file
View File

@@ -0,0 +1,53 @@
<!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>2. Getting Started</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="index.html" title="
C++ BOOST
The Boost Lambda Library"><link rel="next" href="ar01s03.html" title="3. Introduction"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2. Getting Started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:getting_started"></a>2. Getting Started</h2></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2790112"></a>2.1. Installing the library</h3></div></div><p>
The library consists of include files only, hence there is no
installation procedure. The <tt>boost</tt> include directory
must be on the include path.
There are a number of include files that give different functionality:
<div class="itemizedlist"><ul type="disc"><li><p>
<tt>lambda/lambda.hpp</tt> defines lambda expressions for different C++
operators, see <a href="ar01s05.html#sect:operator_expressions" title="5.2. Operator expressions">Section 5.2</a>.
</p></li><li><p>
<tt>lambda/bind.hpp</tt> defines <tt>bind</tt> functions for up to 9 arguments, see <a href="ar01s05.html#sect:bind_expressions" title="5.3. Bind expressions">Section 5.3</a>.</p></li><li><p>
<tt>lambda/control_constructs.hpp</tt> defines lambda function equivalents for the control constructs in C++, see <a href="ar01s05.html#sect:lambda_expressions_for_control_structures" title="5.6. Lambda expressions for control structures">Section 5.6</a> (includes <tt>lambda.hpp</tt>).
</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>
<tt>lambda/casts.hpp</tt> provides lambda versions of different casts, as well as <tt>sizeof</tt> and <tt>typeid</tt>, see <a href="ar01s05.html#sect:cast_expressions" title="5.10.1.
Cast expressions
">Section 5.10.1</a>.
</p></li><li><p>
<tt>lambda/exceptions.hpp</tt> gives tools for throwing and catching
exceptions within lambda functions, <a href="ar01s05.html#sect:exceptions" title="5.7. Exceptions">Section 5.7</a> (includes
<tt>lambda.hpp</tt>).
</p></li><li><p>
<tt>lambda/algorithm.hpp</tt> allows nested STL algorithm invocations, see <a href="ar01s05.html#sect:nested_stl_algorithms" title="5.11. Nesting STL algorithm invocations">Section 5.11</a>.
</p></li></ul></div>
Any other header files in the package are for internal use.
Additionally, the library depends on two other Boost Libraries, the
<span class="emphasis"><i>Tuple</i></span> [<a href="bi01.html#cit:boost::tuple" title="[tuple]">tuple</a>] and the <span class="emphasis"><i>type_traits</i></span> [<a href="bi01.html#cit:boost::type_traits" title="[type_traits]">type_traits</a>] libraries, and on the <tt>boost/ref.hpp</tt> header.
</p><p>
All definitions are placed in the namespace <tt>boost::lambda</tt> and its subnamespaces.
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="id2742926"></a>2.2. Conventions used in this document</h3></div></div><p>In most code examples, we omit the namespace prefixes for names in the <tt>std</tt> and <tt>boost::lambda</tt> namespaces.
Implicit using declarations
<pre class="programlisting">
using namespace std;
using namespace boost::lambda;
</pre>
are assumed to be in effect.
</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.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="ar01s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">
C++ BOOST
The Boost Lambda Library </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 3. Introduction</td></tr></table></div></body></html>

180
doc/ar01s03.html Normal file
View File

@@ -0,0 +1,180 @@
<!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>3. Introduction</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="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>
Any C++ construct that can be called with the function call syntax
is a function object.
The STL contains predefined function objects for some common cases (such as <tt>plus</tt>, <tt>less</tt> and <tt>not1</tt>).
As an example, one possible implementation for the standard <tt>plus</tt> template is:
<pre class="programlisting">
template &lt;class T&gt; : public binary_function&lt;T, T, T&gt;
struct plus {
T operator()(const T&amp; i, const T&amp; j) const {
return i + j;
}
};
</pre>
The base class <tt>binary_function&lt;T, T, T&gt;</tt> contains typedefs for the argument and return types of the function object, which are needed to make the function object <span class="emphasis"><i>adaptable</i></span>.
</p><p>
In addition to the basic function object classes, such as the one above,
the STL contains <span class="emphasis"><i>binder</i></span> templates for creating a unary function object from an adaptable binary function object by fixing one of the arguments to a constant value.
For example, instead of having to explicitly write a function object class like:
<pre class="programlisting">
class plus_1 {
int _i;
public:
plus_1(const int&amp; i) : _i(i) {}
int operator(const int&amp; j) { return i + j; }
};
</pre>
the equivalent functionality can be achieved with the <tt>plus</tt> template and one of the binder templates (<tt>bind1st</tt>).
E.g., the following two expressions create function objects with identical functionalities;
when invoked, both return the result of adding <tt>1</tt> to the argument of the function object:
<pre class="programlisting">
plus_1(1)
bind1st(plus&lt;int&gt;(), 1)
</pre>
The subexpression <tt>plus&lt;int&gt;()</tt> in the latter line is a binary function object which computes the sum of two integers, and <tt>bind1st</tt> invokes this function object partially binding the first argument to <tt>1</tt>.
As an example of using the above function object, the following code adds <tt>1</tt> to each element of some container <tt>a</tt> and outputs the results into the standard output stream <tt>cout</tt>.
<pre class="programlisting">
transform(a.begin(), a.end(), ostream_iterator&lt;int&gt;(cout),
bind1st(plus&lt;int&gt;(), 1));
</pre>
</p><p>
To make the binder templates more generally applicable, the STL contains <span class="emphasis"><i>adaptors</i></span> for making
pointers or references to functions, and pointers to member functions,
adaptable.
Finally, some STL implementations contain function composition operations as
extensions to the standard [<a href="bi01.html#cit:sgi:02" title="[SGI02]">SGI02</a>].
</p><p>
All these tools aim at one goal: to make it possible to specify
<span class="emphasis"><i>unnamed functions</i></span> in a call of an STL algorithm,
in other words, to pass code fragments as an argument to a function.
However, this goal is attained only partially.
The simple example above shows that the definition of unnamed functions
with the standard tools is cumbersome.
Complex expressions involving functors, adaptors, binders and
function composition operations tend to be difficult to comprehend.
In addition to this, there are significant restrictions in applying
the standard tools. E.g. the standard binders allow only one argument
of a binary function to be bound; there are no binders for
3-ary, 4-ary etc. functions.
</p><p>
The Boost Lambda Library provides solutions for the problems described above:
<div class="itemizedlist"><ul type="disc"><li><p>
Unnamed functions can be created easily with an intuitive syntax.
The above example can be written as:
<pre class="programlisting">
transform(a.begin(), a.end(), ostream_iterator&lt;int&gt;(cout),
1 + _1);
</pre>
or even more intuitively:
<pre class="programlisting">
for_each(a.begin(), a.end(), cout &lt;&lt; (1 + _1));
</pre>
</p></li><li><p>
Most of the restrictions in argument binding are removed,
arbitrary arguments of practically any C++ function can be bound.
</p></li><li><p>
Separate function composition operations are not needed,
as function composition is supported implicitly.
</p></li></ul></div>
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="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:
<pre class="programlisting">
lambda x<sub>1</sub> ... x<sub>n</sub>.e
</pre>
A lambda expression defines an unnamed function and consists of:
<div class="itemizedlist"><ul type="disc"><li><p>
the parameters of this function: <tt>x<sub>1</sub> ... x<sub>n</sub></tt>.
</p></li><li><p>the expression e which computes the value of the function in terms of the parameters <tt>x<sub>1</sub> ... x<sub>n</sub></tt>.
</p></li></ul></div>
A simple example of a lambda expression is
<pre class="programlisting">
lambda x y.x+y
</pre>
Applying the lambda function means substituting the formal parameters with the actual arguments:
<pre class="programlisting">
(lambda x y.x+y) 2 3 = 2 + 3 = 5
</pre>
</p><p>
In the C++ version of lambda expressions the <tt>lambda x<sub>1</sub> ... x<sub>n</sub></tt> part is missing and the formal parameters have predefined names.
There are three such predefined formal parameters, called <span class="emphasis"><i>placeholders</i></span>: <tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
They refer to the first, second and third argument of the function defined by the lambda expression.
For example, the C++ version of the definition
<pre class="programlisting">lambda x y.x+y</pre>
is
<pre class="programlisting">_1 + _2</pre>
</p><p>
Hence, there is no syntactic keyword for C++ lambda expressions.
The use of a placeholder as an operand implies that the operator invocation is a lambda expression.
However, this is true only for operator invocations.
Lambda expressions containing function calls, control structures, casts etc. require special syntactic constructs.
Most importantly, function calls need to be wrapped inside a <tt>bind</tt> function.
As an example, consider the lambda expression:
<pre class="programlisting">lambda x y.foo(x,y)</pre>
Rather than <tt>foo(_1, _2)</tt>, the C++ counterpart for this expression is:
<pre class="programlisting">bind(foo, _1, _2)</pre>
We refer to this type of C++ lambda expressions as <span class="emphasis"><i>bind expressions</i></span>.
</p><p>A lambda expression defines a C++ function object, hence function application syntax is like calling any other function object, for instance: <tt>(_1 + _2)(i, j)</tt>.
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:partial_function_application"></a>3.2.1. Partial function application</h4></div></div><p>
A bind expression is in effect a <span class="emphasis"><i>partial function application</i></span>.
In partial function application, some of the arguments of a function are bound to fixed values.
The result is another function, with possibly fewer arguments.
When called with the unbound arguments, this new function invokes the original function with the merged argument list of bound and unbound arguments.
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect: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>

164
doc/ar01s04.html Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>4. Using the library</title><meta name="generator" content="DocBook XSL Stylesheets V1.48"><link rel="home" href="index.html" title="
C++ BOOST
The Boost Lambda Library"><link rel="up" href="index.html" title="
C++ BOOST
The Boost Lambda Library"><link rel="previous" href="ar01s03.html" title="3. Introduction"><link rel="next" href="ar01s05.html" title="5. Lambda expressions in details"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4. Using the library</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:using_library"></a>4. Using the library</h2></div></div><p>
The purpose of this section is to introduce the basic functionality of the library.
There are quite a lot of exceptions and special cases, but discussion of them is postponed until later sections.
</p><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:introductory_examples"></a>4.1. Introductory Examples</h3></div></div><p>
In this section we give basic examples of using BLL lambda expressions in STL algorithm invocations.
We start with some simple expressions and work up.
First, we initialize the elements of a container, say, a <tt>list</tt>, to the value <tt>1</tt>:
<pre class="programlisting">
list&lt;int&gt; v(10);
for_each(v.begin(), v.end(), _1 = 1);</pre>
The expression <tt>_1 = 1</tt> creates a lambda functor which assigns the value <tt>1</tt> to every element in <tt>v</tt>.<sup>[<a name="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>:
<pre class="programlisting">
list&lt;int*&gt; vp(10);
transform(v.begin(), v.end(), vp.begin(), &amp;_1);</pre>
The expression <tt>&amp;_1</tt> creates a function object for getting the address of each element in <tt>v</tt>.
The addresses get assigned to the corresponding elements in <tt>vp</tt>.
</p><p>
The next code fragment changes the values in <tt>v</tt>.
For each element, the function <tt>foo</tt> is called.
The original value of the element is passed as an argument to <tt>foo</tt>.
The result of <tt>foo</tt> is assigned back to the element:
<pre class="programlisting">
int foo(int);
for_each(v.begin(), v.end(), _1 = bind(foo, _1));</pre>
</p><p>
The next step is to sort the elements of <tt>vp</tt>:
<pre class="programlisting">sort(vp.begin(), vp.end(), *_1 &gt; *_2);</pre>
In this call to <tt>sort</tt>, we are sorting the elements by their contents in descending order.
</p><p>
Finally, the following <tt>for_each</tt> call outputs the sorted content of <tt>vp</tt> separated by line breaks:
<pre class="programlisting">
for_each(vp.begin(), vp.end(), cout &lt;&lt; *_1 &lt;&lt; '\n');
</pre>
Note that a normal (non-lambda) expression as subexpression of a lambda expression is evaluated immediately.
This may cause surprises.
For instance, if the previous example is rewritten as
<pre class="programlisting">
for_each(vp.begin(), vp.end(), cout &lt;&lt; '\n' &lt;&lt; *_1);
</pre>
the subexpression <tt>cout &lt;&lt; '\n'</tt> is evaluated immediately and the effect is to output a single line break, followed by the elements of <tt>vp</tt>.
The BLL provides functions <tt>constant</tt> and <tt>var</tt> to turn constants and, 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>
These functions are described more thoroughly in <a href="ar01s05.html#sect:delaying_constants_and_variables" title="5.5. Delaying constants and variables">Section 5.5</a>
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:parameter_and_return_types"></a>4.2. Parameter and return types of lambda functors</h3></div></div><p>
During the invocation of a lambda functor, the actual arguments are substituted for the placeholders.
The placeholders do not dictate the type of these actual arguments.
The basic rule is that a lambda function can be called with arguments of any types, as long as the lambda expression with substitutions performed is a valid C++ expression.
As an example, the expression
<tt>_1 + _2</tt> creates a binary lambda functor.
It can be called with two objects of any types <tt>A</tt> and <tt>B</tt> for which <tt>operator+(A,B)</tt> is defined (and for which BLL knows the return type of the operator, see below).
</p><p>
C++ lacks a mechanism to query a type of an expression.
However, this precise mechanism is crucial for the implementation of C++ lambda expressions.
Consequently, BLL includes a somewhat complex type deduction system which uses a set of traits classes for deducing the resulting type of lambda functions.
It handles expressions where the operands are of built-in types and many of the expressions with operands of standard library types.
Many of the user defined types are covered as well, particularly if the user defined operators obey normal conventions in defining the return types.
</p><p>
There are, however, cases when the return type cannot be deduced. For example, suppose you have defined:
<pre class="programlisting">C operator+(A, B);</pre>
The following lambda function invocation fails, since the return type cannot be deduced:
<pre class="programlisting">A a; B b; (_1 + _2)(a, b);</pre>
</p><p>
There are two alternative solutions to this.
The first is to extend the BLL type deduction system to cover your own types (see <a href="ar01s06.html#sect:extending_return_type_system" title="6. Extending return type deduction system">Section 6</a>).
The second is to use a special lambda expression (<tt>ret</tt>) which defines the return type in place (see <a href="ar01s05.html#sect:overriding_deduced_return_type" title="5.4. Overriding the deduced return type">Section 5.4</a>):
<pre class="programlisting">A a; B b; ret&lt;C&gt;(_1 + _2)(a, b);</pre>
</p><p>
For bind expressions, the return type can be defined as a template argument of the bind function as well:
<pre class="programlisting">bind&lt;int&gt;(foo, _1, _2);</pre>
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:actual_arguments_to_lambda_functors"></a>4.3. About actual arguments to lambda functors</h3></div></div><p>A general restriction for the actual arguments is that they cannot be non-const rvalues.
For example:
<pre class="programlisting">
int i = 1; int j = 2;
(_1 + _2)(i, j); // ok
(_1 + _2)(1, 2); // error (!)
</pre>
This restriction is not as bad as it may look.
Since the lambda functors are most often called inside STL-algorithms,
the arguments originate from dereferencing iterators and the dereferencing operators seldom return rvalues.
And for the cases where they do, there are workarounds discussed in
<a href="ar01s05.html#sect:rvalues_as_actual_arguments" title="5.9.2. Rvalues as actual arguments to lambda functors">Section 5.9.2</a>.
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:storing_bound_arguments"></a>4.4. Storing bound arguments in lambda functions</h3></div></div><p>
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:
<div class="itemizedlist"><ul type="disc"><li><p>
The programmer can control the storing mechanism with <tt>ref</tt> and <tt>cref</tt> wrappers [<a href="bi01.html#cit:boost::ref" title="[ref]">ref</a>].
Wrapping an argument with <tt>ref</tt>, or <tt>cref</tt>, instructs the library to store the argument as a reference, or as a reference to const respectively.
For example, if we rewrite the previous example and wrap the variable <tt>i</tt> with <tt>ref</tt>, we are creating the lambda expression <tt>lambda x.x+i</tt> and the value of the expression in the last line will be 4:
<pre class="programlisting">
i = 1;
(_1 + ref(i))(i = 2);
</pre>
</p></li><li><p>
Array types cannot be copied, they are thus stored as const reference by default.
</p></li><li><p>
For some expressions, it makes more sense to store the arguments as references.
For example, the obvious intention of the lambda expression <tt>i += _1</tt> is that calls to the lambda functor affect the value of the variable <tt>i</tt>, rather than some temporary copy of it.
As another example, the streaming operators take their leftmost argument as non-const references.
The exact rules are:
<div class="itemizedlist"><ul type="round"><li><p>The left argument of compound assignment operators (<tt>+=</tt>, <tt>*=</tt>, etc.) are stored as references to non-const.</p></li><li><p>If the left argument of <tt>&lt;&lt;</tt> or <tt>&gt;&gt;</tt> operator is derived from an instantiation of <tt>basic_ostream</tt> or respectively from <tt>basic_istream</tt>, the argument is stored as a reference to non-const.
For all other types, the argument is stored as a copy.
</p></li><li><p>
In pointer arithmetic expressions, non-const array types are stored as non-const references.
This is to prevent pointer arithmetic making non-const arrays const.
</p></li></ul></div>
</p></li></ul></div>
</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.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.
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">3. Introduction </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 5. Lambda expressions in details</td></tr></table></div></body></html>

914
doc/ar01s05.html Normal file
View File

@@ -0,0 +1,914 @@
<!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>5. Lambda expressions in details</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="ar01s04.html" title="4. Using the library"><link rel="next" href="ar01s06.html" title="6. Extending return type deduction system"></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">5. Lambda expressions in details</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="sect:lambda_expressions_in_details"></a>5. Lambda expressions in details</h2></div></div><p>
This section describes different categories of lambda expressions in details.
We devote a separate section for each of the possible forms of a lambda expression.
</p><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:placeholders"></a>5.1. Placeholders</h3></div></div><p>
The BLL defines three placeholder types: <tt>placeholder1_type</tt>, <tt>placeholder2_type</tt> and <tt>placeholder3_type</tt>.
BLL has a predefined placeholder variable for each placeholder type: <tt>_1</tt>, <tt>_2</tt> and <tt>_3</tt>.
However, the user is not forced to use these placeholders.
It is easy to define placeholders with alternative names.
This is done by defining new variables of placeholder types.
For example:
<pre class="programlisting">boost::lambda::placeholder1_type X;
boost::lambda::placeholder2_type Y;
boost::lambda::placeholder3_type Z;
</pre>
With these variables defined, <tt>X += Y * Z</tt> is equivalent to <tt>_1 += _2 * _3</tt>.
</p><p>
The use of placeholders in the lambda expression determines whether the resulting function is nullary, unary, binary or 3-ary.
The highest placeholder index is decisive. For example:
<pre class="programlisting">
_1 + 5 // unary
_1 * _1 + _1 // unary
_1 + _2 // binary
bind(f, _1, _2, _3) // 3-ary
_3 + 10 // 3-ary
</pre>
Note that the last line creates a 3-ary function, which adds <tt>10</tt> to its <span class="emphasis"><i>third</i></span> argument.
The first two arguments are discarded.
</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.
</p><p>When an actual argument is supplied for a placeholder, the parameter passing mode is always by reference.
This means that any side-effects to the placeholder are reflected to the actual argument.
For example:
<pre class="programlisting">
int i = 1;
(_1 += 2)(i); // i is now 3
(++_1, cout &lt;&lt; _1)(i) // i is now 4, outputs 4
</pre>
</p><p>
Note that placeholder objects do not define the function call operator.
So strictly speaking, they are not lambda expressions, as evaluating a placeholder does not create a callable lambda functor.
Creating an identity functor is however straightforward, for example: <tt>0, _1</tt> serves for this purpose.
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:currying"></a>5.1.1. Currying</h4></div></div><p>Lambda functors support currying, that is, calling functions with one argument at a time.
If too few arguments are provided for a lambda functor, another lambda functor with a lower arity results.
When all arguments are provided, the original lambda functor is called.
For example, the last four lines below all have the same functionality; each of them ends up calling <tt>i + j + k</tt>:
<pre class="programlisting">
int i, j, k;
(_1 + _2 + _3)(i, j, k);
(_1 + _2 + _3)(i)(j)(k);
(_1 + _2 + _3)(i, j)(k);
(_1 + _2 + _3)(i)(j, k);
</pre>
</p><p>
A curried lambda functor just stores the arguments that are provided.
No subexpressions of the original lambda expression are evaluated, even though this might seem possible.
E.g., in the expression <tt>(_1 * _1 + _2)(i)</tt>, the subexpression <tt>i * i</tt> is not evaluated, rather its evaluation is postponed until the actual argument for <tt>_2</tt> is available too.
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:operator_expressions"></a>5.2. Operator expressions</h3></div></div><p>
The basic rule is that any C++ operator invocation with at least one argument being a lambda expression is itself a lambda expression.
Almost all overloadable operators are supported.
For example, the following is a valid lambda expression:
<pre class="programlisting">cout &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="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.
Consequently, the left operand must be a lambda expression. For example:
<pre class="programlisting">
int i;
_1 = i; // ok
i = _1; // not ok. i is not a lambda expression
</pre>
There is a simple solution around this limitation, described in <a href="ar01s05.html#sect:delaying_constants_and_variables" title="5.5. Delaying constants and variables">Section 5.5</a>.
In short,
the left hand argument can be explicitly turned into a lambda functor by wrapping it with a special <tt>var</tt> function:
<pre class="programlisting">
var(i) = _1; // ok
</pre>
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:logical_operators"></a>5.2.3. Logical operators</h4></div></div><p>
Logical operators obey the short-circuiting evaluation rules. For example, in the following code, <tt>i</tt> is never incremented:
<pre class="programlisting">
bool flag = true; int i = 0;
(_1 || ++_2)(flag, i);
</pre>
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:comma_operator"></a>5.2.4. Comma operator</h4></div></div><p>
Comma operator is the &#8216;statement separator&#8217; in lambda expressions.
Since comma is also the separator between arguments in a function call, extra parenthesis are sometimes needed:
<pre class="programlisting">
for_each(a.begin(), a.end(), (++_1, cout &lt;&lt; _1));
</pre>
Without the extra parenthesis around <tt>++_1, cout &lt;&lt; _1</tt>, the code would be interpreted as an attempt to call <tt>for_each</tt> with four arguments.
</p><p>
The lambda functor created by the comma operator adheres to the C++ rule of always evaluating the left operand before the right one.
In the above example, each element of <tt>a</tt> is first incremented, then written to the stream.
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_call_operator"></a>5.2.5. Function call operator</h4></div></div><p>
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.
We must separate two cases:
<div class="itemizedlist"><ul type="disc"><li><p>The right hand argument is a pointer to a data member.
In this case the lambda functor simply performs the argument substitution and calls the built-in member pointer operator, which returns a reference to the member pointed to.
For example:
<pre class="programlisting">
struct A { int d; };
A* a = new A();
...
(a -&gt;* &amp;A::d); // returns a reference to a-&gt;d
(_1 -&gt;* &amp;A::d)(a); // likewise
</pre>
</p></li><li><p>
The right hand argument is a pointer to a member function.
For a built-in call like this, the result is kind of a delayed member function call.
Such an expression must be followed by a function argument list, with which the delayed member function call is performed.
For example:
<pre class="programlisting">
struct B { int foo(int); };
B* b = new B();
...
(b -&gt;* &amp;B::foo) // returns a delayed call to b-&gt;foo
// a function argument list must follow
(b -&gt;* &amp;B::foo)(1) // ok, calls b-&gt;foo(1)
(_1 -&gt;* &amp;B::foo)(b); // returns a delayed call to b-&gt;foo,
// no effect as such
(_1 -&gt;* &amp;B::foo)(b)(1); // calls b-&gt;foo(1)
</pre>
</p></li></ul></div>
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:bind_expressions"></a>5.3. Bind expressions</h3></div></div><p>
Bind expressions can have two forms:
<pre class="programlisting">
bind(<i><tt>target-function</tt></i>, <i><tt>bind-argument-list</tt></i>)
bind(<i><tt>target-member-function</tt></i>, <i><tt>object-argument</tt></i>, <i><tt>bind-argument-list</tt></i>)
</pre>
A bind expression delays the call of a function.
If this <span class="emphasis"><i>target function</i></span> is <span class="emphasis"><i>n</i></span>-ary, then the <tt><span class="emphasis"><i>bind-argument-list</i></span></tt> must contain <span class="emphasis"><i>n</i></span> arguments as well.
In the current version of the BLL, 0 &lt;= n &lt;= 9 must hold.
For member functions, the number of arguments must be at most 8, as the object argument takes one argument position.
Basically, the
<span class="emphasis"><i><tt>bind-argument-list</tt></i></span> must be a valid argument list for the target function, except that any argument can be replaced with a placeholder, or more generally, with a lambda expression.
Note that also the target function can be a lambda expression.
The result of a bind expression is either a nullary, unary, binary or 3-ary function object depending on the use of placeholders in the <span class="emphasis"><i><tt>bind-argument-list</tt></i></span> (see <a href="ar01s05.html#sect:placeholders" title="5.1. Placeholders">Section 5.1</a>).
</p><p>
The return type of the lambda functor created by the bind expression can be given as an explicitly specified template parameter, as in the following example:
<pre class="programlisting">
bind&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.
</p><p>
The following sections describe the different types of bind expressions.
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:function_pointers_as_targets"></a>5.3.1. Function pointers or references as targets</h4></div></div><p>The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example:
<pre class="programlisting">
X foo(A, B, C); A a; B b; C c;
bind(foo, _1, _2, c)(a, b);
bind(&amp;foo, _1, _2, c)(a, b);
bind(_1, a, b, c)(foo);
</pre>
The return type deduction always succeeds with this type of bind expressions.
</p><p>
Note, that in C++ it is possible to take the address of an overloaded function only if the address is assigned to, or used as an initializer of, a variable, the type of which solves the amibiguity, or if an explicit cast expression is used.
This means, that overloaded functions cannot be used in bind expressions directly, e.g.:
<pre class="programlisting">
void foo(int);
void foo(float);
int i;
...
bind(&amp;foo, _1)(i); // error
...
void (*pf1)(int) = &amp;foo;
bind(pf1, _1)(i); // ok
bind(static_cast&lt;void(*)(int)&gt;(&amp;foo), _1)(i); // ok
</pre>
</p></div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="member_functions_as_targets"></a>5.3.2. Member functions as targets</h4></div></div><p>
The syntax for using pointers to member function in bind expression is:
<pre class="programlisting">
bind(<i><tt>target-member-function</tt></i>, <i><tt>object-argument</tt></i>, <i><tt>bind-argument-list</tt></i>)
</pre>
The object argument can be a reference or pointer to the object, the BLL supports both cases with a uniform interface:
<pre class="programlisting">
bool A::foo(int) const;
A a;
vector&lt;int&gt; ints;
...
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 binder object can be called both via a pointer or a reference:
<pre class="programlisting">
bool A::foo(int);
list&lt;A&gt; refs;
list&lt;A*&gt; pointers;
...
find_if(refs.begin(), refs.end(), bind(&amp;A::foo, _1, 1));
find_if(pointers.begin(), pointers.end(), bind(&amp;A::foo, _1, 1));
</pre>
</p><p>
Even though the interfaces are the same, there are important semantic differences between using a pointer or a reference as the object argument.
The differences stem from the way <tt>bind</tt>-functions take their parameters, and how the bound parameters are stored within the lambda functor.
The object argument has the same parameter passing and storing mechanism 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) { j = x; };
};
</pre>
When a pointer is used, the behavior is what the programmer might expect:
<pre class="programlisting">
A a(0,0); int k = 1;
bind(&amp;A::set_i, &amp;a, _1)(k); // a.i == 1
bind(&amp;A::set_j, &amp;a, _1)(k); // a.j == 1
</pre>
Even though a const copy of the object argument is stored, the original object <tt>a</tt> is still modified.
This is since the object argument is a pointer, and the pointer is copied, not the object it points to.
When we use a reference, the behaviour is different:
<pre class="programlisting">
A a(0,0); int k = 1;
bind(&amp;A::set_i, a, _1)(k); // error; a const copy of a is stored.
// Cannot call a non-const function set_i
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:
<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, 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:function_objects_as_targets"></a>5.3.3. Function objects as targets</h4></div></div><p>Function objects, that is, class objects which have the function call operator defined, can be used as target functions.
In general, BLL cannot deduce the return type of an arbitrary function object.
However, there are two ways to give BLL this capability for a certain function object class.
</p><div class="simplesect"><div class="titlepage"><div><h5 class="title"><a name="id2803148"></a>The result_type typedef</h5></div></div><p>
The BLL recognizes the typedef <tt>result_type</tt> in the function object, and uses that as the return type of the function call operator.
For example:
<pre class="programlisting">
struct A {
typedef B result_type;
B operator()(X, Y, Z);
};
</pre>
Function objects in the standard library adhere to this convention.
</p><p>
There are two significant restrictions with this scheme:
<div class="orderedlist"><ol type="1"><li><p>
If the function object defines several function call operators, there is no way to specify different result types for them.
</p></li><li><p>
If the function call operator is a template, the result type may depend on the template parameters.
Hence, the typedef ought to be a template too, which the C++ language does not support.
</p></li></ol></div>
</p></div><div class="simplesect"><div class="titlepage"><div><h5 class="title"><a name="id2803217"></a>The sig template</h5></div></div><p>
The second method is slightly more complex, but also more flexible.
The steps that need to be taken to make BLL aware of the return type(s) of a function object are:
<div class="orderedlist"><ol type="1"><li><p>
Make the function object class derive from <tt>has_sig</tt> class.
(This is a technical requirement that is needed to let the two mechanisms for specifying the return type coexist.)
</p></li><li><p>Provide a member template struct <tt>sig&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>
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 : public has_sig {
// the return type equals the third argument type:
template&lt;class T1, T2, T3&gt;
T3 operator()(const T1&amp; t1, const T2&amp; t2, const T3&amp; t3);
template &lt;class Args&gt;
class sig {
// get the third argument type (4th element)
typedef typename
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_const&lt;T3_non_ref&gt;::type type;
}
};
</pre>
The <tt>sig</tt> template is a <span class="emphasis"><i>meta-function</i></span> that maps the argument type tuple to the result type.
As the example above demonstrates, the template can end up being somewhat complex.
Typical tasks to be performed are the extraction of the relevant types from the tuple, removing cv-qualifiers, removing references etc.
See the Boost type_traits Library for tools that can aid in these tasks.
</p></div></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:overriding_deduced_return_type"></a>5.4. Overriding the deduced return type</h3></div></div><p>
The return type deduction system may not be able to deduce the return types of some user defined operators or bind expressions with class objects.
A special lambda expression type is provided for stating the return type explicitly and overriding the deduction system.
To state that the return type of the lambda functor defined by the lambda expression <tt>e</tt> is <tt>T</tt>, you can write:
<pre class="programlisting">ret&lt;T&gt;(e);</pre>
The effect is that the return type deduction is not performed for the lambda expression <tt>e</tt> at all, but instead, <tt>T</tt> is used as the return type.
Obviously <tt>T</tt> cannot be an arbitrary type, the true result of the lambda functor must be implicitly convertible to <tt>T</tt>.
For example:
<pre class="programlisting">
A a; B b;
C operator+(A, B);
int operator*(A, B);
...
ret&lt;D&gt;(_1 + _2)(a, b); // error (C cannot be converted to D)
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 {
typedef Y result_type;
Y operator()(); // #1
Z operator(int)(); // #2
};
...
X x; int i;
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>
</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;
C operator+(A, B); D operator-(C);
...
ret&lt;D&gt;( - (_1 + _2))(a, b); // error
ret&lt;D&gt;( - ret&lt;C&gt;(_1 + _2))(a, b); // ok
</pre>
</p><p>If you find yourself using <tt>ret</tt> repeatedly with the same types, it is worth while extending the return type deduction (see <a href="ar01s06.html#sect:extending_return_type_system" title="6. Extending return type deduction system">Section 6</a>).
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:nullary_functors_and_ret"></a>5.4.1. Nullary lambda functors and ret</h4></div></div><p>
As stated above, the effect of <tt>ret</tt> is to prevent the return type deduction to be performed.
However, there is an exception.
Due to the way the C++ template instantiation works, the compiler is always forced to instantiate the return type deduction templates for zero-argument lambda functors.
This introduces a slight problem with <tt>ret</tt>, best described with an example:
<pre class="programlisting">
struct F { int operator()(int i) const; };
F f;
...
bind(f, _1); // fails, cannot deduce the return type
ret&lt;int&gt;(bind(f, _1)); // ok
...
bind(f, 1); // fails, cannot deduce the return type
ret&lt;int&gt;(bind(f, 1)); // fails as well!
</pre>
The BLL cannot deduce the return types of the above bind calls, as <tt>F</tt> does not define the typedef <tt>result_type</tt>.
One would expect <tt>ret</tt> to fix this, but for the nullary lambda functor that results from a bind expression (last line above) this does not work.
The return type deduction templates are instantiated, even though it would not be necessary and the result is a compilation error.
</p><p>The solution to this is not to use the <tt>ret</tt> function, but rather define the return type as an explicitly specified template parameter in the <tt>bind</tt> call:
<pre class="programlisting">
bind&lt;int&gt;(f, 1); // ok
</pre>
The lambda functors created with
<tt>ret&lt;<i><tt>T</tt></i>&gt;(bind(<i><tt>arg-list</tt></i>))</tt> and
<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> 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">
for_each(a.begin(), a.end(), cout &lt;&lt; _1 &lt;&lt; ' ');
for_each(a.begin(), a.end(), cout &lt;&lt; ' ' &lt;&lt; _1);
</pre>
The first line outputs the elements of <tt>a</tt> separated by spaces, while the second line outputs a space followed by the elements of <tt>a</tt> without any separators.
The reason for this is that neither of the operands of
<tt>cout &lt;&lt; ' '</tt> is a lambda expression, hence <tt>cout &lt;&lt; ' '</tt> is evaluated immediately.
To delay the evaluation of <tt>cout &lt;&lt; ' '</tt>, one of the operands must be explicitly marked as a lambda expression.
This is accomplished with the <tt>constant</tt> function:
<pre class="programlisting">
for_each(a.begin(), a.end(), cout &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 <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:
<pre class="programlisting">
int index = 0;
for_each(a.begin(), a.end(), cout &lt;&lt; ++index &lt;&lt; ':' &lt;&lt; _1 &lt;&lt; '\n');
for_each(a.begin(), a.end(), cout &lt;&lt; ++var(index) &lt;&lt; ':' &lt;&lt; _1 &lt;&lt; '\n');
</pre>
The first <tt>for_each</tt> invocation does not do what we want; <tt>index</tt> is incremented only once, and its value is written into the output stream only once.
By using <tt>var</tt> to make <tt>index</tt> a lambda expression, we get the desired effect.
</p><p>
In sum, <tt>var(x)</tt> creates a nullary lambda functor,
which stores a reference to the variable <tt>x</tt>.
When the lambda functor is invoked, a reference to <tt>x</tt> is returned.
</p><div class="simplesect"><div class="titlepage"><div><h4 class="title"><a name="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> 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));
constant_type&lt;T&gt;::type delayed_c(constant(c));
</pre>
The first line defines the variable <tt>delayed_i</tt> which is a delayed version of the variable <tt>i</tt> of type <tt>T</tt>.
Analogously, the second line defines the constant <tt>delayed_c</tt> as a delayed version of the constant <tt>c</tt>.
For example:
<pre class="programlisting">
int i = 0; int j;
for_each(a.begin(), a.end(), (var(j) = _1, _1 = var(i), var(i) = var(j)));
</pre>
is equivalent to:
<pre class="programlisting">
int i = 0; int j;
var_type&lt;int&gt;::type vi(var(i)), vj(var(j));
for_each(a.begin(), a.end(), (vj = _1, _1 = vi, vi = vj));
</pre>
</p><p>
Here is an example of naming a delayed constant:
<pre class="programlisting">
constant_type&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="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.
Consequently, it is sometimes necessary to use <tt>var</tt> for this purpose.
We repeat the example from <a href="ar01s05.html#sect:assignment_and_subscript" title="5.2.2. Assignment and subscript operators">Section 5.2.2</a>:
<pre class="programlisting">
int i;
i = _1; // error
var(i) = _1; // ok
</pre>
</p><p>
Note that the compound assignment operators <tt>+=</tt>, <tt>-=</tt> etc. can be defined as non-member functions, and thus they are interpreted as lambda expressions even if only the right-hand operand is a lambda expression.
Nevertheless, it is perfectly ok to delay the left operand explicitly.
For example, <tt>i += _1</tt> is equivalent to <tt>var(i) += _1</tt>.
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:lambda_expressions_for_control_structures"></a>5.6. Lambda expressions for control structures</h3></div></div><p>
BLL defines several functions to create lambda functors that represent control structures.
They all take lambda functors as parameters and return <tt>void</tt>.
To start with an example, the following code outputs all even elements of some container <tt>a</tt>:
<pre class="programlisting">
for_each(a.begin(), a.end(),
if_then(_1 % 2 == 0, cout &lt;&lt; _1));
</pre>
</p><p>
The BLL supports the following function templates for control structures:
<pre class="programlisting">
if_then(condition, then_part)
if_then_else(condition, then_part, else_part)
while_loop(condition, body)
while_loop(condition) // no body case
do_while_loop(condition, body)
do_while_loop(condition) // no body case
for_loop(init, condition, increment, body)
for_loop(init, condition, increment) // no body case
switch_statement(...)
</pre>
</p><p>
Delayed variables tend to be commonplace in control structure lambda expressions.
For instance, here we use the <tt>var</tt> function to turn the arguments of <tt>for_loop</tt> into lambda expressions.
The effect of the code is to add 1 to each element of a two-dimensional array:
<pre class="programlisting">
int a[5][10]; int i;
for_each(a, a+5,
for_loop(var(i)=0, var(i)&lt;10, ++var(i),
_1[var(i)] += 1));
</pre>
</p><div class="section"><div class="titlepage"><div><h4 class="title"><a name="sect:switch_statement"></a>5.6.1. Switch statement</h4></div></div></div><p>
The lambda expressions for <tt>switch</tt> control structures are more complex since the number of cases may vary.
The general form of a switch lambda expression is:
<pre class="programlisting">
switch_statement(<i><tt>condition</tt></i>,
case_statement&lt;<i><tt>label</tt></i>&gt;(<i><tt>lambda expression</tt></i>),
case_statement&lt;<i><tt>label</tt></i>&gt;(<i><tt>lambda expression</tt></i>),
...
default_statement(<i><tt>lambda expression</tt></i>)
)
</pre>
The <tt><i><tt>condition</tt></i></tt> argument must be a lambda expression that creates a lambda functor with an integral return type.
The different cases are created with the <tt>case_statement</tt> functions, and the optional default case with the <tt>default_statement</tt> function.
The case labels are given as explicitly specified template arguments to <tt>case_statement</tt> functions and
<tt>break</tt> statements are implicitly part of each case.
For example, <tt>case_statement&lt;1&gt;(a)</tt>, where <tt>a</tt> is some lambda functor, generates the code:
<pre class="programlisting">
case 1:
<i><tt>evaluate lambda functor</tt></i> a;
break;
</pre>
The <tt>switch_statement</tt> function is specialized for up to 9 case statements.
</p><p>
As a concrete example, the following code iterates over some container <tt>v</tt> and ouptuts &#8220;zero&#8221; for each <tt>0</tt>, &#8220;one&#8221; for each <tt>1</tt>, and &#8220;other: <i><tt>n</tt></i>&#8221; for any other value <i><tt>n</tt></i>.
Note that another lambda expression is sequenced after the <tt>switch_statement</tt> to output a line break after each element:
<pre class="programlisting">
std::for_each(v.begin(), v.end(),
(
switch_statement(
_1,
case_statement&lt;0&gt;(std::cout &lt;&lt; constant(&quot;zero&quot;)),
case_statement&lt;1&gt;(std::cout &lt;&lt; constant(&quot;one&quot;)),
default_statement(cout &lt;&lt; constant(&quot;other: &quot;) &lt;&lt; _1)
),
cout &lt;&lt; constant(&quot;\n&quot;)
)
);
</pre>
</p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:exceptions"></a>5.7. Exceptions</h3></div></div><p>
The BLL provides lambda functors that throw and catch exceptions.
Lambda functors for throwing exceptions are created with the unary function <tt>throw_exception</tt>.
The argument to this function is the exception to be thrown, or a lambda functor which creates the exception to be thrown.
A lambda functor for rethrowing exceptions is created with the nullary <tt>rethrow</tt> function.
</p><p>
Lambda expressions for handling exceptions are somewhat more complex.
The general form of a lambda expression for try catch blocks is as follows:
<pre class="programlisting">
try_catch(
<i><tt>lambda expression</tt></i>,
catch_exception&lt;<i><tt>type</tt></i>&gt;(<i><tt>lambda expression</tt></i>),
catch_exception&lt;<i><tt>type</tt></i>&gt;(<i><tt>lambda expression</tt></i>),
...
catch_all(<i><tt>lambda expression</tt></i>)
)
</pre>
The first lambda expression is the try block.
Each <tt>catch_exception</tt> defines a catch block where the explicitly specified template argument defines the type of the exception to catch.
The lambda expression within the <tt>catch_exception</tt> defines the actions to take if the exception is caught.
Note that the resulting exception handlers catch the exceptions as references, i.e.,
<tt>catch_exception&lt;T&gt;(...)</tt> results in the catch block:
<pre class="programlisting">
catch(T&amp; e) { ... }
</pre>
The last catch block can alternatively be a call to
<tt>catch_exception&lt;<i><tt>type</tt></i>&gt;</tt>
or to
<tt>catch_all</tt>, which is the lambda expression equivalent to
<tt>catch(...)</tt>.
</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 first handler catches exceptions of type <tt>foo_exception</tt>.
Note the use of <tt>_1</tt> placeholder in the body of the handler.
</p><p>
The second handler shows how to throw exceptions, and demonstrates the use of the <span class="emphasis"><i>exception placeholder</i></span> <tt>_E</tt>.
It is a special placeholder, which refers to the caught exception object within the handler body.
Here we are handling an exception of type <tt>std::exception</tt>, which carries a string explaining the cause of the exception.
This explanation can be queried with the zero-argument member function <tt>what</tt>.
The expression
<tt>bind(&amp;std::exception::what, _E)</tt> creates the lambda function for making that call.
Note that <tt>_E</tt> is not a full-fledged placeholder, but rather a special case of <tt>_3</tt>.
As a consequence, <tt>_E</tt> cannot be used outside of an exception handler lambda expression, and <tt>_3</tt> cannot be used inside of an exception handler lambda expression.
Violating this rule is caught by the compiler.
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.
</p><div class="example"><p><a name="ex:exceptions"></a><b>Example 1. Throwing and handling exceptions in lambda expressions.</b></p><pre class="programlisting">
for_each(
a.begin(), a.end(),
try_catch(
bind(foo, _1), // foo may throw
catch_exception&lt;foo_exception&gt;(
cout &lt;&lt; constant(&quot;Caught foo_exception: &quot;)
&lt;&lt; &quot;foo was called with argument = &quot; &lt;&lt; _1
),
catch_exception&lt;std::exception&gt;(
cout &lt;&lt; constant(&quot;Caught std::exception: &quot;)
&lt;&lt; bind(&amp;std::exception::what, _E),
throw_exception(bind(constructor&lt;bar_exception&gt;(), _1)))
),
catch_all(
(cout &lt;&lt; constant(&quot;Unknown&quot;), rethrow())
)
)
);
</pre></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:construction_and_destruction"></a>5.8. Construction and destruction</h3></div></div></div><p>
Operators <tt>new</tt> and <tt>delete</tt> can be overloaded, but their return types are fixed.
Particularly, the return types cannot be lambda functors, which prevents them to be overloaded for lambda expressions.
It is not possible to take the address of a constructor, hence constructors cannot be used as target functions in bind expressions.
The same is true for destructors.
As a way around these constraints, BLL defines wrapper classes for <tt>new</tt> and <tt>delete</tt> calls, as well as for constructors and destructors.
Instances of these classes are function objects, that can be used as target functions of bind expressions.
For example:
<pre class="programlisting">
int* a[10];
for_each(a, a+10, _1 = bind(new_ptr&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.
</p><p>
As an example of constructor calls in lambda expressions, the following code reads integers from two containers <tt>x</tt> and <tt>y</tt>, constructs pairs out of them and inserts them into a third container:
<pre class="programlisting">
vector&lt;pair&lt;int, int&gt; &gt; v;
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.
</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.
For example:
<pre class="programlisting">
int foo(int); int bar(int);
...
int i;
bind(foo, bind(bar, _1)(i);
</pre>
The last line makes the call <tt>foo(bar(i));</tt>
Note that the first argument in a bind expression, the target function, is no exception, and can thus be a bind expression too.
The innermost lambda functor just has to return something that can be used as a target function: another lambda functor, function pointer, pointer to member function etc.
For example, in the following code the innermost lambda functor makes a selection between two functions, and returns a pointer to one of them:
<pre class="programlisting">
int add(int a, int b) { return a+b; }
int mul(int a, int b) { return a*b; }
int(*)(int, int) add_or_mul(bool x) {
return x ? add : mul;
}
bool condition; int i; int j;
...
bind(bind(&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.
In such a case, the programmer may not know whether the target function is a lambda functor or not.
</p><p>Consider the following function template:
<pre class="programlisting">
template&lt;class F&gt;
int nested(const F&amp; f) {
int x;
...
bind(f, _1)(x);
...
}
</pre>
Somewhere inside the function the formal parameter
<tt>f</tt> is used as a target function in a bind expression.
In order for this <tt>bind</tt> call to be valid, <tt>f</tt> must be a unary function.
Suppose the following two calls to <tt>nested</tt> are made:
<pre class="programlisting">
int foo(int);
int bar(int, int);
nested(&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:
<pre class="programlisting">
bind(bind(bar, 1, _1), _1)
</pre>
When this is invoked with <tt>x</tt>, after substituitions we end up trying to call
<pre class="programlisting">
bar(1, x)(x)
</pre>
which is an error.
The call to <tt>bar</tt> returns int, not a unary function or function object.
</p><p>
In the example above, the intent of the bind expression in the <tt>nested</tt> function is to treat <tt>f</tt> as an ordinary function object, instead of a lambda functor.
The BLL provides the function template <tt>unlambda</tt> to express this: a lambda functor wrapped inside <tt>unlambda</tt> is not a lambda functor anymore, and does not take part into the argument substitution process.
Note that for all other argument types <tt>unlambda</tt> is an identity operation, except for making non-const objects const.
</p><p>
Using <tt>unlambda</tt>, the <tt>nested</tt> function is written as:
<pre class="programlisting">
template&lt;class F&gt;
int nested(const F&amp; f) {
int x;
...
bind(unlambda(f), _1)(x);
...
}
</pre>
</p></div><div class="section"><div class="titlepage"><div><h5 class="title"><a name="id2805499"></a>5.9.1.2. Protect</h5></div></div><p>
The <tt>protect</tt> function is related to unlambda.
It is also used to prevent the argument substitution taking place, but whereas <tt>unlambda</tt> turns a lambda functor into an ordinary function object for good, <tt>protect</tt> does this temporarily, for just one evaluation round.
For example:
<pre class="programlisting">
int x = 1, y = 10;
(_1 + protect(_1 + 2))(x)(y);
</pre>
The first call substitutes <tt>x</tt> for the leftmost <tt>_1</tt>, and results in another lambda functor <tt>x + (_1 + 2)</tt>, which after the call with <tt>y</tt> becomes <tt>x + (y + 2)</tt>, and thus finally 13.
</p><p>
Primary motivation for including <tt>protect</tt> into the library, was to allow nested STL algorithm invocations (<a href="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.
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:
<pre class="programlisting">
int i = 1; int j = 2;
(_1 + _2)(i, j); // ok
(_1 + _2)(1, 2); // error (!)
</pre>
<div class="orderedlist"><ol type="1"><li><p>
If the rvalue is of a class type, the return type of the function that creates the rvalue should be defined as const. Due to an unfortunate language restriction this does not work for built-in types, as built-in rvalues cannot be const qualified. </p></li><li><p>
If the lambda function call is accessible, the <tt>make_const</tt> function can be used to <span class="emphasis"><i>constify</i></span> the rvalue. E.g.:
<pre class="programlisting">
(_1 + _2)(make_const(1), make_const(2)); // ok</pre>
Commonly the lambda function call site is inside a standard algorithm function template, preventing this solution to be used.
</p></li><li><p>
If neither of the above is possible, the lambda expression can be wrapped in a <tt>const_parameters</tt> function.
It creates another type of lambda functor, which takes its arguments as const references. For example:
<pre class="programlisting">
const_parameters(_1 + _2)(1, 2); // ok
</pre>
Note that <tt>const_parameters</tt> makes all arguments const.
Hence, in the case were one of the arguments is a non-const rvalue, and another argument needs to be passed as a non-const reference, this approach cannot be used.
</p></li><li><p>If none of the above is possible, there is still one solution, which unfortunately can break const correctness.
The solution is yet another lambda functor wrapper, which we have named <tt>break_const</tt> to alert the user of the potential dangers of this function.
The <tt>break_const</tt> function creates a lambda functor that takes its arguments as const, and casts away constness prior to the call to the original wrapped lambda functor.
For example:
<pre class="programlisting">
int i;
...
(_1 += _2)(i, 2); // error, 2 is a non-const rvalue
const_parameters(_1 += _2)(i, 2); // error, i becomes const
break_const(_1 += _2)(i, 2); // ok, but dangerous
</pre>
Note, that the results of
<tt> break_const</tt> or <tt>const_parameters</tt> are not lambda functors, so they cannot be used as subexpressions of lambda expressions. For instance:
<pre class="programlisting">
break_const(_1 + _2) + _3; // fails.
const_parameters(_1 + _2) + _3; // fails.
</pre>
However, this kind of code should never be necessary, since calls to sub lambda functors are made inside the BLL, and are not affected by the non-const rvalue problem.
</p></li></ol></div>
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="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.
If the argument is a lambda functor, the lambda functor is evaluated first.
For example, the following code uses <tt>ll_dynamic_cast</tt> to count the number of <tt>derived</tt> instances in the container <tt>a</tt>:
<pre class="programlisting">
class base {};
class derived : public base {};
vector&lt;base*&gt; a;
...
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="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.
For example:
<pre class="programlisting">
vector&lt;base*&gt; a;
...
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.
</p></div></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="sect:nested_stl_algorithms"></a>5.11. Nesting STL algorithm invocations</h3></div></div><p>
The BLL defines common STL algorithms as function object classes, instances of which can be used as target functions in bind expressions.
For example, the following code iterates over the elements of a two-dimensional array, and computes their sum.
<pre class="programlisting">
int a[100][200];
int sum = 0;
std::for_each(a, a + 100,
bind(ll::for_each(), _1, _1 + 200, protect(sum += _1)));
</pre>
The BLL versions of the STL algorithms are classes, which define the function call operator (or several overloaded ones) to call the corresponding function templates in the <tt>std</tt> namespace.
All these structs are placed in the subnamespace <tt>boost::lambda:ll</tt>.
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.
In general, something analogous to the pseudo-code below cannot be written:
<pre class="programlisting">
std::for_each(a.begin(), a.end(),
bind(ll::for_each(), _1.begin(), _1.end(), protect(sum += _1)));
</pre>
Some aid for common special cases can be provided though.
The BLL defines two helper function object classes, <tt>call_begin</tt> and <tt>call_end</tt>, which wrap a call to the <tt>begin</tt> and, respectively, <tt>end</tt> functions of a container, and return the <tt>const_iterator</tt> type of the container.
With these helper templates, the above code becomes:
<pre class="programlisting">
std::for_each(a.begin(), a.end(),
bind(ll::for_each(),
bind(call_begin(), _1), bind(call_end(), _1),
protect(sum += _1)));
</pre>
</p><div 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>

124
doc/ar01s06.html Normal file
View File

@@ -0,0 +1,124 @@
<!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>6. Extending return type deduction system</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="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.
Sometimes this cannot be avoided, though.
</p><p>
The overloadable user defined operators are either unary or binary.
For each arity, there are two traits templates that define the return types of the different operators.
Hence, the return type system can be extended by providing more specializations for these templates.
The templates for unary functors are
<tt>
plain_return_type_1&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 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>
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>:
<pre class="programlisting">
namespace boost {
namespace lambda {
template&lt;class Act&gt;
struct plain_return_type_2&lt;arithmetic_action&lt;Act&gt;, X, Y&gt; {
typedef Z type;
};
}
}
</pre>
Having this specialization defined, BLL is capable of correctly deducing the return type of the above two operators.
Note, that the specializations must be in the same namespace, <tt>::boost::lambda</tt>, with the primary template.
For brevity, we do not show the namespace definitions in the examples below.
</p><p>
It is possible to specialize on the level of an individual operator as well, in addition to providing a specialization for a group of operators. Say, we add a new arithmetic operator for argument types <tt>X</tt> and <tt>Y</tt>:
<pre class="programlisting">
X operator*(const X&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.
Hence, we provide a new rule for the multiplication operator:
<pre class="programlisting">
template&lt;&gt;
struct plain_return_type_2&lt;arithmetic_action&lt;multiply_action&gt;, X, Y&gt; {
typedef X type;
};
</pre>
</p><p>
The specializations can define arbitrary mappings from the argument types to the return type.
Suppose we have some mathematical vector type, templated on the element type:
<pre class="programlisting">template &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.
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&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&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:
<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&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 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>

85
doc/ar01s07.html Normal file
View File

@@ -0,0 +1,85 @@
<!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>7. Practical considerations</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="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.
</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, 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.
Compiling such expressions may end up requiring a lot of memory
at compile time, and being slow to compile.
</p></li><li><p>
The types of lambda functors that result from even the simplest lambda expressions are cryptic.
Usually the programmer doesn't need to deal with the lambda functor the types at all, but in the case of an error in a lambda expression, the compiler usually outputs the types of the lambda functors involved.
This can make the error messages very long and difficult to interpret, particularly if the compiler outputs the whole chain of template instantiations.
</p></li><li><p>
The C++ Standard suggests a template nesting level of 17 to help detect infinite recursion.
Complex lambda templates can easily exceed this limit.
Most compilers allow a greater number of nested templates, but commonly require the limit explicitly increased with a command line argument.
</p></li></ul></div></p></div><div class="section"><div class="titlepage"><div><h3 class="title"><a name="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.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="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.
Function composition with bind expressions.</p></li><li><p><tt>bind_tests_simple_function_references.cpp</tt> :
Repeats all tests from <tt>bind_tests_simple.cpp</tt> where the target function is a function pointer, but uses function references instead.
</p></li><li><p><tt>bind_tests_advanced.cpp</tt> : Contains tests for nested bind expressions, <tt>unlambda</tt>, <tt>protect</tt>, <tt>const_parameters</tt> and <tt>break_const</tt>.
Tests passing lambda functors as actual arguments to other lambda functors, currying, and using the <tt>sig</tt> template to specify the return type of a function object.
</p></li><li><p>
<tt>operator_tests_simple.cpp</tt> :
Tests using all operators that are overloaded for lambda expressions, that is, unary and binary arithmetic,
bitwise,
comparison,
logical,
increment and decrement,
compound,
assignment,
subscrict,
address of,
dereference, and comma operators.
The streaming nature of shift operators is tested, as well as pointer arithmetic with plus and minus operators.
</p></li><li><p><tt>member_pointer_test.cpp</tt> : The pointer to member operator is complex enough to warrant a separate test file.
</p></li><li><p>
<tt>control_structures.cpp</tt> :
Tests for the looping and if constructs.
</p></li><li><p>
<tt>switch_construct.cpp</tt> :
Includes tests for all supported arities of the switch statement, both with and without the default case.
</p></li><li><p>
<tt>exception_test.cpp</tt> :
Includes tests for throwing exceptions and for try/catch constructs with varying number of catch blocks.
</p></li><li><p>
<tt>constructor_tests.cpp</tt> :
Contains tests for <tt>constructor</tt>, <tt>destructor</tt>, <tt>new_ptr</tt>, <tt>delete_ptr</tt>, <tt>new_array</tt> and <tt>delete_array</tt>.
</p></li><li><p>
<tt>cast_test.cpp</tt> : Tests for the four cast expressions, as well as <tt>typeid</tt> and <tt>sizeof</tt>.
</p></li><li><p>
<tt>extending_return_type_traits.cpp</tt> : Tests extending the return type deduction system for user defined types.
Contains several user defined operators and the corresponding specializations for the return type deduction templates.
</p></li><li><p>
<tt>is_instance_of_test.cpp</tt> : Includes tests for an internally used traits template, which can detect whether a given type is an instance of a certain template or not.
</p></li><li><p>
<tt>bll_and_function.cpp</tt> :
Contains tests for using <tt>boost::function</tt> together with lambda functors.
</p></li></ul></div>
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s06.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="ar01s08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6. Extending return type deduction system </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 8. Relation to other Boost libraries</td></tr></table></div></body></html>

143
doc/ar01s08.html Normal file
View File

@@ -0,0 +1,143 @@
<!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>8. Relation to other Boost libraries</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="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 (almost) arbitrary function objects; and these wrappers have types that are easy to type out.
For example:
<pre class="programlisting">
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.
</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 = 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="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.
The same holds for using BLL bind expressions in the BB.
The libraries can coexist, however, as
the names of the BB library are in <tt>boost</tt> namespace, whereas the BLL names are in <tt>boost::lambda</tt> namespace.
</p><p>
The BLL requires a compiler that is reasonably conformant to the C++ standard, whereas the BB library is more portable, and works 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="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.
For example:
<pre class="programlisting">
template&lt;class F&gt;
int foo(const F&amp; f) {
int x;
..
bind(f, _1)(x);
...
}
</pre><pre class="programlisting">
int bar(int, int);
nested(bind(bar, 1, _1));
</pre>
The bind expression inside <tt>foo</tt> becomes:
<pre class="programlisting">
bind(bind(bar, 1, _1), _1)(x)
</pre>
The BLL interpretes this as:
<pre class="programlisting">
bar(1, x)(x)
</pre>
whereas the BB library as
<pre class="programlisting">
bar(1, x)
</pre>
To get this functionality in BLL, the bind expression inside the <tt>foo</tt> function can be written as:
<pre class="programlisting">
bind(unlambda(f), _1)(x);
</pre>
as explained in <a href="ar01s05.html#sect:unlambda" title="5.9.1.1. Unlambda">Section 5.9.1.1</a>.
</div><div class="section"><div class="titlepage"><div><h4 class="title"><a name="id2808206"></a>8.2.2.
Arity of function objects
</h4></div></div><p>
In both libraries, the highest placeholder index in a bind expression determines the arity of the resulting function object.
However, in the BB library, this is kind of a minimal arity, as the function object can take arbitrarily many arguments; those not needed are discarded.
Consider the two bind expressions and their invocations below:
<pre class="programlisting">
bind(g, _3, _3, _3)(x, y, z);
bind(g, _1, _1, _1)(x, y, z);
</pre>
This first line ends up making the call:
<pre class="programlisting">
g(z, z, z)
</pre>
in both libraries.
The second line is treated differently.
In BLL a compile time error will result, whereas BB will silently ignore the superfluous arguments and invoke:
<pre class="programlisting">
g(x, x, x)
</pre>
In this tradeoff between safety and flexibility, BLL takes the safer route.
Note however, that it is easy to write a lambda functor that would make the above call to
<tt>g(x, x, x)</tt> discarding all but the first argument:
<pre class="programlisting">
(_3, bind(g, _1, _1, _1))(x, y, z);
</pre>
This lambda expression takes three arguments.
The left-hand argument of the comma operator does nothing, and as comma returns the result of evaluating the right-hand argument we end up with the call
<tt>g(x, x, x)</tt>.
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7. Practical considerations </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 9. Contributors</td></tr></table></div></body></html>

13
doc/ar01s09.html Normal file
View File

@@ -0,0 +1,13 @@
<!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>9. Contributors</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="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.
</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>

18
doc/bi01.html Normal file
View File

@@ -0,0 +1,18 @@
<!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>Bibliography</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"></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>
<span class="title"><I>C++ Function Object Binders Made Easy</I>. </span>
. </span><span class="title"><I>Lecture Notes in Computer Science</I>. </span><span class="volumenum">1977. </span><span class="publishername">Springer. </span><span class="pubdate">2000. </span></p></div><div class="biblioentry"><a name="cit:jarvi:00"></a><p>[Jär00] <span class="author">Jaakko Järvi. </span><span class="author">Gary Powell. </span><span class="title"><I>The Lambda Library : Lambda Abstraction in C++</I>. </span><span class="orgname">Turku Centre for Computer Science. </span><span class="bibliomisc">Technical Report . </span><span class="issuenum">378. </span><span class="pubdate">2000. </span><span class="bibliomisc"><a href="http://www.tucs.fi/Publications/techreports/TR378.php" target="_top">www.tucs.fi/publications</a>. </span></p></div><div class="biblioentry"><a name="cit:jarvi:01"></a><p>[Jär01] <span class="author">Jaakko Järvi. </span><span class="author">Gary Powell. </span><span class="title"><I>The Lambda Library : Lambda Abstraction in C++</I>. </span><span class="confgroup"><span class="conftitle">Second Workshop on C++ Template Programming. </span><span class="address">Tampa Bay, OOPSLA'01. </span>. </span><span class="pubdate">2001. </span><span class="bibliomisc"><a href="http://www.oonumerics.org/tmpw01/" target="_top">www.oonumerics.org/tmpw01/</a>. </span></p></div><div class="biblioentry"><a name="cit:boost::tuple"></a><p>[tuple] <span class="title"><I>The Boost Tuple Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html" target="_top">www.boost.org/libs/tuple/doc/tuple_users_guide.html</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::type_traits"></a><p>[type_traits] <span class="title"><I>The Boost type_traits</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/type_traits/index.htm" target="_top">www.boost.org/libs/type_traits/</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::ref"></a><p>[ref] <span class="title"><I>Boost ref</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/ref.html" target="_top">www.boost.org/libs/bind/ref.html</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::bind"></a><p>[bind] <span class="title"><I>Boost Bind Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/bind/bind.html" target="_top">www.boost.org/libs/bind/bind.html</a>
. </span><span class="pubdate">2002. </span></p></div><div class="biblioentry"><a name="cit:boost::function"></a><p>[function] <span class="title"><I>Boost Function Library</I>. </span><span class="bibliomisc"><a href="http://www.boost.org/libs/function/" target="_top">www.boost.org/libs/function/</a>
. </span><span class="pubdate">2002. </span></p></div></div><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>

37
doc/index.html Normal file
View File

@@ -0,0 +1,37 @@
<!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>
C++ BOOST
The Boost Lambda Library</title><meta name="generator" content="DocBook XSL Stylesheets V1.48"><link rel="home" href="index.html" title="
C++ BOOST
The Boost Lambda Library"><link rel="next" href="ar01s02.html" title="2. Getting Started"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">
C++ BOOST
The Boost Lambda Library</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s02.html">Next</a></td></tr></table><hr></div><div class="article"><div class="titlepage"><div><h1 class="title"><a name="id2733458"></a>
<span class="inlinemediaobject"><img src="../../../c++boost.gif" alt="C++ BOOST"></span>
The Boost Lambda Library</h1></div><div><p class="copyright">Copyright © 1999-2002 Jaakko Järvi, Gary Powell</p></div><div><div class="legalnotice"><p>
The Boost Lambda Library is free software; Permission to copy,
use, modify and distribute this software and its documentation is granted, provided this copyright
notice appears in all copies.
</p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt>1. <a href="index.html#introduction">In a nutshell</a></dt><dt>2. <a href="ar01s02.html">Getting Started</a></dt><dd><dl><dt>2.1. <a href="ar01s02.html#id2790112">Installing the library</a></dt><dt>2.2. <a href="ar01s02.html#id2742926">Conventions used in this document</a></dt></dl></dd><dt>3. <a href="ar01s03.html">Introduction</a></dt><dd><dl><dt>3.1. <a href="ar01s03.html#id2742980">Motivation</a></dt><dt>3.2. <a href="ar01s03.html#id2741408">Introduction to lambda expressions</a></dt></dl></dd><dt>4. <a href="ar01s04.html">Using the library</a></dt><dd><dl><dt>4.1. <a href="ar01s04.html#sect:introductory_examples">Introductory Examples</a></dt><dt>4.2. <a href="ar01s04.html#sect:parameter_and_return_types">Parameter and return types of lambda functors</a></dt><dt>4.3. <a href="ar01s04.html#sect:actual_arguments_to_lambda_functors">About actual arguments to lambda functors</a></dt><dt>4.4. <a href="ar01s04.html#sect:storing_bound_arguments">Storing bound arguments in lambda functions</a></dt></dl></dd><dt>5. <a href="ar01s05.html">Lambda expressions in details</a></dt><dd><dl><dt>5.1. <a href="ar01s05.html#sect:placeholders">Placeholders</a></dt><dt>5.2. <a href="ar01s05.html#sect:operator_expressions">Operator expressions</a></dt><dt>5.3. <a href="ar01s05.html#sect:bind_expressions">Bind expressions</a></dt><dt>5.4. <a href="ar01s05.html#sect:overriding_deduced_return_type">Overriding the deduced return type</a></dt><dt>5.5. <a href="ar01s05.html#sect:delaying_constants_and_variables">Delaying constants and variables</a></dt><dt>5.6. <a href="ar01s05.html#sect:lambda_expressions_for_control_structures">Lambda expressions for control structures</a></dt><dt>5.7. <a href="ar01s05.html#sect:exceptions">Exceptions</a></dt><dt>5.8. <a href="ar01s05.html#sect:construction_and_destruction">Construction and destruction</a></dt><dt>5.9. <a href="ar01s05.html#id2805233">Special lambda expressions</a></dt><dt>5.10. <a href="ar01s05.html#id2805803">Casts, sizeof and typeid</a></dt><dt>5.11. <a href="ar01s05.html#sect:nested_stl_algorithms">Nesting STL algorithm invocations</a></dt></dl></dd><dt>6. <a href="ar01s06.html">Extending return type deduction system</a></dt><dt>7. <a href="ar01s07.html">Practical considerations</a></dt><dd><dl><dt>7.1. <a href="ar01s07.html#id2807383">Performance</a></dt><dt>7.2. <a href="ar01s07.html#id2807426">About compiling</a></dt><dt>7.3. <a href="ar01s07.html#id2807495">Portability</a></dt></dl></dd><dt>8. <a href="ar01s08.html">Relation to other Boost libraries</a></dt><dd><dl><dt>8.1. <a href="ar01s08.html#id2807887">Boost Function</a></dt><dt>8.2. <a href="ar01s08.html#id2808050">Boost Bind</a></dt></dl></dd><dt>9. <a href="ar01s09.html">Contributors</a></dt><dt><a href="bi01.html">Bibliography</a></dt></dl></div><div class="section"><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="introduction"></a>1. In a nutshell</h2></div></div><p>
The Boost Lambda Library (BLL in the sequel) is a C++ template
library, which implements form of <span class="emphasis"><i>lambda abstractions</i></span> for C++.
The term originates from functional programming and lambda calculus, where a lambda abstraction defines an unnamed function.
The primary motivation for the BLL is to provide flexible and
convenient means to define unnamed function objects for STL algorithms.
In explaining what the library is about, a line of code says more than a thousand words; the
following line outputs the elements of some STL container
<tt>a</tt> separated by spaces:
<pre class="programlisting">for_each(a.begin(), a.end(), std::cout &lt;&lt; _1 &lt;&lt; ' ');</pre>
The expression <tt>std::cout &lt;&lt; _1 &lt;&lt; ' '</tt> defines a unary function object.
The variable <tt>_1</tt> is the parameter of this function, a <span class="emphasis"><i>placeholder</i></span> for the actual argument.
Within each iteration of <tt>for_each</tt>, the function is
called with an element of <tt>a</tt> as the actual argument.
This actual argument is substituted for the placeholder, and the &#8216;body&#8217; of the function is evaluated.
</p><p>The essence of BLL is letting you define small unnamed function objects, such as the one above, directly on the call site of an STL algorithm.
</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"> </td><td width="40%" align="right" valign="top"> 2. Getting Started</td></tr></table></div></body></html>

1646
doc/lambda_doc.html Normal file

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

0
dummy
View File

View File

@@ -0,0 +1,202 @@
// -- algorithm.hpp -- Boost Lambda Library -----------------------------------
// Copyright (C) 2002 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
#ifndef BOOST_LAMBDA_ALGORITHM_HPP
#define BOOST_LAMBDA_ALGORITHM_HPP
#include "boost/lambda/core.hpp"
#include <algorithm>
namespace boost {
namespace lambda {
namespace ll {
// for_each ---------------------------------
struct for_each : public has_sig {
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::remove_reference<
typename boost::tuples::element<3, Args>::type
>::type
>::type type;
};
template <class A, class B, class C>
C
operator()(A a, B b, C c) const
{ return ::std::for_each(a, b, c); }
};
// find ---------------------------------
struct find : public has_sig {
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::remove_reference<
typename boost::tuples::element<1, Args>::type
>::type
>::type type;
};
template <class A, class B, class C>
A
operator()(A a, B b, const C& c) const
{ return ::std::find(a, b, c); }
};
// find_if ---------------------------------
struct find_if : public has_sig {
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::remove_reference<
typename boost::tuples::element<1, Args>::type
>::type
>::type type;
};
template <class A, class B, class C>
A
operator()(A a, B b, C c) const
{ return ::std::find_if(a, b, c); }
};
// find_end ---------------------------------
struct find_end : public has_sig {
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::remove_reference<
typename boost::tuples::element<1, Args>::type
>::type
>::type type;
};
template <class A, class B, class C, class D>
A
operator()(A a, B b, C c, D d) const
{ return ::std::find_end(a, b, c, d); }
template <class A, class B, class C, class D, class E>
A
operator()(A a, B b, C c, D d, E e) const
{ return ::std::find_end(a, b, c, d, e); }
};
// find_first_of ---------------------------------
struct find_first_of : public has_sig {
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::remove_reference<
typename boost::tuples::element<1, Args>::type
>::type
>::type type;
};
template <class A, class B, class C, class D>
A
operator()(A a, B b, C c, D d) const
{ return ::std::find_first_of(a, b, c, d); }
template <class A, class B, class C, class D, class E>
A
operator()(A a, B b, C c, D d, E e) const
{ return ::std::find_first_of(a, b, c, d, e); }
};
// transform --------------------------------
struct transform : public has_sig {
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::remove_reference<
typename boost::tuples::element<
boost::tuples::length<Args>::value - 2,
Args
>::type
>::type
>::type type;
};
template <class A, class B, class C, class D>
C
operator()(A a, B b, C c, D d) const
{ return std::transform(a, b, c, d);}
template <class A, class B, class C, class D, class E>
D
operator()(A a, B b, C c, D d, E e)
{ return std::transform(a, b, c, d, e);}
};
} // end of ll namespace
// There is no good way to call an overloaded member function in a
// lambda expression.
// The macro below defines a function object class for calling a
// const_iterator returning member function of a container.
#define CALL_MEMBER(X) \
struct call_##X : public has_sig { \
template <class Args> \
struct sig { \
typedef typename boost::remove_const< \
typename boost::remove_reference< \
typename boost::tuples::element<1, Args>::type \
>::type \
>::type::const_iterator type; \
}; \
\
template<class T> \
typename T::const_iterator \
operator()(const T& t) const \
{ \
return t.X(); \
} \
};
// create call_begin and call_end classes
CALL_MEMBER(begin)
CALL_MEMBER(end)
#undef CALL_MEMBER
} // end of lambda namespace
} // end of boost namespace
#endif

View File

@@ -0,0 +1,24 @@
// -- bind.hpp -- Boost Lambda Library --------------------------------------
// Copyright (C) 1999-2001 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
// 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_BIND_HPP
#define BOOST_LAMBDA_BIND_HPP
#include "boost/lambda/core.hpp"
#include "boost/lambda/detail/bind_functions.hpp"
#endif

View File

@@ -0,0 +1,255 @@
// - casts.hpp -- BLambda Library -------------
//
// 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 http://www.boost.org
// -----------------------------------------------
#if !defined(BOOST_LAMBDA_CASTS_HPP)
#define BOOST_LAMBDA_CASTS_HPP
#include <typeinfo>
namespace boost {
namespace lambda {
template<class T> class cast_action;
template<class T> class static_cast_action;
template<class T> class dynamic_cast_action;
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:
template<class RET, class Arg1>
static RET apply(Arg1 &a1) {
return static_cast<RET>(a1);
}
};
template<class T> class cast_action<dynamic_cast_action<T> > {
public:
template<class RET, class Arg1>
static RET apply(Arg1 &a1) {
return dynamic_cast<RET>(a1);
}
};
template<class T> class cast_action<const_cast_action<T> > {
public:
template<class RET, class Arg1>
static RET apply(Arg1 &a1) {
return const_cast<RET>(a1);
}
};
template<class T> class cast_action<reinterpret_cast_action<T> > {
public:
template<class RET, class Arg1>
static RET apply(Arg1 &a1) {
return reinterpret_cast<RET>(a1);
}
};
// typedid action
class typeid_action {
public:
template<class RET, class Arg1>
static RET apply(Arg1 &a1) {
return typeid(a1);
}
};
// sizeof action
class sizeof_action
{
public:
template<class RET, class Arg1>
static RET apply(Arg1 &a1) {
return sizeof(a1);
}
};
// return types of casting lambda_functors (all "T" type.)
template<template <class T> class cast_type, class T, class Args, int Code, class Open>
struct return_type<lambda_functor_args<action<1, cast_action< cast_type<T> > >, Args, Code>,
Open>
{
typedef T type;
};
// return type of typeid_action
template<class Args, int Code, class Open>
struct return_type<lambda_functor_args<action<1, typeid_action >, Args, Code>,
Open>
{
typedef std::type_info const & type;
};
// return type of sizeof_action
template<class Args, int Code, class Open>
struct return_type<lambda_functor_args<action<1, sizeof_action >, Args, Code>,
Open >
{
typedef std::size_t type;
};
// the four cast & typeid overloads.
// casts can take ordinary variables (not just lambda functors)
// static_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_args<
action<1,
cast_action<static_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_static_cast(const Arg1& a1) {
return lambda_functor< lambda_functor_args<
action<1,
cast_action<static_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value> >
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
}
// dynamic_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_args<
action<1,
cast_action<dynamic_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_dynamic_cast(const Arg1& a1) {
return lambda_functor< lambda_functor_args<
action<1,
cast_action<dynamic_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value> >
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
}
// const_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_args<
action<1,
cast_action<const_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_const_cast(const Arg1& a1) {
return lambda_functor< lambda_functor_args<
action<1,
cast_action<const_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value> >
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
}
// reinterpret_cast
template <class T, class Arg1>
inline const lambda_functor<
lambda_functor_args<
action<1,
cast_action<reinterpret_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_reinterpret_cast(const Arg1& a1) {
return lambda_functor< lambda_functor_args<
action<1,
cast_action<reinterpret_cast_action<T> >
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value> >
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
}
// typeid
// can be applied to a normal variable as well (can refer to a polymorphic
// class object)
template <class Arg1>
inline const lambda_functor<
lambda_functor_args<
action<1,
typeid_action
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value
>
>
ll_typeid(const Arg1& a1) {
return lambda_functor<lambda_functor_args<
action<1,
typeid_action
>,
tuple<typename const_copy_argument <const Arg1>::type>,
dig_arity<Arg1>::value> >
( tuple<typename const_copy_argument <const Arg1>::type>(a1));
}
// sizeof(expression)
// Always takes a lambda expression (if not, built in sizeof will do)
template <class Arg1>
inline const lambda_functor<
lambda_functor_args<
action<1, sizeof_action>,
tuple<lambda_functor<Arg1> >,
dig_arity<Arg1>::value
>
>
ll_sizeof(const lambda_functor<Arg1>& a1) {
return
lambda_functor<
lambda_functor_args<
action<1, sizeof_action>,
tuple<lambda_functor<Arg1> >,
dig_arity<Arg1>::value
>
>
( tuple<lambda_functor<Arg1> >(a1));
}
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,242 @@
// - construct.hpp -- Lambda Library -------------
//
// 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 http://www.boost.org
//
// -----------------------------------------------
#if !defined(BOOST_LAMBDA_CONSTRUCT_HPP)
#define BOOST_LAMBDA_CONSTRUCT_HPP
namespace boost {
namespace lambda {
// constructor is used together with bind. constructor<A> creates a bindable
// function object that passes its arguments forward to a constructor call
// of type A
template<class T> struct constructor {
typedef T result_type;
T operator()() const {
return T();
}
template<class A1>
T operator()(A1& a1) const {
return T(a1);
}
template<class A1, class A2>
T operator()(A1& a1, A2& a2) const {
return T(a1, a2);
}
template<class A1, class A2, class A3>
T operator()(A1& a1, A2& a2, A3& a3) const {
return T(a1, a2, a3);
}
template<class A1, class A2, class A3, class A4>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4) const {
return T(a1, a2, a3, a4);
}
template<class A1, class A2, class A3, class A4, class A5>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) const {
return T(a1, a2, a3, a4, a5);
}
template<class A1, class A2, class A3, class A4, class A5, class A6>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) const {
return T(a1, a2, a3, a4, a5, a6);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) const {
return T(a1, a2, a3, a4, a5, a6, a7);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) const {
return T(a1, a2, a3, a4, a5, a6, a7, a8);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9) const {
return T(a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
T operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9, A10& a10) const {
return T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
};
namespace detail {
// A standard conforming compiler could disambiguate between
// A1* and A1&, but not all compilers do that, so we need the
// helpers
template <bool IsPointer>
struct destructor_helper {
template<class A1>
static void exec(A1& a1) {
// remove all the qualifiers, not sure whether it is necessary
typedef typename boost::remove_cv<A1>::type plainA1;
a1.~plainA1();
}
};
template <>
struct destructor_helper<true> {
template<class A1>
static void exec(A1* a1) {
typedef typename boost::remove_cv<A1>::type plainA1;
(*a1).~plainA1();
}
};
}
// destructor funtion object
struct destructor {
typedef void result_type;
template<class A1>
void operator()(A1& a1) const {
typedef typename boost::remove_cv<A1>::type plainA1;
detail::destructor_helper<boost::is_pointer<plainA1>::value>::exec(a1);
}
};
// new_ptr is used together with bind.
// note: placement new is not supported
template<class T> struct new_ptr {
typedef T* result_type;
T* operator()() const {
return new T();
}
template<class A1>
T* operator()(A1& a1) const {
return new T(a1);
}
template<class A1, class A2>
T* operator()(A1& a1, A2& a2) const {
return new T(a1, a2);
}
template<class A1, class A2, class A3>
T* operator()(A1& a1, A2& a2, A3& a3) const {
return new T(a1, a2, a3);
}
template<class A1, class A2, class A3, class A4>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4) const {
return new T(a1, a2, a3, a4);
}
template<class A1, class A2, class A3, class A4, class A5>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) const {
return new T(a1, a2, a3, a4, a5);
}
template<class A1, class A2, class A3, class A4, class A5, class A6>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) const {
return new T(a1, a2, a3, a4, a5, a6);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) const {
return new T(a1, a2, a3, a4, a5, a6, a7);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8) const {
return new T(a1, a2, a3, a4, a5, a6, a7, a8);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9) const {
return new T(a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
T* operator()(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7, A8& a8, A9& a9, A10& a10) const {
return new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
};
// delete_ptr return void
struct delete_ptr {
typedef void result_type;
template <class A1>
void operator()(A1& a1) const {
delete a1;
}
};
// new_array is used together with bind.
template<class T> struct new_array {
typedef T* result_type;
T* operator()(int size) const {
return new T[size];
}
};
// delete_ptr return void
struct delete_array {
typedef void result_type;
template <class A1>
void operator()(A1& a1) const {
delete[] a1;
}
};
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,27 @@
// -- control_structures.hpp -- Boost Lambda Library --------------------------
// 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_CONTROL_STRUCTURES_HPP
#define BOOST_LAMBDA_CONTROL_STRUCTURES_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"
#include "boost/lambda/detail/control_structures_impl.hpp"
#include "boost/lambda/detail/switch.hpp"
#endif

View File

@@ -0,0 +1,72 @@
// -- core.hpp -- Boost Lambda Library -------------------------------------
//
// Includes the core of LL, without any real features for client:
//
// tuples, lambda functors, return type deduction templates,
// argument substitution mechanism (select functions)
//
// Some functionality comes as well:
// Assignment and subscript operators, as well as function
// call operator for placeholder variables.
// -------------------------------------------------------------------------
#ifndef BOOST_LAMBDA_CORE_HPP
#define BOOST_LAMBDA_CORE_HPP
#include "boost/type_traits/transform_traits.hpp"
#include "boost/type_traits/cv_traits.hpp"
#include "boost/tuple/tuple.hpp"
// inject some of the tuple names into lambda
namespace boost {
namespace lambda {
using ::boost::tuples::tuple;
using ::boost::tuples::null_type;
} // lambda
} // boost
#include "boost/lambda/detail/lambda_config.hpp"
#include "boost/lambda/detail/lambda_fwd.hpp"
#include "boost/lambda/detail/arity_code.hpp"
#include "boost/lambda/detail/actions.hpp"
#include "boost/lambda/detail/lambda_traits.hpp"
#include "boost/lambda/detail/function_adaptors.hpp"
#include "boost/lambda/detail/return_type_traits.hpp"
#include "boost/lambda/detail/select_functions.hpp"
#include "boost/lambda/detail/lambda_functor_base.hpp"
#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& _1 = free1;
boost::lambda::placeholder2_type& _2 = free2;
boost::lambda::placeholder3_type& _3 = free3;
// _1, _2, ... naming scheme by Peter Dimov
} // unnamed
} // lambda
} // boost
#endif //BOOST_LAMBDA_CORE_HPP

View File

@@ -0,0 +1,198 @@
// -- Boost Lambda Library - actions.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_ACTIONS_HPP
#define BOOST_LAMBDA_ACTIONS_HPP
namespace boost {
namespace lambda {
template<int Arity, class Act> class action;
// these need to be defined here, since the corresponding lambda
// functions are members of lambda_functor classes
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 {};
namespace detail {
class unspecified {};
}
// function action is a special case: bind functions can be called with
// the return type specialized explicitly e.g. bind<int>(foo);
// If this call syntax is used, the return type is stored in the latter
// 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<class T> class function_action<1, T> {
public:
template<class RET, class A1>
static RET apply(A1& a1) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>(a1);
}
};
template<class T> class function_action<2, T> {
public:
template<class RET, class A1, class A2>
static RET apply(A1& a1, A2& a2) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2);
}
};
template <class T> struct is_lambda_functor;
template<class T> class function_action<3, T> {
public:
template<class RET, class A1, class A2, class A3>
static RET apply(A1& a1, A2& a2, A3& a3) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3);
}
};
template<class T> class function_action<4, T> {
public:
template<class RET, class A1, class A2, class A3, class A4>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4);
}
};
template<class T> class function_action<5, T> {
public:
template<class RET, class A1, class A2, class A3, class A4, class A5>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5);
}
};
template<class T> class function_action<6, T> {
public:
template<class RET, class A1, class A2, class A3, class A4, class A5,
class A6>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6);
}
};
template<class T> class function_action<7, T> {
public:
template<class RET, class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7);
}
};
template<class T> class function_action<8, T> {
public:
template<class RET, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7,
A8& a8) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7, a8);
}
};
template<class T> class function_action<9, T> {
public:
template<class RET, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7,
A8& a8, A9& a9) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
};
template<class T> class function_action<10, T> {
public:
template<class RET, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9, class A10>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4, A5& a5, A6& a6, A7& a7,
A8& a8, A9& a9, A10& a10) {
return function_adaptor<typename boost::remove_const<A1>::type>::template apply<RET>
(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
};
// 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
#endif

View File

@@ -0,0 +1,128 @@
// -- Boost Lambda Library -------------------------------------------------
// 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_ARITY_CODE_HPP
#define BOOST_LAMBDA_ARITY_CODE_HPP
#include "boost/type_traits/cv_traits.hpp"
#include "boost/type_traits/transform_traits.hpp"
namespace boost {
namespace lambda {
// These constants state, whether a lambda_functor instantiation results from
// an expression which contains no placeholders (NONE),
// only free1 placeholders (FIRST),
// free2 placeholders and maybe free1 placeholders (SECOND),
// free3 and maybe free1 and free2 placeholders (THIRD),
// 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};
// -- dig the arity from lambda_functor_args;
template <class T> struct dig_arity;
namespace detail {
template <int Arity, int Step> struct reduce_arity
{
BOOST_STATIC_CONSTANT(int, value = Arity >> Step);
};
// The implementation template, do not instantiate this directly
template <class Arg> struct dig_arity_ {
static const int value = NONE;
};
template <class Args> struct dig_arity_<lambda_functor<Args> > {
static const int value = dig_arity<Args>::value;
// Args should be always plain, so it would be safe to instantiatie dig_arity_
// To be very sure, we use dig_arity
};
template <class Act, class Args, int ArityCode>
struct dig_arity_<lambda_functor_args<Act, Args, ArityCode> >{
static const int value = ArityCode;
};
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);
};
} // namespace lambda
} // namespace boost
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,580 @@
// Boost Lambda Library -- control_structures_impl.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_CONTROL_CONSTRUCTS_HPP)
#define BOOST_LAMBDA_CONTROL_CONSTRUCTS_HPP
namespace boost {
namespace lambda {
// -- void return control actions ----------------------
class forloop_action {};
class ifthen_action {};
class ifthenelse_action {};
class whileloop_action {};
class dowhileloop_action {};
// -- nonvoid return control actions ----------------------
class ifthenelsereturn_action {};
// For loop
template <class Arg1, class Arg2, class Arg3, class Arg4>
inline const
lambda_functor<
lambda_functor_args<
action<4, return_void_action<forloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
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<
lambda_functor_args<
action<4, return_void_action<forloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>,
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)
);
}
// No body case.
template <class Arg1, class Arg2, class Arg3>
inline const
lambda_functor<
lambda_functor_args<
action<3, return_void_action<forloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >,
combine_arities<Arg1, Arg2, Arg3>::value
>
>
for_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
const lambda_functor<Arg3>& a3) {
return
lambda_functor<
lambda_functor_args<
action<3, return_void_action<forloop_action> >,
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) );
}
// While loop
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_args<
action<2, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
return
lambda_functor<
lambda_functor_args<
action<2, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
}
// No body case.
template <class Arg1>
inline const
lambda_functor<
lambda_functor_args<
action<1, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
>
while_loop(const lambda_functor<Arg1>& a1) {
return
lambda_functor<
lambda_functor_args<
action<1, return_void_action<whileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
> ( tuple<lambda_functor<Arg1> >(a1) );
}
// Do While loop
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_args<
action<2, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
do_while_loop(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
return
lambda_functor<
lambda_functor_args<
action<2, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
}
// No body case.
template <class Arg1>
inline const
lambda_functor<
lambda_functor_args<
action<1, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
>
do_while_loop(const lambda_functor<Arg1>& a1) {
return
lambda_functor<
lambda_functor_args<
action<1, return_void_action<dowhileloop_action> >,
tuple<lambda_functor<Arg1> >,
combine_arities<Arg1>::value
>
> ( tuple<lambda_functor<Arg1> >(a1));
}
// If Then
template <class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_args<
action<2, return_void_action<ifthen_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
>
if_then(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2) {
return
lambda_functor<
lambda_functor_args<action<2, return_void_action<ifthen_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
> ( tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2) );
}
// If then else
template <class Arg1, class Arg2, class Arg3>
inline const
lambda_functor<
lambda_functor_args<
action<3, return_void_action<ifthenelse_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >,
combine_arities<Arg1, Arg2, Arg3>::value
>
>
if_then_else(const lambda_functor<Arg1>& a1, const lambda_functor<Arg2>& a2,
const lambda_functor<Arg3>& a3) {
return
lambda_functor<
lambda_functor_args<
action<3, return_void_action<ifthenelse_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2>, lambda_functor<Arg3> >,
combine_arities<Arg1, Arg2, Arg3>::value
>
>
(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_args<action<3, other_action<ifthenelsereturn_action> >,
tuple<lambda_functor<Arg1>,
typename const_copy_argument<Arg2>::type,
typename const_copy_argument<Arg3>::type>,
combine_arities<Arg1, Arg2, Arg3>::value
>
>
if_then_else_return(const lambda_functor<Arg1>& a1,
const Arg2 & a2,
const Arg3 & a3) {
return
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>,
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) );
}
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
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 -----------
// Control loop lambda_functor_base specializations.
// Specialization for for_loop.
template<class Args>
class
lambda_functor_base<action<4, return_void_action<forloop_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 {
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), a, b, c);
}
};
// No body case
template<class Args>
class
lambda_functor_base<action<3, return_void_action<forloop_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 {
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)) {}
}
};
// Specialization for while_loop.
template<class Args>
class
lambda_functor_base<action<2, return_void_action<whileloop_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 {
while(detail::select(boost::tuples::get<0>(args), a, b, c))
detail::select(boost::tuples::get<1>(args), a, b, c);
}
};
// No body case
template<class Args>
class
lambda_functor_base<action<1, return_void_action<whileloop_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 {
while(detail::select(boost::tuples::get<0>(args), a, b, c)) {}
}
};
// Specialization for do_while_loop.
// Note that the first argument is the condition.
template<class Args>
class
lambda_functor_base<action<2, return_void_action<dowhileloop_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 {
do {
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<action<1, return_void_action<dowhileloop_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 {
do {} while (detail::select(boost::tuples::get<0>(args), a, b, c) );
}
};
// Specialization for if_then.
template<class Args>
class
lambda_functor_base<action<2, return_void_action<ifthen_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 {
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<action<3, return_void_action<ifthenelse_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 {
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), a, b, c);
}
};
// Specialization of lambda_functor_base for if_then_else_return.
template<class Args>
class
lambda_functor_base<action<3, other_action<ifthenelsereturn_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)
:
detail::select(boost::tuples::get<2>(args), a, b, c);
}
};
} // lambda
} // boost
#endif // BOOST_LAMBDA_CONTROL_CONSTRUCTS_HPP

View File

@@ -0,0 +1,599 @@
// Boost Lambda Library - function_adaptors.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_FUNCTION_ADAPTORS_HPP
#define BOOST_LAMBDA_FUNCTION_ADAPTORS_HPP
#include "boost/type_traits/same_traits.hpp"
namespace boost {
namespace lambda {
template <class Func> struct function_adaptor {
typedef detail::unspecified type;
template<class RET, class A1>
static RET apply(A1& a1) {
return a1();
}
template<class RET, class A1, class A2>
static RET apply(A1& a1, A2& a2) {
return a1(a2);
}
template<class RET, class A1, class A2, class A3>
static RET apply(A1& a1, A2& a2, A3& a3) {
return a1(a2, a3);
}
template<class RET, class A1, class A2, class A3, class A4>
static RET apply(A1& a1, A2& a2, A3& a3, A4& a4) {
return a1(a2, a3, a4);
}
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 a1(a2, a3, a4, a5);
}
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 a1(a2, a3, a4, a5, a6);
}
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 a1(a2, a3, a4, a5, a6, a7);
}
template<class RET, class A1, class A2, class A3, class A4, class A5, 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 a1(a2, a3, a4, a5, a6, a7, a8);
}
template<class RET, class A1, class A2, class A3, class A4, class A5, 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 a1(a2, a3, a4, a5, a6, a7, a8, a9);
}
template<class RET, class A1, class A2, class A3, class A4, class A5, 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 a1(a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
};
// -- function adaptors with 1 argument apply
template <class Result>
struct function_adaptor<Result (void)> {
typedef Result type;
template <class RET>
static Result apply(Result (*func)()) {
return func();
}
};
template <class Result>
struct function_adaptor<Result (*)(void)> {
typedef Result type;
template <class RET>
static Result apply(Result (*func)()) {
return func();
}
};
// -- function adaptors with 2 argument apply
template <class Object, class Result>
struct function_adaptor<Result (Object::*)() const> {
typedef Result type;
template <class RET>
static Result apply( Result (Object::*func)() const, const Object* o) {
return (o->*func)();
}
template <class RET>
static Result apply( Result (Object::*func)() const, const Object& o) {
return (o.*func)();
}
};
template <class Object, class Result>
struct function_adaptor<Result (Object::*)()> {
typedef Result type;
template <class RET>
static Result apply( Result (Object::*func)(), Object* o) {
return (o->*func)();
}
template <class RET>
static Result apply( Result (Object::*func)(), Object& o) {
return (o.*func)();
}
};
template <class Arg1, class Result>
struct function_adaptor<Result (Arg1)> {
typedef Result type;
template <class RET, class A1>
static Result apply(Result (*func)(Arg1), A1& a1) {
return func(a1);
}
};
template <class Arg1, class Result>
struct function_adaptor<Result (*)(Arg1)> {
typedef Result type;
template <class RET, class A1>
static Result apply(Result (*func)(Arg1), A1& a1) {
return func(a1);
}
};
// -- function adaptors with 3 argument apply
template <class Object, class Arg1, class Result>
struct function_adaptor<Result (Object::*)(Arg1) const> {
typedef Result type;
template <class RET, class 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) {
return (o.*func)(a1);
}
};
template <class Object, class Arg1, class Result>
struct function_adaptor<Result (Object::*)(Arg1)> {
typedef Result type;
template <class RET, class A1>
static Result apply( Result (Object::*func)(Arg1), Object* o, A1& a1) {
return (o->*func)(a1);
}
template <class RET, class A1>
static Result apply( Result (Object::*func)(Arg1), Object& o, A1& a1) {
return (o.*func)(a1);
}
};
template <class Arg1, class Arg2, class Result>
struct function_adaptor<Result (Arg1, Arg2)> {
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);
}
};
template <class Arg1, class Arg2, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2)> {
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);
}
};
// -- function adaptors with 4 argument apply
template <class Object, class Arg1, class Arg2, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2) const> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Object, class Arg1, class Arg2, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2)> {
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);
}
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3)> {
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3)> {
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);
}
};
// -- function adaptors with 5 argument apply
template <class Object, class Arg1, class Arg2, class Arg3, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3) const> {
typedef Result type;
template <class 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);
}
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);
}
};
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);
}
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4)> {
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4)> {
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);
}
};
// -- function adaptors with 6 argument apply
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4) const> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4)> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5)> {
typedef Result type;
template <class 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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5)> {
typedef Result type;
template <class 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);
}
};
// -- function adaptors with 7 argument apply
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5) const> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5)> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
typedef Result type;
template <class 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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
typedef Result type;
template <class 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);
}
};
// -- function adaptors with 8 argument apply
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
typedef Result type;
template <class 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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
typedef Result type;
template <class 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);
}
};
// -- function adaptors with 9 argument apply
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) const> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7)> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
struct function_adaptor<Result (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> {
typedef Result type;
template <class 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);
}
};
template <class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
struct function_adaptor<Result (*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> {
typedef Result type;
template <class 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);
}
};
// -- function adaptors with 10 argument apply
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) const> {
typedef Result type;
template <class 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);
}
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);
}
};
template <class Object, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6, class Arg7, class Arg8, class Result>
struct function_adaptor<Result (Object::*)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8)> {
typedef Result type;
template <class 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);
}
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);
}
};
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);
}
};
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
#endif

View File

@@ -0,0 +1,109 @@
// Boost Lambda Library - is_instance_of.hpp ---------------------
// Copyright (C) 2001 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_IS_INSTANCE_OF
#define BOOST_LAMBDA_IS_INSTANCE_OF
#include "boost/config.hpp" // for BOOST_STATIC_CONSTANT
#include "boost/type_traits/conversion_traits.hpp" // for is_convertible
#include "boost/preprocessor/enum_shifted_params.hpp"
#include "boost/preprocessor/repeat_2nd.hpp"
// is_instance_of --------------------------------
//
// is_instance_of_n<A, B>::value is true, if type A is
// an instantiation of a template B, or A derives from an instantiation
// of template B
//
// n is the number of template arguments for B
//
// Example:
// is_instance_of_2<std::istream, basic_stream>::value == true
// The original implementation was somewhat different, with different versions
// for different compilers. However, there was still a problem
// with gcc.3.0.2 and 3.0.3 compilers, which didn't think regard
// is_instance_of_N<...>::value was a constant.
// John Maddock suggested the way around this problem by building
// is_instance_of templates using boost::is_convertible.
// Now we only have one version of is_instance_of templates, which delagate
// all the nasty compiler tricks to is_convertible.
#define BOOST_LAMBDA_CLASS(N,A) BOOST_PP_COMMA_IF(N) class
#define BOOST_LAMBDA_CLASS_ARG(N,A) BOOST_PP_COMMA_IF(N) class A##N
#define BOOST_LAMBDA_ARG(N,A) BOOST_PP_COMMA_IF(N) A##N
#define BOOST_LAMBDA_CLASS_LIST(n, NAME) BOOST_PP_REPEAT(n, BOOST_LAMBDA_CLASS, NAME)
#define BOOST_LAMBDA_CLASS_ARG_LIST(n, NAME) BOOST_PP_REPEAT(n, BOOST_LAMBDA_CLASS_ARG, NAME)
#define BOOST_LAMBDA_ARG_LIST(n, NAME) BOOST_PP_REPEAT(n, BOOST_LAMBDA_ARG, NAME)
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 */ \
\
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); \
};
#define BOOST_LAMBDA_HELPER(N, A) BOOST_LAMBDA_IS_INSTANCE_OF_TEMPLATE( BOOST_PP_INC(N) )
// Generate the traits for 1-4 argument templates
BOOST_PP_REPEAT_2ND(4,BOOST_LAMBDA_HELPER,FOO)
#undef BOOST_LAMBDA_HELPER
#undef BOOST_LAMBDA_IS_INSTANCE_OF_TEMPLATE
#undef BOOST_LAMBDA_CLASS
#undef BOOST_LAMBDA_ARG
#undef BOOST_LAMBDA_CLASS_ARG
#undef BOOST_LAMBDA_CLASS_LIST
#undef BOOST_LAMBDA_ARG_LIST
#undef BOOST_LAMBDA_CLASS_ARG_LIST
} // lambda
} // boost
#endif

View File

@@ -0,0 +1,46 @@
// Boost Lambda Library - lambda_config.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_LAMBDA_CONFIG_HPP
#define BOOST_LAMBDA_LAMBDA_CONFIG_HPP
// add to boost/config.hpp
// for now
# if defined __GNUC__
# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97)
#define BOOST_NO_TEMPLATED_STREAMS
#define BOOST_LAMBDA_INCORRECT_BIND_OVERLOADING
#endif
#endif // __GNUC__
#if defined __KCC
#define BOOST_NO_FDECL_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMS
#endif // __KCC
#endif

View File

@@ -0,0 +1,371 @@
// Boost Lambda Library 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_LAMBDA_FUNCTOR_BASE_HPP
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_HPP
namespace boost {
namespace lambda {
namespace detail {
// In a call make_rvalues_const<T>::exec(x)
// x should be of type T. If T is a non-reference type, exec
// returns x as const reference.
// Otherwise the type doesn't change.
// The purpose of this class is to avoid
// 'cannot bind temporaries to non-const references' errors.
template <class T> struct make_rvalues_const {
template<class U>
static const U& exec(const U& u) { return u; }
};
template <class T> struct make_rvalues_const<T&> {
template<class U>
static U& exec(U& u) { return u; }
};
template <int N, class Args, class A, class B, class C>
struct nth_return_type {
typedef typename
return_type<
typename tuple_element_as_reference<N, Args>::type,
open_args<A, B, C>
>::type type;
};
} // end detail
// -- lambda_functor base ---------------------
// the explicit_return_type_action case -----------------------------------
template<class RET, class 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 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::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<action<1, protect_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 boost::tuples::get<0>(args);
}
};
// The work of curry action is not defined in action class apply,
// but rather directly in lambda_functor_base::call
// The argument substitution would be messed up otherwise.
// the curry_action 2-ary lambda_functor, one curried arg -------------------
template<class Args>
class lambda_functor_base<action<3, curry_action<1> >, Args>
{
public:
Args args;
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 boost::tuples::get<0>(args).template ret_call<RET>(
boost::tuples::get<1>(args), a);
}
};
// 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) {}
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 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:
explicit lambda_functor_base(const Args& a) : args(a) {}
template<class RET, class A, class B, class C>
RET call(A& a, B& b, C& c) const
{
return boost::tuples::get<0>(args).template ret_call<RET>(
boost::tuples::get<1>(args), 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;\
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 detail::nth_return_type<0, Args, A&, B&, C&>::type ret0;
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 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;
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 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>(
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 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>(
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 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>(
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 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>(
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 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>(
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 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 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))
);
}
};
#undef BOOST_LAMBDA_LAMBDA_FUNCTOR_BASE_FIRST_PART
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,651 @@
// Boost Lambda Library - lambda_functors.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 http://www.boost.org
// ------------------------------------------------
#ifndef BOOST_LAMBDA_LAMBDA_FUNCTORS_HPP
#define BOOST_LAMBDA_LAMBDA_FUNCTORS_HPP
namespace boost {
namespace lambda {
// -- lambda_functor --------------------------------------------
// --------------------------------------------------------------
//inline const null_type const_null_type() { return null_type(); }
namespace detail {
namespace {
static const null_type constant_null_type = null_type();
} // unnamed
} // detail
#define const_null_type() detail::constant_null_type
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT"
#endif
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT\
template<class A>\
const lambda_functor<lambda_functor_args<\
action<2, other_action<assignment_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
operator=(const A& a) const { \
return lambda_functor<lambda_functor_args<\
action<2, other_action<assignment_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
( boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>(*this, a) );\
}\
\
#if defined BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
#error "Multiple defines of BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT"
#endif
#define BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT\
template<class A>\
const lambda_functor<lambda_functor_args<\
action<2, other_action<subscript_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
operator[](const A& a) const { \
return lambda_functor<lambda_functor_args<\
action<2, other_action<subscript_action> >,\
boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>,\
combine_arities<lambda_functor,A>::value> >\
( boost::tuple<lambda_functor, \
typename const_copy_argument <const A>::type>(*this, a ) );\
}\
\
// -- 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.
// -------------------------------------------------------------------
// template <int I>
// class lambda_functor<placeholder<I> > {
// public:
// lambda_functor() {}
// // (do nothing) bug in gcc 2.95.2 for const template objects.
// BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
// BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
// };
// covers _E, does not define (), cause it will only be called
// inside of other lambda functors.
template <int I>
class lambda_functor<placeholder<I> > {
public:
lambda_functor() {}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
template<>
class lambda_functor<placeholder<FIRST> > {
public:
lambda_functor() {}
template <class A>
A& operator()(A& a) const { return a; }
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
template<>
class lambda_functor<placeholder<SECOND> > {
public:
lambda_functor() {}
template <class A, class B>
B& operator()(A&, B& b) const { return b; }
// currying call: creates another lambda functor
template<class A>
placeholder1_type
operator()(A&) const { return _1; }
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
template<>
class lambda_functor<placeholder<THIRD> > {
public:
lambda_functor() {}
template <class A, class B, class C>
C& operator()(A&, B&, C& c) const { return c; }
// currying calls: create another lambda functor
template<class A>
placeholder2_type
operator()(A&) const { return _2; }
template<class A, class B>
placeholder1_type
operator()(A&, B&) const { return _1; }
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
namespace detail {
// helpers
template <class T> struct identity { typedef T type; };
// take the Nth element in the tuple, or null_type if tuple is not
// long enough
template <int N, class T>
struct element_or_null_type {
typedef typename
detail::IF_type<
(N < boost::tuples::length<T>::value),
boost::tuples::element<N, T>,
identity<null_type>
>::type type;
};
// Lambda functors all provide the sig member template for
// querying their return type.
// these type mappings implement the tools for that deduction
//type mapping to compute the new lambda functor resulting from a curried
// call.
template<class LF, int Args_expected, class SigArgs>
struct curry_sig {
// First arg in SigArgs is the lambda functor type, that's why the -1
BOOST_STATIC_CONSTANT(int, acount = boost::tuples::length<SigArgs>::value-1);
// currying is only supported for 2- and 3-ary lambda functors, and
// must be called by 1 or 2 arguments.
// acount 1 or 2, dig_arity<LF>::value SECOND or THIRD
typedef typename detail::element_or_null_type<1, SigArgs>::type el_1;
typedef typename detail::element_or_null_type<2, SigArgs>::type el_2;
typedef lambda_functor<
lambda_functor_args<
action<Args_expected + 1, curry_action<acount> >,
// remove_const_refernce takes care that const null_type will
// be null_type, that arrays are always stored as const refs,
// that nonconst refs remain nonconst refs, and everything else goes
// to const copy.
tuple<
LF,
typename detail::remove_const_reference<el_1>::type,
typename detail::remove_const_reference<el_2>::type
>,
detail::reduce_arity<dig_arity<LF>::value, acount>::value
>
> type;
};
// enter the normal return type deduction
template <class LF, class SigArgs>
struct eval_sig
{
typedef typename
return_type<
LF,
open_args<
typename detail::element_or_null_type<1, SigArgs>::type,
typename detail::element_or_null_type<2, SigArgs>::type,
typename detail::element_or_null_type<3, SigArgs>::type
>
>::type type;
};
// either a normal evaluation, or a curried call
template <class LF, int Args_expected, class SigArgs>
struct lambda_functor_sig
{
typedef typename
detail::IF_type<
(boost::tuples::length<SigArgs>::value - 1 < Args_expected),
detail::curry_sig<LF, Args_expected, SigArgs>,
detail::eval_sig<LF, SigArgs>
>::type type;
};
} // end detail
// -- lambda_functor NONE ------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, NONE> >
: public lambda_functor_base<Action, Args>, public has_sig
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples are copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, NONE> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 0, SigArgs>::type type;
};
typename return_type<
lambda_functor,
open_args<null_type, null_type, null_type>
>::type
operator()() const {
return inherited::template
call<
typename return_type<
lambda_functor,
open_args<null_type, null_type, null_type> >::type
>(const_null_type(), const_null_type(), const_null_type());
}
template<class RET>
RET ret_call() const {
return inherited:: template call<RET>(const_null_type(),
const_null_type(),
const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor FIRST -------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, FIRST> >
: public lambda_functor_base<Action, Args>
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, FIRST> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 1, SigArgs>::type type;
};
template<class A>
typename
return_type<lambda_functor, open_args<A&, null_type, null_type> >::type
operator()(A& a) const
{
return inherited::template call<
typename return_type<
lambda_functor, open_args<A&, null_type, null_type>
>::type
>(a, const_null_type(), const_null_type());
}
template<class RET, class A>
RET ret_call(A& a) const
{
return inherited:: template call<RET>(a, const_null_type(), const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor SECOND -------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, SECOND> >
: public lambda_functor_base<Action, Args>, public has_sig
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, SECOND> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 2, SigArgs>::type type;
};
template<class A, class B>
typename return_type<lambda_functor, open_args<A&, B&, null_type> >::type
operator()(A& a, B& b) const
{
return inherited::template call<
typename return_type<
lambda_functor, open_args<A&, B&, null_type>
>::type>(a, b, const_null_type());
}
// currying call: creates another lambda functor
template<class A>
typename sig<tuple<const lambda_functor&, A&> >::type
operator()(A& a) const
{
return
typename sig<tuple<const lambda_functor&, A&> >::type
(
tuple<lambda_functor,
typename detail::remove_const_reference<A&>::type>(*this, a)
);
}
template<class RET, class A, class B>
RET ret_call(A& a, B& b) const {
return inherited::template call<RET>(a, b, const_null_type());
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor THIRD -------------------------------------------------
template <class Action, class Args>
class lambda_functor<lambda_functor_args<Action, Args, THIRD> > : public lambda_functor_base<Action, Args>, public has_sig
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, THIRD> >& f)
: inherited(f.args) {}
template <class SigArgs> struct sig {
typedef typename
detail::lambda_functor_sig<lambda_functor, 3, SigArgs>::type type;
};
template<class A, class B, class C>
typename return_type<lambda_functor, open_args<A&, B&, C&> >::type
operator()(A& a, B& b, C& c) const
{
return inherited::template call<
typename return_type<lambda_functor, open_args<A&, B&, C&>
>::type>(a, b, c);
}
template<class RET, class A, class B, class C>
RET ret_call(A& a, B& b, C& c) const {
return inherited::template call<RET>(a, b, c);
}
// currying call, one argument still missing
template<class A, class B>
typename sig<tuple<const lambda_functor&, A&, B&> >::type
operator()(A& a, B& b) const
{
return
typename sig<tuple<const lambda_functor&, A&, B&> >::type
( tuple<
lambda_functor,
typename detail::remove_const_reference<A&>::type,
typename detail::remove_const_reference<B&>::type
> (*this, a, b)
);
}
// currying call, two arguments still missing
// The return type is:
// lambda_functor<
// lambda_functor_args<
// action<4, curry_action<1> >,
// detail::bind_tuple_mapper<lambda_functor, const A>::type,
// SECOND
// >
// >
template<class A>
typename sig<tuple<const lambda_functor&, A&> >::type
operator()(A& a) const
{
return
typename sig<tuple<const lambda_functor&, A&> >::type
(
tuple<lambda_functor, typename detail::remove_const_reference<A&>::type>(*this, a)
);
}
BOOST_LAMBDA_LAMBDA_FUNCTOR_ASSIGNMENT
BOOST_LAMBDA_LAMBDA_FUNCTOR_SUBSCRIPT
};
// -- lambda_functor (Arbitrary Code) ---------------------------------------
// matches any arity code with EXCEPTION or RETHROW bits on
// This specialisation is only instantiated if delayed exception
// handling is used. See exceptions.hpp.
// ----------------------------------------------------------
template <class Action, class Args, int Code>
class lambda_functor<lambda_functor_args<Action, Args, Code> >
: public lambda_functor_base<Action, Args>
{
public:
typedef lambda_functor_base<Action, Args> inherited;
explicit lambda_functor(const Args& args)
: inherited(args) {}
// lambda functors can be copied, if arity and action are the same
// and Args tuples copyable
template <class Args2> lambda_functor
(const lambda_functor<lambda_functor_args<Action, Args2, Code> >& f)
: inherited(f.args) {}
// No operator() for this, since this lambda_functor can only be used
// in a catch_exception or catch_all
template<class RET, class A, class B, class C>
RET ret_call(A& a, B& b, C& c) const
{
return inherited::template call<RET>(a, b, c);
}
};
// any lambda functor can be turned into a const_incorrect_lambda_functor
// The operator() takes arguments as consts and then casts constness
// away. So this breaks const correctness!!! but is a necessary workaround
// in some cases due to language limitations.
// Note, that this is not a lambda_functor anymore, so it can not be used
// as a sub lambda expression.
template <class Arg>
struct const_incorrect_lambda_functor
: private lambda_functor<Arg> {
public:
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
// only allowed for normal lambda functions, not EXCEPTION ones
typedef lambda_functor<Arg> inherited;
explicit const_incorrect_lambda_functor(const lambda_functor<Arg>& lf)
: inherited(lf.args) {}
template <class SigArgs> struct sig {
typedef typename
::boost::lambda::lambda_functor<Arg>::template sig<SigArgs>::type type;
};
typename sig<tuple<const lambda_functor<Arg>& > >::type
operator()() const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>& > >::type>();
}
template<class A>
typename sig<tuple<const lambda_functor<Arg>&, A&> >::type
operator()(const A& a) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&> >::type >(const_cast<A&>(a));
}
template<class A, class B>
typename sig<tuple<const lambda_functor<Arg>&, A&, B&> >::type
operator()(const A& a, const B& b) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&, B&> >::type >(const_cast<A&>(a), const_cast<B&>(b));
}
template<class A, class B, class C>
typename sig<tuple<const lambda_functor<Arg>&, A&, B&, C&> >::type
operator()(const A& a, const B& b, const C& c) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, A&, B&, C&> >::type>(const_cast<A&>(a), const_cast<B&>(b), const_cast<C&>(c));
}
};
// ------------------------------------------------------------------------
// any lambda functor can be turned into a const_parameter_lambda_functor
// The operator() takes arguments as const.
// This is useful if lambda functors are called with non-const rvalues.
// Note, that this is not a lambda_functor anymore, so it can not be used
// as a sub lambda expression.
template <class Arg>
struct const_parameter_lambda_functor
: private lambda_functor<Arg> {
public:
BOOST_STATIC_ASSERT(dig_arity<Arg>::value <= THIRD);
// only allowed for normal lambda functions, not EXCEPTION ones
typedef lambda_functor<Arg> inherited;
explicit const_parameter_lambda_functor(const lambda_functor<Arg>& lf)
: inherited(lf.args) {}
template <class SigArgs> struct sig {
typedef typename
::boost::lambda::lambda_functor<Arg>::template sig<SigArgs>::type type;
};
// This is provided just for completeness; no arguments, no constness
// problems.
typename sig<tuple<const lambda_functor<Arg>& > >::type
operator()() const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>& > >::type>();
}
template<class A>
typename sig<tuple<const lambda_functor<Arg>&, const A&> >::type
operator()(const A& a) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&> >::type >(a);
}
template<class A, class B>
typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&> >::type
operator()(const A& a, const B& b) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&> >::type >(a, b);
}
template<class A, class B, class C>
typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&, const C&> >::type
operator()(const A& a, const B& b, const C& c) const {
return inherited::template ret_call<typename sig<tuple<const lambda_functor<Arg>&, const A&, const B&, const C&> >::type>(a, b, c);
}
};
// Tagged lambda_functor -------------
// This is a generic class for special types of lambda functors,
// e.g. certain parameters of switch_statement must be case_statements,
// rather than arbitrary lambda functors
template<class Tag, class LambdaFunctor>
class tagged_lambda_functor;
template<class Tag, class Args>
class tagged_lambda_functor<Tag, lambda_functor<Args> >
: public lambda_functor<Args>
{
public:
template<class T>
tagged_lambda_functor(const lambda_functor<T>& a)
: lambda_functor<Args>(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
#endif

View File

@@ -0,0 +1,59 @@
// lambda_fwd.hpp - Boost Lambda Library -------------------------------
// 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_FWD_HPP
#define BOOST_LAMBDA_FWD_HPP
namespace boost {
namespace lambda {
namespace detail {
template<class T> struct generate_error;
}
// -- placeholders --------------------------------------------
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 BinderArgs>
class lambda_functor;
template <class Action,
class Args,
int ArityCode>
class lambda_functor_args;
template <class Act, class Args>
class lambda_functor_base;
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,497 @@
// - lambda_traits.hpp --- Boost Lambda Library ----------------------------
//
// 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_LAMBDA_TRAITS_HPP
#define BOOST_LAMBDA_LAMBDA_TRAITS_HPP
#include "boost/type_traits/transform_traits.hpp"
#include "boost/type_traits/cv_traits.hpp"
#include "boost/type_traits/function_traits.hpp"
#include "boost/type_traits/object_traits.hpp"
namespace boost {
namespace lambda {
// -- if construct ------------------------------------------------
// Proposed by Krzysztof Czarnecki and Ulrich Eisenecker
namespace detail {
template <bool If, class Then, class Else> struct IF { typedef Then RET; };
template <class Then, class Else> struct IF<false, Then, Else> {
typedef Else RET;
};
// An if construct that doesn't instantiate the non-matching template:
// Called as:
// IF_type<condition, A, B>::type
// The matching template must define the typeded 'type'
// I.e. A::type if condition is true, B::type if condition is false
// Idea from Vesa Karvonen (from C&E as well I guess)
template<class T>
struct IF_type_
{
typedef typename T::type type;
};
template<bool C, class T, class E>
struct IF_type
{
typedef typename
IF_type_<typename IF<C, T, E>::RET >::type 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
// If condition is true A::value must be defined, otherwise B::value
template<class T>
struct IF_value_
{
BOOST_STATIC_CONSTANT(int, value = T::value);
};
template<bool C, class T, class E>
struct IF_value
{
BOOST_STATIC_CONSTANT(int, value = (IF_value_<typename IF<C, T, E>::RET>::value));
};
// --------------------------------------------------------------
// removes reference from other than function types:
template<class T> class remove_reference_if_valid
{
typedef typename boost::remove_reference<T>::type plainT;
public:
typedef typename IF<
boost::is_function<plainT>::value,
T,
plainT
>::RET type;
};
template<class T> struct remove_reference_and_cv {
typedef typename boost::remove_cv<
typename boost::remove_reference<T>::type
>::type type;
};
// returns a reference to the element of tuple T
// If the element is stored as a copy, the reference is to
// const type. Constness of reference type elements remain unchanged.
template<int N, class T> struct tuple_element_as_reference {
typedef typename
boost::tuples::access_traits<
typename boost::tuples::element<N, T>::type
>::const_type type;
};
// returns the cv and reverence stripped type of a tuple element
template<int N, class T> struct tuple_element_stripped {
typedef typename
remove_reference_and_cv<
typename boost::tuples::element<N, T>::type
>::type type;
};
// is_lambda_functor -------------------------------------------------
template <class T> struct is_lambda_functor_ {
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <class Arg> struct is_lambda_functor_<lambda_functor<Arg> > {
BOOST_STATIC_CONSTANT(bool, value = true);
};
} // end detail
template <class T> struct is_lambda_functor {
BOOST_STATIC_CONSTANT(bool,
value =
detail::is_lambda_functor_<
typename detail::remove_reference_and_cv<T>::type
>::value);
};
namespace detail {
// -- parameter_traits_ ---------------------------------------------
// An internal parameter type traits class that respects
// the reference_wrapper class.
// The conversions performed are:
// references -> compile_time_error
// T1 -> T2,
// reference_wrapper<T> -> T&
// const array -> ref to const array
// array -> ref to array
// function -> ref to function
// ------------------------------------------------------------------------
template<class T1, class T2>
struct parameter_traits_ {
typedef T2 type;
};
// 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;
};
// Arrays can't be stored as plain types; convert them to references
template<class T, int n, class Any> struct parameter_traits_<T[n], Any> {
typedef T (&type)[n];
};
template<class T, int n, class Any>
struct parameter_traits_<const T[n], Any> {
typedef const T (&type)[n];
};
template<class T, int n, class Any>
struct parameter_traits_<volatile T[n], Any> {
typedef volatile T (&type)[n];
};
template<class T, int n, class Any>
struct parameter_traits_<const volatile T[n], Any> {
typedef const volatile T (&type)[n];
};
template<class T, class Any>
struct parameter_traits_<boost::reference_wrapper<T>, Any >{
typedef T& type;
};
template<class T, class Any>
struct parameter_traits_<const boost::reference_wrapper<T>, Any >{
typedef T& type;
};
template<class T, class Any>
struct parameter_traits_<volatile boost::reference_wrapper<T>, Any >{
typedef T& type;
};
template<class T, class Any>
struct parameter_traits_<const volatile boost::reference_wrapper<T>, Any >{
typedef T& type;
};
template<class Any>
struct parameter_traits_<void, Any> {
typedef void type;
};
} // end namespace detail
// ------------------------------------------------------------------------
// traits classes for lambda expressions (bind functions, operators ...)
// must be instantiated with non-reference types
// The default is const plain type -------------------------
// const T -> const T,
// T -> const T,
// references -> compile_time_error
// reference_wrapper<T> -> T&
// array -> const ref array
template<class T>
struct const_copy_argument {
typedef typename
detail::parameter_traits_<
T,
typename detail::IF<boost::is_function<T>::value, T&, const T>::RET
>::type type;
};
// T may be a function type. Without the IF test, const would be added
// to a function type, which is illegal.
// all arrays are converted to const.
// This traits template is used for 'const T&' parameter passing
// and thus the knowledge of the potential
// non-constness of an actual argument is lost.
template<class T, int n> struct const_copy_argument <T[n]> {
typedef const T (&type)[n];
};
template<class T, int n> struct const_copy_argument <volatile T[n]> {
typedef const volatile T (&type)[n];
};
template<class T>
struct const_copy_argument<T&> {
typedef typename detail::generate_error<T&>::references_not_allowed type;
};
template<>
struct const_copy_argument<void> {
typedef void type;
};
// The default is non-const reference -------------------------
// const T -> const T&,
// T -> T&,
// references -> compile_time_error
// reference_wrapper<T> -> T&
template<class T>
struct reference_argument {
typedef typename detail::parameter_traits_<T, T&>::type type;
};
template<class T>
struct reference_argument<T&> {
typedef typename detail::generate_error<T&>::references_not_allowed type;
};
template<class Arg>
struct reference_argument<lambda_functor<Arg> > {
typedef lambda_functor<Arg> type;
};
template<class Arg>
struct reference_argument<const lambda_functor<Arg> > {
typedef lambda_functor<Arg> type;
};
// Are the volatile versions needed?
template<class Arg>
struct reference_argument<volatile lambda_functor<Arg> > {
typedef lambda_functor<Arg> type;
};
template<class Arg>
struct reference_argument<const volatile lambda_functor<Arg> > {
typedef lambda_functor<Arg> type;
};
template<>
struct reference_argument<void> {
typedef void type;
};
namespace detail {
// Array to pointer conversion
template <class T>
struct array_to_pointer {
typedef T type;
};
template <class T, int N>
struct array_to_pointer <const T[N]> {
typedef const T* type;
};
template <class T, int N>
struct array_to_pointer <T[N]> {
typedef T* type;
};
template <class T, int N>
struct array_to_pointer <const T (&) [N]> {
typedef const T* type;
};
template <class T, int N>
struct array_to_pointer <T (&) [N]> {
typedef T* type;
};
// ---------------------------------------------------------------------------
// The call_traits for bind
// Respects the reference_wrapper class.
// These templates are used outside of bind functions as well.
// the bind_tuple_mapper provides a shorter notation for default
// bound argument storing semantics, if all arguments are treated
// uniformly.
// from template<class T> foo(const T& t) : bind_traits<const T>::type
// from template<class T> foo(T& t) : bind_traits<T>::type
// Conversions:
// T -> const T,
// cv T -> cv T,
// T& -> T&
// reference_wrapper<T> -> T&
// const reference_wrapper<T> -> T&
// array -> const ref array
// make bound arguments const, this is a deliberate design choice, the
// purpose is to prevent side effects to bound arguments that are stored
// as copies
template<class T>
struct bind_traits {
typedef const T type;
};
template<class T>
struct bind_traits<T&> {
typedef T& type;
};
// null_types are an exception, we always want to store them as non const
// so that other templates can assume that null_type is always without const
template<>
struct bind_traits<null_type> {
typedef null_type type;
};
// the bind_tuple_mapper, bind_type_generators may
// introduce const to null_type
template<>
struct bind_traits<const null_type> {
typedef null_type type;
};
// Arrays can't be stored as plain types; convert them to references.
// All arrays are converted to const. This is because bind takes its
// parameters as const T& and thus the knowledge of the potential
// non-constness of actual argument is lost.
template<class T, int n> struct bind_traits <T[n]> {
typedef const T (&type)[n];
};
template<class T, int n>
struct bind_traits<const T[n]> {
typedef const T (&type)[n];
};
template<class T, int n> struct bind_traits<volatile T[n]> {
typedef const volatile T (&type)[n];
};
template<class T, int n>
struct bind_traits<const volatile T[n]> {
typedef const volatile T (&type)[n];
};
template<class T>
struct bind_traits<reference_wrapper<T> >{
typedef T& type;
};
template<class T>
struct bind_traits<const reference_wrapper<T> >{
typedef T& type;
};
template<>
struct bind_traits<void> {
typedef void type;
};
template <
class T0 = null_type, class T1 = null_type, class T2 = null_type,
class T3 = null_type, class T4 = null_type, class T5 = null_type,
class T6 = null_type, class T7 = null_type, class T8 = null_type,
class T9 = null_type
>
struct bind_tuple_mapper {
typedef
tuple<typename bind_traits<T0>::type,
typename bind_traits<T1>::type,
typename bind_traits<T2>::type,
typename bind_traits<T3>::type,
typename bind_traits<T4>::type,
typename bind_traits<T5>::type,
typename bind_traits<T6>::type,
typename bind_traits<T7>::type,
typename bind_traits<T8>::type,
typename bind_traits<T9>::type> type;
};
// bind_traits, except map const T& -> const T
// this is needed e.g. in currying. Const reference arguments can
// refer to temporaries, so it is not safe to store them as references.
template <class T> struct remove_const_reference {
typedef typename bind_traits<T>::type type;
};
template <class T> struct remove_const_reference<const T&> {
typedef const T type;
};
// maps the bind argument types to the resulting lambda functor type
template <
class T0 = null_type, class T1 = null_type, class T2 = null_type,
class T3 = null_type, class T4 = null_type, class T5 = null_type,
class T6 = null_type, class T7 = null_type, class T8 = null_type,
class T9 = null_type
>
class bind_type_generator {
typedef typename
detail::bind_tuple_mapper<
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9
>::type args_t;
BOOST_STATIC_CONSTANT(int, nof_elems = boost::tuples::length<args_t>::value);
typedef
action<
nof_elems,
function_action<nof_elems>
> action_type;
public:
typedef
lambda_functor<
lambda_functor_args<
action_type,
args_t,
combine_arities<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value
>
> type;
};
} // detail
template <class T> inline const T& make_const(const T& t) { return t; }
} // end of namespace lambda
} // end of namespace boost
#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

@@ -0,0 +1,725 @@
// Boost Lambda Library -- member_ptr.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 of its suitability for any purpose.
//
// For more information, see www.boost.org
// --------------------------------------------------------------------------
#if !defined(BOOST_LAMBDA_MEMBER_PTR_HPP)
#define BOOST_LAMBDA_MEMBER_PTR_HPP
namespace boost {
namespace lambda {
namespace detail {
// the boost type_traits member_pointer traits are not enough,
// need to know more details.
template<class T>
struct member_pointer {
typedef typename boost::add_reference<T>::type type;
typedef detail::unspecified class_type;
typedef detail::unspecified qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = false);
};
template<class T, class U>
struct member_pointer<T U::*> {
typedef typename boost::add_reference<T>::type type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = true);
BOOST_STATIC_CONSTANT(bool, is_function_member = false);
};
template<class T, class U>
struct member_pointer<const T U::*> {
typedef typename boost::add_reference<const T>::type type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = true);
BOOST_STATIC_CONSTANT(bool, is_function_member = false);
};
template<class T, class U>
struct member_pointer<volatile T U::*> {
typedef typename boost::add_reference<volatile T>::type type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = true);
BOOST_STATIC_CONSTANT(bool, is_function_member = false);
};
template<class T, class U>
struct member_pointer<const volatile T U::*> {
typedef typename boost::add_reference<const volatile T>::type type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = true);
BOOST_STATIC_CONSTANT(bool, is_function_member = false);
};
// -- nonconst member functions --
template<class T, class U>
struct member_pointer<T (U::*)()> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1>
struct member_pointer<T (U::*)(A1)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2>
struct member_pointer<T (U::*)(A1, A2)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3>
struct member_pointer<T (U::*)(A1, A2, A3)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4>
struct member_pointer<T (U::*)(A1, A2, A3, A4)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
typedef T type;
typedef U class_type;
typedef U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
// -- const member functions --
template<class T, class U>
struct member_pointer<T (U::*)() const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1>
struct member_pointer<T (U::*)(A1) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2>
struct member_pointer<T (U::*)(A1, A2) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3>
struct member_pointer<T (U::*)(A1, A2, A3) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4>
struct member_pointer<T (U::*)(A1, A2, A3, A4) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const> {
typedef T type;
typedef U class_type;
typedef const U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
// -- volatile --
template<class T, class U>
struct member_pointer<T (U::*)() volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1>
struct member_pointer<T (U::*)(A1) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2>
struct member_pointer<T (U::*)(A1, A2) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3>
struct member_pointer<T (U::*)(A1, A2, A3) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4>
struct member_pointer<T (U::*)(A1, A2, A3, A4) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) volatile> {
typedef T type;
typedef U class_type;
typedef volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
// -- const volatile
template<class T, class U>
struct member_pointer<T (U::*)() const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1>
struct member_pointer<T (U::*)(A1) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2>
struct member_pointer<T (U::*)(A1, A2) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3>
struct member_pointer<T (U::*)(A1, A2, A3) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4>
struct member_pointer<T (U::*)(A1, A2, A3, A4) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
template<class T, class U, class A1, class A2, class A3, class A4, class A5,
class A6, class A7, class A8, class A9>
struct member_pointer<T (U::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const volatile> {
typedef T type;
typedef U class_type;
typedef const volatile U qualified_class_type;
BOOST_STATIC_CONSTANT(bool, is_data_member = false);
BOOST_STATIC_CONSTANT(bool, is_function_member = true);
};
} // detail
namespace detail {
// this class holds a pointer to a member function and the object.
// when called, it just calls the member function with the parameters
// provided
// It would have been possible to use existing lambda_functors to represent
// a bound member function like this, but to have a separate template is
// safer, since now this functor doesn't mix and match with lambda_functors
// only thing you can do with this is to call it
// note that previously instantiated classes
// (other_action<member_pointer_action> and member_pointer_action_helper
// guarantee, that A and B are
// such types, that for objects a and b of corresponding types, a->*b leads
// to the builtin ->* to be called. So types that would end in a call to
// a user defined ->* do not create a member_pointer_caller object.
template<class RET, class A, class B>
class member_pointer_caller {
A a;
B b;
public:
member_pointer_caller(A aa, B bb) : a(aa), b(bb) {}
RET operator()() const { return (a->*b)(); }
template<class A1>
RET operator()(const A1& a1) const { return (a->*b)(a1); }
template<class A1, class A2>
RET operator()(const A1& a1, const A2& a2) const { return (a->*b)(a1, a2); }
template<class A1, class A2, class A3>
RET operator()(const A1& a1, const A2& a2, const A3& a3) const {
return (a->*b)(a1, a2, a3);
}
template<class A1, class A2, class A3, class A4>
RET operator()(const A1& a1, const A2& a2, const A3& a3,
const A4& a4) const {
return (a->*b)(a1, a2, a3, a4);
}
template<class A1, class A2, class A3, class A4, class A5>
RET operator()(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
const A5& a5) const {
return (a->*b)(a1, a2, a3, a4, a5);
}
template<class A1, class A2, class A3, class A4, class A5, class A6>
RET operator()(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
const A5& a5, const A6& a6) const {
return (a->*b)(a1, a2, a3, a4, a5, a6);
}
template<class A1, class A2, class A3, class A4, class A5, class A6,
class A7>
RET operator()(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
const A5& a5, const A6& a6, const A7& a7) const {
return (a->*b)(a1, a2, a3, a4, a5, a6, a7);
}
template<class A1, class A2, class A3, class A4, class A5, class A6,
class A7, class A8>
RET operator()(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
const A5& a5, const A6& a6, const A7& a7,
const A8& a8) const {
return (a->*b)(a1, a2, a3, a4, a5, a6, a7, a8);
}
template<class A1, class A2, class A3, class A4, class A5, class A6,
class A7, class A8, class A9>
RET operator()(const A1& a1, const A2& a2, const A3& a3, const A4& a4,
const A5& a5, const A6& a6, const A7& a7,
const A8& a8, const A9& a9) const {
return (a->*b)(a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
};
// helper templates for return type deduction and action classes
// different cases for data member, function member, neither
// true-true case
template <bool Is_data_member, bool Is_function_member>
struct member_pointer_action_helper;
// cannot be both, no body provided
// data member case
// this means, that B is a data member and A is a pointer type,
// so either built-in ->* should be called, or there is an error
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;
}
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;
// A is a reference to pointer
// remove the top level cv qualifiers and reference
typedef typename
detail::remove_reference_and_cv<A>::type non_ref_A;
// A is a pointer type, so take the type pointed to
typedef typename ::boost::remove_pointer<non_ref_A>::type non_pointer_A;
public:
// For non-reference types, we must add const and/or volatile if
// the pointer type has these qualifiers
// If the member is a reference, these do not have any effect
// (cv T == T if T is a reference type)
typedef typename detail::IF<
::boost::is_const<non_pointer_A>::value,
typename ::boost::add_const<type1>::type,
type1
>::RET type2;
typedef typename detail::IF<
::boost::is_volatile<non_pointer_A>::value,
typename ::boost::add_volatile<type2>::type,
type2
>::RET type3;
// add reference back
typedef typename ::boost::add_reference<type3>::type type;
};
};
// neither case
template <>
struct member_pointer_action_helper<false, false> {
public:
template<class RET, class A, class B>
static RET apply(A& a, B& b) {
// not a built in member pointer operator, just call ->*
return a->*b;
}
// an overloaded member pointer operators, user should have specified
// the return type
template<class A, class B>
struct return_type {
typedef detail::unspecified type;
};
};
// member pointer function case
// This is a built in ->* call for a member function,
// the only thing that you can do with that, is to give it some arguments
// note, it is guaranteed that A is a pointer type, and thus it cannot
// be a call to overloaded ->*
template <>
struct member_pointer_action_helper<false, true> {
public:
template<class RET, class A, class B>
static RET apply(A& a, B& b) {
typedef typename ::boost::remove_cv<B>::type plainB;
typedef typename detail::member_pointer<plainB>::type ret_t;
return detail::member_pointer_caller<ret_t, A&, B&>(a, b);
}
template<class A, class B>
struct return_type {
typedef typename detail::remove_reference_and_cv<B>::type plainB;
typedef typename detail::member_pointer<plainB>::type ret_t;
typedef detail::member_pointer_caller<ret_t, A, B> type;
};
};
} // detail
class member_pointer_action {};
template<> class other_action<member_pointer_action> {
public:
template<class RET, class A, class B>
static RET apply(A& a, B& b) {
typedef typename
::boost::remove_cv<B>::type plainB;
return
detail::member_pointer_action_helper<
boost::is_pointer<A>::value &&
detail::member_pointer<plainB>::is_data_member,
boost::is_pointer<A>::value &&
detail::member_pointer<plainB>::is_function_member
>::template apply<RET>(a, b);
}
};
// return type deduction --
// If the right argument is a pointer to data member,
// and the left argument is of compatible pointer to class type
// return type is a reference to the data member type
// if right argument is a pointer to a member function, and the left
// argument is of a compatible type, the return type is a
// member_pointer_caller (see above)
// Otherwise, return type deduction fails. There is either an error,
// or the user is trying to call an overloaded ->*
// 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_action_helper<
detail::member_pointer<plainB>::is_data_member,
detail::member_pointer<plainB>::is_function_member
>::template return_type<A, B>::type type;
};
template<class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
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<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<lambda_functor<Arg1>, typename const_copy_argument<Arg2>::type>,
combine_arities<Arg1, Arg2>::value
>
> (tuple<lambda_functor<Arg1>,
typename const_copy_argument<Arg2>::type>(a1, a2));
}
template<class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
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<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
> (tuple<lambda_functor<Arg1>, lambda_functor<Arg2> >(a1, a2));
}
template<class Arg1, class Arg2>
inline const
lambda_functor<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
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<
lambda_functor_args<
action<2, other_action<member_pointer_action> >,
tuple<typename const_copy_argument<Arg1>::type, lambda_functor<Arg2> >,
combine_arities<Arg1, Arg2>::value
>
> (tuple<typename const_copy_argument<Arg1>::type,
lambda_functor<Arg2> >(a1, a2));
}
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,201 @@
// -- operator_actions.hpp - Boost Lambda Library ----------------------
// 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://lambda.cs.utu.fi
#ifndef BOOST_LAMBDA_OPERATOR_ACTIONS_HPP
#define BOOST_LAMBDA_OPERATOR_ACTIONS_HPP
namespace boost {
namespace lambda {
// -- artihmetic ----------------------
class plus_action {};
class minus_action {};
class multiply_action {};
class divide_action {};
class remainder_action {};
// -- bitwise -------------------
class leftshift_action {};
class rightshift_action {};
class xor_action {};
// -- bitwise/logical -------------------
class and_action {};
class or_action {};
class not_action {};
// -- relational -------------------------
class less_action {};
class greater_action {};
class lessorequal_action {};
class greaterorequal_action {};
class equal_action {};
class notequal_action {};
// -- increment/decrement ------------------------------
class increment_action {};
class decrement_action {};
// -- void return ------------------------------
class do_nothing_action {};
// -- other ------------------------------
class addressof_action {};
// class comma_action {}; // defined in actions.hpp
class contentsof_action {};
// class member_pointer_action {}; (defined in member_ptr.hpp)
// -- actioun group templates --------------------
template <class Action> class arithmetic_action;
template <class Action> class bitwise_action;
template <class Action> class logical_action;
template <class Action> class relational_action;
template <class Action> class arithmetic_assignment_action;
template <class Action> class bitwise_assignment_action;
template <class Action> class unary_arithmetic_action;
template <class Action> class pre_increment_decrement_action;
template <class Action> class post_increment_decrement_action;
// ---------------------------------------------------------
#if defined BOOST_LAMBDA_BINARY_ACTION
#error "Multiple defines of BOOST_LAMBDA_BINARY_ACTION"
#endif
#define BOOST_LAMBDA_BINARY_ACTION(OPER_SYMBOL, GROUP, OPER_NAME) \
template<> class GROUP < OPER_NAME> : public protectable {\
public: \
template<class RET, class A, class B>\
static RET apply(A& a, B& b) { \
return a OPER_SYMBOL b; }\
};\
\
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]; }
};
// 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() {}
};
// 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)
#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

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

@@ -0,0 +1,902 @@
// operator_return_type_traits.hpp -- Boost Lambda Library ------------------
// 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_RETURN_TYPE_TRAITS_HPP
#define BOOST_LAMBDA_OPERATOR_RETURN_TYPE_TRAITS_HPP
#include "boost/lambda/detail/is_instance_of.hpp"
#include "boost/type_traits/same_traits.hpp"
#include <cstddef> // needed for the ptrdiff_t
#include <iosfwd> // for istream and ostream
#include <iterator> // needed for operator&
namespace boost {
namespace lambda {
namespace detail {
// -- general helper templates for type deduction ------------------
// Much of the type deduction code for standard arithmetic types from Gary Powell
template <class A> struct promote_code { static const int value = -1; };
// this means that a code is not defined for A
// -- the next 5 types are needed in if_then_else_return
// the promotion order is not important, but they must have distinct values.
template <> struct promote_code<bool> { static const int value = 10; };
template <> struct promote_code<char> { static const int value = 20; };
template <> struct promote_code<unsigned char> { static const int value = 30; };
template <> struct promote_code<signed char> { static const int value = 40; };
template <> struct promote_code<short int> { static const int value = 50; };
// ----------
template <> struct promote_code<int> { static const int value = 100; };
template <> struct promote_code<unsigned int> { static const int value = 200; };
template <> struct promote_code<long> { static const int value = 300; };
template <> struct promote_code<unsigned long> { static const int value = 400; };
template <> struct promote_code<float> { static const int value = 500; };
template <> struct promote_code<double> { static const int value = 600; };
template <> struct promote_code<long double> { static const int value = 700; };
// TODO: wchar_t
// forward delcaration of complex.
} // namespace detail
} // namespace lambda
} // namespace boost
namespace std {
template<class T> class complex;
}
namespace boost {
namespace lambda {
namespace detail {
template <> struct promote_code< std::complex<float> > { static const int value = 800; };
template <> struct promote_code< std::complex<double> > { static const int value = 900; };
template <> struct promote_code< std::complex<long double> > { static const int value = 1000; };
// -- int promotion -------------------------------------------
template <class T> struct promote_to_int { typedef T type; };
template <> struct promote_to_int<bool> { typedef int type; };
template <> struct promote_to_int<char> { typedef int type; };
template <> struct promote_to_int<unsigned char> { typedef int type; };
template <> struct promote_to_int<signed char> { typedef int type; };
template <> struct promote_to_int<short int> { typedef int type; };
// The unsigned short int promotion rule is this:
// unsigned short int to signed int if a signed int can hold all values
// 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),
// I had the logic reversed but ">" messes up the parsing.
unsigned int,
int>::RET type;
};
// TODO: think, should there be default behaviour for non-standard types?
} // namespace detail
// ------------------------------------------
// Unary actions ----------------------------
// ------------------------------------------
template<class Act, class A>
struct plain_return_type_1 {
typedef detail::unspecified type;
};
template<class Act, class A>
struct plain_return_type_1<unary_arithmetic_action<Act>, A> {
typedef A type;
};
template<class Act, class A>
struct return_type_1<unary_arithmetic_action<Act>, A> {
typedef
typename plain_return_type_1<
unary_arithmetic_action<Act>,
typename detail::remove_reference_and_cv<A>::type
>::type type;
};
template<class A>
struct plain_return_type_1<bitwise_action<not_action>, A> {
typedef A type;
};
// bitwise not, operator~()
template<class A> struct return_type_1<bitwise_action<not_action>, A> {
typedef
typename plain_return_type_1<
bitwise_action<not_action>,
typename detail::remove_reference_and_cv<A>::type
>::type type;
};
// identity_action
template<class A> struct return_type_1<other_action<identity_action>, A> {
typedef A type;
};
// prefix increment and decrement operators return the default is
// a non-const reference
template<class Act, class A>
struct plain_return_type_1<pre_increment_decrement_action<Act>, A> {
typedef A& type;
};
template<class Act, class A>
struct return_type_1<pre_increment_decrement_action<Act>, A> {
typedef
typename plain_return_type_1<
pre_increment_decrement_action<Act>,
typename detail::remove_reference_and_cv<A>::type
>::type type;
};
// post decrement just returns the same plain type.
template<class Act, class A>
struct plain_return_type_1<post_increment_decrement_action<Act>, A> {
typedef A type;
};
template<class Act, class A>
struct return_type_1<post_increment_decrement_action<Act>, A>
{
typedef
typename plain_return_type_1<
post_increment_decrement_action<Act>,
typename detail::remove_reference_and_cv<A>::type
>::type type;
};
// logical not, operator!()
template<class A>
struct plain_return_type_1<logical_action<not_action>, A> {
typedef bool type;
};
template<class A>
struct return_type_1<logical_action<not_action>, A> {
typedef
typename plain_return_type_1<
logical_action<not_action>,
typename detail::remove_reference_and_cv<A>::type
>::type type;
};
// address of action ---------------------------------------
template<class A>
struct return_type_1<other_action<addressof_action>, A> {
typedef
typename plain_return_type_1<
other_action<addressof_action>,
typename detail::remove_reference_and_cv<A>::type
>::type type1;
// If no user defined specialization for A, then return the
// cv qualified pointer to A
typedef typename detail::IF<
boost::is_same<type1, detail::unspecified>::value,
typename boost::remove_reference<A>::type*,
type1
>::RET type;
};
// contentsof action ------------------------------------
// TODO: this deduction may lead to fail directly,
// (if A has no specialization for iterator_traits and has no
// typedef A::reference.
// There is no easy way around this, cause there doesn't seem to be a way
// to test whether a class is an iterator or not.
// The default works with std::iterators.
namespace detail {
// A is a nonreference type
template <class A> struct contentsof_type {
typedef typename std::iterator_traits<A>::reference type;
};
template <class A> struct contentsof_type<const A> {
typedef typename contentsof_type<A>::type type1;
// return a reference to the underlying const type
// the IF is because the A::reference in the primary template could
// be some class type rather than a real reference, hence
// we do not want to make it a reference here either
typedef typename detail::IF<
is_reference<type1>::value,
const typename boost::remove_reference<type1>::type &,
const type1
>::RET type;
};
template <class A> struct contentsof_type<volatile A> {
typedef typename contentsof_type<A>::type type1;
typedef typename detail::IF<
is_reference<type1>::value,
volatile typename boost::remove_reference<type1>::type &,
volatile type1
>::RET type;
};
template <class A> struct contentsof_type<const volatile A> {
typedef typename contentsof_type<A>::type type1;
typedef typename detail::IF<
is_reference<type1>::value,
const volatile typename boost::remove_reference<type1>::type &,
const volatile type1
>::RET type;
};
// standard iterator traits should take care of the pointer types
// but just to be on the safe side, we have the specializations here:
// these work even if A is cv-qualified.
template <class A> struct contentsof_type<A*> {
typedef A& type;
};
template <class A> struct contentsof_type<A* const> {
typedef A& type;
};
template <class A> struct contentsof_type<A* volatile> {
typedef A& type;
};
template <class A> struct contentsof_type<A* const volatile> {
typedef A& type;
};
template<class A, int N> struct contentsof_type<A[N]> {
typedef A& type;
};
template<class A, int N> struct contentsof_type<const A[N]> {
typedef const A& type;
};
template<class A, int N> struct contentsof_type<volatile A[N]> {
typedef volatile A& type;
};
template<class A, int N> struct contentsof_type<const volatile A[N]> {
typedef const volatile A& type;
};
} // end detail
template<class A>
struct return_type_1<other_action<contentsof_action>, A> {
typedef
typename plain_return_type_1<
other_action<contentsof_action>,
typename detail::remove_reference_and_cv<A>::type
>::type type1;
// If no user defined specialization for A, then return the
// cv qualified pointer to A
typedef typename
detail::IF_type<
boost::is_same<type1, detail::unspecified>::value,
detail::contentsof_type<
typename boost::remove_reference<A>::type
>,
plain_return_type_1<
other_action<contentsof_action>,
typename detail::remove_reference_and_cv<A>::type
>
>::type type;
};
// ------------------------------------------------------------------
// binary actions ---------------------------------------------------
// ------------------------------------------------------------------
// here the default case is: no user defined versions:
template <class Act, class A, class B>
struct plain_return_type_2 {
typedef detail::unspecified type;
};
namespace detail {
// error classes
class illegal_pointer_arithmetic{};
// pointer arithmetic type deductions ----------------------
// value = false means that this is not a pointer arithmetic case
// value = true means, that this can be a pointer arithmetic case, but not necessarily is
// This means, that for user defined operators for pointer types, say for some operator+(X, *Y),
// the deductions must be coded at an earliel level (return_type_2).
template<class Act, class A, class B>
struct pointer_arithmetic_traits { static const bool value = false; };
template<class A, class B>
struct pointer_arithmetic_traits<plus_action, A, B> {
typedef typename
array_to_pointer<typename boost::remove_reference<A>::type>::type AP;
typedef typename
array_to_pointer<typename boost::remove_reference<B>::type>::type BP;
static const bool is_pointer_A = boost::is_pointer<AP>::value;
static const bool is_pointer_B = boost::is_pointer<BP>::value;
static const bool value = is_pointer_A || is_pointer_B;
// can't add two pointers.
// note, that we do not check wether the other type is valid for
// addition with a pointer.
// the compiler will catch it in the apply function
typedef typename
detail::IF<
is_pointer_A && is_pointer_B,
detail::return_type_deduction_failure<
detail::illegal_pointer_arithmetic
>,
typename detail::IF<is_pointer_A, AP, BP>::RET
>::RET type;
};
template<class A, class B>
struct pointer_arithmetic_traits<minus_action, A, B> {
typedef typename
array_to_pointer<typename boost::remove_reference<A>::type>::type AP;
typedef typename
array_to_pointer<typename boost::remove_reference<B>::type>::type BP;
static const bool is_pointer_A = boost::is_pointer<AP>::value;
static const bool is_pointer_B = boost::is_pointer<BP>::value;
static const bool value = is_pointer_A || is_pointer_B;
static const bool same_pointer_type =
is_pointer_A && is_pointer_B &&
boost::is_same<
typename boost::remove_const<
typename boost::remove_pointer<
typename boost::remove_const<AP>::type
>::type
>::type,
typename boost::remove_const<
typename boost::remove_pointer<
typename boost::remove_const<BP>::type
>::type
>::type
>::value;
// ptr - ptr has type ptrdiff_t
// note, that we do not check if, in ptr - B, B is
// valid for subtraction with a pointer.
// the compiler will catch it in the apply function
typedef typename
detail::IF<
same_pointer_type, const std::ptrdiff_t,
typename detail::IF<
is_pointer_A,
AP,
detail::return_type_deduction_failure<detail::illegal_pointer_arithmetic>
>::RET
>::RET type;
};
} // namespace detail
// -- arithmetic actions ---------------------------------------------
namespace detail {
template<bool is_pointer_arithmetic, class Act, class A, class B>
struct return_type_2_arithmetic_phase_1;
template<class A, class B> struct return_type_2_arithmetic_phase_2;
template<class A, class B> struct return_type_2_arithmetic_phase_3;
} // namespace detail
// drop any qualifiers from the argument types within arithmetic_action
template<class A, class B, class Act>
struct return_type_2<arithmetic_action<Act>, 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<arithmetic_action<Act>, plain_A, plain_B>::type type1;
// if user defined return type, do not enter the whole arithmetic deductions
typedef typename
detail::IF_type<
boost::is_same<type1, detail::unspecified>::value,
detail::return_type_2_arithmetic_phase_1<
detail::pointer_arithmetic_traits<Act, A, B>::value, Act, A, B
>,
plain_return_type_2<arithmetic_action<Act>, plain_A, plain_B>
>::type type;
};
namespace detail {
// perform integral promotion, no pointer arithmetic
template<bool is_pointer_arithmetic, class Act, class A, class B>
struct return_type_2_arithmetic_phase_1
{
typedef typename
return_type_2_arithmetic_phase_2<
typename remove_reference_and_cv<A>::type,
typename remove_reference_and_cv<B>::type
>::type type;
};
// pointer_arithmetic
template<class Act, class A, class B>
struct return_type_2_arithmetic_phase_1<true, Act, A, B>
{
typedef typename
pointer_arithmetic_traits<Act, A, B>::type type;
};
template<class A, class B>
struct return_type_2_arithmetic_phase_2 {
typedef typename
return_type_2_arithmetic_phase_3<
typename promote_to_int<A>::type,
typename promote_to_int<B>::type
>::type type;
};
// specialization for unsigned int.
// We only have to do these two specialization because the value promotion will
// take care of the other cases.
// The unsigned int promotion rule is this:
// unsigned int to long if a long can hold all values of unsigned int,
// otherwise go to unsigned long.
// struct so I don't have to type this twice.
struct promotion_of_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;
};
template<>
struct return_type_2_arithmetic_phase_2<unsigned int, long>
{
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;
};
template<class A, class B> struct return_type_2_arithmetic_phase_3 {
enum { promote_code_A_value = promote_code<A>::value,
promote_code_B_value = promote_code<B>::value }; // enums for KCC
typedef typename
detail::IF<
promote_code_A_value == -1 || promote_code_B_value == -1,
detail::return_type_deduction_failure<return_type_2_arithmetic_phase_3>,
typename detail::IF<
((int)promote_code_A_value > (int)promote_code_B_value),
A,
B
>::RET
>::RET type;
};
} // namespace detail
// -- bitwise actions -------------------------------------------
// note: for integral types deuduction is similar to arithmetic actions.
// drop any qualifiers from the argument types within arithmetic action
template<class A, class B, class Act>
struct return_type_2<bitwise_action<Act>, 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<bitwise_action<Act>, plain_A, plain_B>::type type1;
// if user defined return type, do not enter type deductions
typedef typename
detail::IF_type<
boost::is_same<type1, detail::unspecified>::value,
return_type_2<arithmetic_action<plus_action>, A, B>,
plain_return_type_2<bitwise_action<Act>, plain_A, plain_B>
>::type type;
// plus_action is just a random pick, has to be a concrete instance
// TODO: This check is only valid for built-in types, overloaded types might
// accept floating point operators
// bitwise operators not defined for floating point types
// these test are not strictly needed here, since the error will be caught in
// the apply function
BOOST_STATIC_ASSERT(!(boost::is_float<plain_A>::value && boost::is_float<plain_B>::value));
};
namespace detail {
template<class A, class B>
struct leftshift_type {
typedef typename detail::IF<
#ifdef BOOST_NO_TEMPLATED_STREAMS
boost::is_convertible<
typename boost::remove_reference<A>::type*,
std::ostream*
>::value,
#else
is_instance_of_2<
typename boost::remove_reference<A>::type,
std::basic_ostream
>::value,
#endif
A, //reference to the stream
typename detail::remove_reference_and_cv<A>::type
>::RET type;
};
template<class A, class B>
struct rightshift_type {
typedef typename detail::IF<
#ifdef BOOST_NO_TEMPLATED_STREAMS
boost::is_convertible<
typename boost::remove_reference<A>::type*,
std::istream*
>::value,
#else
is_instance_of_2<
typename boost::remove_reference<A>::type,
std::basic_istream
>::value,
#endif
A, //reference to the stream
typename detail::remove_reference_and_cv<A>::type
>::RET type;
};
} // end detail
// ostream
template<class A, class B>
struct return_type_2<bitwise_action<leftshift_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<bitwise_action<leftshift_action>, plain_A, plain_B>::type type1;
// if user defined return type, do not enter type deductions
typedef typename
detail::IF_type<
boost::is_same<type1, detail::unspecified>::value,
detail::leftshift_type<A, B>,
plain_return_type_2<bitwise_action<leftshift_action>, plain_A, plain_B>
>::type type;
};
// istream
template<class A, class B>
struct return_type_2<bitwise_action<rightshift_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<bitwise_action<rightshift_action>, plain_A, plain_B>::type type1;
// if user defined return type, do not enter type deductions
typedef typename
detail::IF_type<
boost::is_same<type1, detail::unspecified>::value,
detail::rightshift_type<A, B>,
plain_return_type_2<bitwise_action<rightshift_action>, plain_A, plain_B>
>::type type;
};
// -- logical actions ----------------------------------------
// always bool
// NOTE: this may not be true for some weird user-defined types,
template<class A, class B, class Act>
struct plain_return_type_2<logical_action<Act>, A, B> {
typedef bool type;
};
template<class A, class B, class Act>
struct return_type_2<logical_action<Act>, 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<logical_action<Act>, plain_A, plain_B>::type type;
};
// -- relational actions ----------------------------------------
// always bool
// NOTE: this may not be true for some weird user-defined types,
template<class A, class B, class Act>
struct plain_return_type_2<relational_action<Act>, A, B> {
typedef bool type;
};
template<class A, class B, class Act>
struct return_type_2<relational_action<Act>, 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<relational_action<Act>, plain_A, plain_B>::type type;
};
// Assingment actions -----------------------------------------------
// 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!
// NOTE: this may not be true for some weird user-defined types,
template<class A, class B, class Act>
struct return_type_2<arithmetic_assignment_action<Act>, 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<
arithmetic_assignment_action<Act>, plain_A, plain_B
>::type type1;
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
A,
type1
>::RET type;
};
template<class A, class B, class Act>
struct return_type_2<bitwise_assignment_action<Act>, 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<
bitwise_assignment_action<Act>, plain_A, plain_B
>::type type1;
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
A,
type1
>::RET type;
};
template<class A, class B>
struct return_type_2<other_action<assignment_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<assignment_action>, plain_A, plain_B
>::type type1;
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
A,
type1
>::RET type;
};
// -- other actions ----------------------------------------
// comma action ----------------------------------
// Note: this may not be true for some weird user-defined types,
// NOTE! A and B in comma_action can be non-reference types too!!!
// (The built in operator, can return a l- or rvalue).
template<class A, class B>
struct return_type_2<other_action<comma_action>, A, B> {
typedef typename detail::remove_reference_and_cv<A>::type plain_A;
typedef typename detail::remove_reference_and_cv<B>::type plain_B;
typedef typename
plain_return_type_2<
other_action<comma_action>, plain_A, plain_B
>::type type1;
typedef typename
detail::IF<
boost::is_same<type1, detail::unspecified>::value,
B,
type1
>::RET type;
};
// subscript action -----------------------------------------------
namespace detail {
// A and B are nonreference types
template <class A, class B> struct subscript_type {
typedef detail::unspecified type;
};
template <class A, class B> struct subscript_type<A*, B> {
typedef A& type;
};
template <class A, class B> struct subscript_type<A* const, B> {
typedef A& type;
};
template <class A, class B> struct subscript_type<A* volatile, B> {
typedef A& type;
};
template <class A, class B> struct subscript_type<A* const volatile, B> {
typedef A& type;
};
template<class A, class B, int N> struct subscript_type<A[N], B> {
typedef A& type;
};
// these 3 specializations are needed to make gcc <3 happy
template<class A, class B, int N> struct subscript_type<const A[N], B> {
typedef const A& type;
};
template<class A, class B, int N> struct subscript_type<volatile A[N], B> {
typedef volatile A& type;
};
template<class A, class B, int N> struct subscript_type<const volatile A[N], B> {
typedef const volatile A& type;
};
} // end detail
template<class A, class B>
struct return_type_2<other_action<subscript_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 boost::remove_reference<A>::type nonref_A;
typedef typename boost::remove_reference<B>::type nonref_B;
typedef typename
plain_return_type_2<
other_action<subscript_action>, plain_A, plain_B
>::type type1;
typedef typename
detail::IF_type<
boost::is_same<type1, detail::unspecified>::value,
detail::subscript_type<nonref_A, nonref_B>,
plain_return_type_2<other_action<subscript_action>, plain_A, plain_B>
>::type type;
};
} // namespace lambda
} // namespace boost
namespace std {
template <class Key, class T, class Cmp, class Allocator> class map;
template <class Key, class T, class Cmp, class Allocator> class multimap;
template <class T, class Allocator> class vector;
template <class T, class Allocator> class deque;
template <class Char, class Traits, class Allocator> class basic_string;
}
namespace boost {
namespace lambda {
template<class Key, class T, class Cmp, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, std::map<Key, T, Cmp, Allocator>, B> {
typedef T& type;
// T == std::map<Key, T, Cmp, Allocator>::mapped_type;
};
template<class Key, class T, class Cmp, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, std::multimap<Key, T, Cmp, Allocator>, B> {
typedef T& type;
// T == std::map<Key, T, Cmp, Allocator>::mapped_type;
};
// deque
template<class T, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, std::deque<T, Allocator>, B> {
typedef typename std::deque<T, Allocator>::reference type;
};
template<class T, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, const std::deque<T, Allocator>, B> {
typedef typename std::deque<T, Allocator>::const_reference type;
};
// vector
template<class T, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, std::vector<T, Allocator>, B> {
typedef typename std::vector<T, Allocator>::reference type;
};
template<class T, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, const std::vector<T, Allocator>, B> {
typedef typename std::vector<T, Allocator>::const_reference type;
};
// basic_string
template<class Char, class Traits, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, std::basic_string<Char, Traits, Allocator>, B> {
typedef typename std::basic_string<Char, Traits, Allocator>::reference type;
};
template<class Char, class Traits, class Allocator, class B>
struct plain_return_type_2<other_action<subscript_action>, const std::basic_string<Char, Traits, Allocator>, B> {
typedef typename std::basic_string<Char, Traits, Allocator>::const_reference type;
};
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,375 @@
// Boost Lambda Library - operators.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_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_BINARY_EXPRESSION1
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION1"
#endif
#define BOOST_LAMBDA_BINARY_EXPRESSION1(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) template<class Arg, class B> \
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<lambda_functor<Arg>, \
typename CONST_CONVERSION <CONSTB B>::type>,\
dig_arity<Arg>::value> >\
OPER_FUNC_NAME (const lambda_functor<Arg>& a, \
CONSTB B& b)\
{\
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<lambda_functor<Arg>, typename CONST_CONVERSION <CONSTB B>::type>, \
dig_arity<Arg>::value> >\
(\
tuple<lambda_functor<Arg>, typename CONST_CONVERSION <CONSTB B>::type>(a, b)\
);\
}\
\
#if defined BOOST_LAMBDA_BINARY_EXPRESSION2
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION2"
#endif
#define BOOST_LAMBDA_BINARY_EXPRESSION2(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) template<class A, class Arg> \
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >,\
tuple<typename CONST_CONVERSION <CONSTA A>::type, \
lambda_functor<Arg> >,\
dig_arity<Arg>::value> >\
OPER_FUNC_NAME (CONSTA A& a,\
const lambda_functor<Arg>& b)\
{\
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<typename CONST_CONVERSION <CONSTA A>::type, lambda_functor<Arg> >, \
dig_arity<Arg>::value> >\
(\
tuple<typename CONST_CONVERSION <CONSTA A>::type, lambda_functor<Arg> >(a, b)\
);\
}\
\
#if defined BOOST_LAMBDA_BINARY_EXPRESSION3
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION3"
#endif
#define BOOST_LAMBDA_BINARY_EXPRESSION3(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) template<class ArgA, class ArgB> \
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >,\
tuple<lambda_functor<ArgA>, \
lambda_functor<ArgB> >,\
combine_arities<ArgA, ArgB>::value> >\
OPER_FUNC_NAME (const lambda_functor<ArgA>& a, \
const lambda_functor<ArgB>& b)\
{\
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<lambda_functor<ArgA>, \
lambda_functor<ArgB> >,\
combine_arities<ArgA, ArgB>::value> >\
(\
boost::make_tuple(a, b)\
);\
}\
\
#if defined BOOST_LAMBDA_BINARY_EXPRESSION
#error "Multiple defines of BOOST_LAMBDA_BINARY_EXPRESSION"
#endif
#define BOOST_LAMBDA_BINARY_EXPRESSION(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION) \
BOOST_LAMBDA_BINARY_EXPRESSION1(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION)\
BOOST_LAMBDA_BINARY_EXPRESSION2(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION)\
BOOST_LAMBDA_BINARY_EXPRESSION3(OPER_FUNC_NAME, OPER_NAME, CONSTA, CONSTB, CONST_CONVERSION)
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_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
#if defined BOOST_LAMBDA_COMMA_OPERATOR_NAME
#error "Multiple defines of BOOST_LAMBDA_COMMA_OPERATOR_NAME"
#endif
#define BOOST_LAMBDA_COMMA_OPERATOR_NAME operator,
BOOST_LAMBDA_BINARY_EXPRESSION1(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action< comma_action>, const, const, const_copy_argument)
BOOST_LAMBDA_BINARY_EXPRESSION2(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action< comma_action>, const, const, const_copy_argument)
BOOST_LAMBDA_BINARY_EXPRESSION3(BOOST_LAMBDA_COMMA_OPERATOR_NAME, other_action< comma_action>, const, const, const_copy_argument)
namespace detail {
// special cases for ostream& << Any and istream& >> Any ---------------
// the actual stream classes may vary and thus a specialisation for,
// say ostream& does not match (the general case above is chosen).
// Therefore we specialise for non-const reference:
// if the left argument is a stream, we store the stream as reference
// if it is something else, we store a const plain by default
// Note that the overloading is const vs. non-const first argument
#ifdef BOOST_NO_TEMPLATED_STREAMS
template<class T> struct convert_ostream_to_ref_others_to_c_plain_by_default {
typedef typename detail::IF<
boost::is_convertible<T*, std::ostream*>::value,
T&,
typename const_copy_argument <T>::type
>::RET type;
};
template<class T> struct convert_istream_to_ref_others_to_c_plain_by_default {
typedef typename detail::IF<
boost::is_convertible<T*, std::istream*>::value,
T&,
typename const_copy_argument <T>::type
>::RET type;
};
#else
template<class T> struct convert_ostream_to_ref_others_to_c_plain_by_default {
typedef typename detail::IF<
is_instance_of_2<
T, std::basic_ostream
>::value,
T&,
typename const_copy_argument <T>::type
>::RET type;
};
template<class T> struct convert_istream_to_ref_others_to_c_plain_by_default {
typedef typename detail::IF<
is_instance_of_2<
T, std::basic_istream
>::value,
T&,
typename const_copy_argument <T>::type
>::RET type;
};
#endif
} // detail
BOOST_LAMBDA_BINARY_EXPRESSION2(operator<<, bitwise_action< leftshift_action>, , const, detail::convert_ostream_to_ref_others_to_c_plain_by_default)
BOOST_LAMBDA_BINARY_EXPRESSION2(operator>>, bitwise_action< rightshift_action>, , const, detail::convert_istream_to_ref_others_to_c_plain_by_default)
// special case for io_manipulators.
// function references cannot be given as arguments to lambda operator
// expressions in general. With << and >> the use of manipulators is
// so common, that specializations are provided to make them work.
template<class Arg, class Ret, class ManipArg>
inline const
lambda_functor<
lambda_functor_args<
action<2, bitwise_action<leftshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
>
operator<<(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
{
return
lambda_functor<
lambda_functor_args<
action<2, bitwise_action<leftshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
> ( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
}
template<class Arg, class Ret, class ManipArg>
inline const
lambda_functor<
lambda_functor_args<
action<2, bitwise_action<rightshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
>
operator>>(const lambda_functor<Arg>& a, Ret(&b)(ManipArg))
{
return
lambda_functor<
lambda_functor_args<
action<2, bitwise_action<rightshift_action> >,
tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>,
dig_arity<Arg>::value
>
> ( tuple<lambda_functor<Arg>, Ret(&)(ManipArg)>(a, b) );
}
// (+ and -) take their arguments as const references.
// This has consquences with pointer artihmetic
// E.g int a[]; ... *a = 1 works but not *(a+1) = 1.
// the result of a+1 would be const
// To make the latter work too,
// non-const arrays are taken as non-const and stored as non-const as well.
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1"
#endif
#define BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(OPER_FUNC_NAME, OPER_NAME, CONST) template<class Arg, int N, class B> \
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<lambda_functor<Arg>, \
CONST B (&) [N]>,\
dig_arity<Arg>::value> > \
OPER_FUNC_NAME (const lambda_functor<Arg>& a, \
CONST B (&b) [N])\
{\
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<lambda_functor<Arg>, CONST B (&) [N]>, \
dig_arity<Arg>::value> >\
(\
tuple<lambda_functor<Arg>, CONST B (&) [N]>(a, b)\
);\
}\
\
#if defined BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2
#error "Multiple defines of BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2"
#endif
#define BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(OPER_FUNC_NAME, OPER_NAME, CONST) template<int N, class A, class Arg> \
inline const lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<CONST A (&) [N], lambda_functor<Arg> >, \
dig_arity<Arg>::value> > \
OPER_FUNC_NAME (CONST A (&a) [N], const lambda_functor<Arg>& b) \
{\
return lambda_functor<lambda_functor_args<action<2, OPER_NAME >, \
tuple<CONST A (&) [N], lambda_functor<Arg> >, \
dig_arity<Arg>::value> >\
(\
tuple<CONST A (&) [N], lambda_functor<Arg> >(a, b)\
);\
}\
\
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(operator+, arithmetic_action< plus_action>,)
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator+, arithmetic_action< plus_action>,)
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1(operator+, arithmetic_action< plus_action>,const)
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator+, arithmetic_action< plus_action>,const)
//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_EXPRESSION2(operator-, arithmetic_action< minus_action>, )
BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2(operator-, arithmetic_action< minus_action>, const)
#undef BOOST_LAMBDA_BINARY_EXPRESSION1
#undef BOOST_LAMBDA_BINARY_EXPRESSION2
#undef BOOST_LAMBDA_BINARY_EXPRESSION3
#undef BOOST_LAMBDA_BINARY_EXPRESSION
#undef BOOST_LAMBDA_COMMA_OPERATOR_NAME
#undef BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION1
#undef BOOST_LAMBDA_PTR_ARITHMETIC_EXPRESSION2
// ---------------------------------------------------------------------
// unary operators -----------------------------------------------------
// ---------------------------------------------------------------------
#if defined BOOST_LAMBDA_UNARY_EXPRESSION
#error "Multiple defines of BOOST_LAMBDA_UNARY_EXPRESSION"
#endif
#define BOOST_LAMBDA_UNARY_EXPRESSION(FUNCTION_NAME, ACTION_NAME) \
template<class Arg>\
inline const lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
tuple<lambda_functor<Arg> >,\
dig_arity<Arg>::value> >\
FUNCTION_NAME (const lambda_functor<Arg>& a)\
{\
return lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
tuple<lambda_functor<Arg> >,\
dig_arity<Arg>::value> >\
( make_tuple(a) );\
}\
\
BOOST_LAMBDA_UNARY_EXPRESSION(operator+, unary_arithmetic_action<plus_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator-, unary_arithmetic_action<minus_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator~, bitwise_action<not_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator!, logical_action<not_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator++, pre_increment_decrement_action<increment_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator--, pre_increment_decrement_action<decrement_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator*, other_action<contentsof_action>)
BOOST_LAMBDA_UNARY_EXPRESSION(operator&, other_action<addressof_action>)
#if defined BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION
#error "Multiple defines of BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION"
#endif
#define BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(FUNCTION_NAME, ACTION_NAME) \
template<class Arg>\
inline const lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
tuple<lambda_functor<Arg> >,\
dig_arity<Arg>::value> >\
FUNCTION_NAME (const lambda_functor<Arg>& a, int)\
{\
return lambda_functor<lambda_functor_args<action<1, ACTION_NAME >,\
tuple<lambda_functor<Arg> >,\
dig_arity<Arg>::value> >\
( make_tuple(a) );\
}\
\
BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(operator++, post_increment_decrement_action<increment_action>)
BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION(operator--, post_increment_decrement_action<decrement_action>)
#undef BOOST_LAMBDA_UNARY_EXPRESSION
#undef BOOST_LAMBDA_POSTFIX_UNARY_EXPRESSION
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,265 @@
// Boost Lambda Library ret.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_RET_HPP
#define BOOST_LAMBDA_RET_HPP
namespace boost {
namespace lambda {
// TODO:
// Add specializations for function references for ret, protect and unlambda
// e.g void foo(); unlambda(foo); fails, as it would add a const qualifier
// for a function type.
// on the other hand unlambda(*foo) does work
// -- ret -------------------------
// the explicit return type template
// TODO: It'd be nice to make ret a nop for other than lambda functors
// but causes an ambiguiyty with gcc (not with KCC), check what is the
// right interpretation.
// // ret for others than lambda functors has no effect
// template <class U, class T>
// inline const T& ret(const T& t) { return t; }
template<class RET, class Arg>
inline const
lambda_functor<
lambda_functor_args<
action<1, explicit_return_type_action<RET> >,
tuple<lambda_functor<Arg> >,
dig_arity<Arg>::value
>
>
ret(const lambda_functor<Arg>& a1)
{
return lambda_functor<
lambda_functor_args<
action<1, explicit_return_type_action<RET> >,
tuple<lambda_functor<Arg> >,
dig_arity<Arg>::value
>
>
(tuple<lambda_functor<Arg> >(a1));
}
// protect ------------------
// protecting others than lambda functors has no effect
template <class T>
inline const T& protect(const T& t) { return t; }
template<class Arg>
inline const
lambda_functor<
lambda_functor_args<
action<1, protect_action>,
tuple<lambda_functor<Arg> >,
NONE
>
>
protect(const lambda_functor<Arg>& a1)
{
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.
// After this, the functor is immune to argument substitution, etc.
// This can be used, e.g. to make it safe to pass lambda functors as
// arguments to functions, which might use them as target functions
// note, unlambda and protect are different things. Protect hides the lambda
// functor for one application, unlambda for good.
template <class Arg>
class non_lambda_functor : public has_sig {
lambda_functor<Arg> lf; // a lambda functor
public:
// This functor defines the result_type typedef.
// The result type must be deducible without knowing the arguments
// TODO: check that passing unspecified as open args fails
// typedef typename
// return_type<Arg,
// open_args<detail::unspecified,
// detail::unspecified,
// detail::unspecified> >::type
// result_type;
template <class SigArgs> struct sig {
typedef typename
lambda_functor<Arg>::template sig<SigArgs>::type type;
};
non_lambda_functor(const lambda_functor<Arg>& a) : lf(a) {}
typename sig<tuple<lambda_functor<Arg> > >::type
operator()() const {
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg> > >::type>();
}
template<class A>
typename sig<tuple<lambda_functor<Arg>, A&> >::type
operator()(A& a) const {
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&> >::type >(a);
}
template<class A, class B>
typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type
operator()(A& a, B& b) const {
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&> >::type >(a, b);
}
template<class A, class B, class C>
typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type
operator()(A& a, B& b, C& c) const {
return lf.template ret_call<typename sig<tuple<lambda_functor<Arg>, A&, B&, C&> >::type>(a, b, c);
}
};
template <class Arg>
inline const Arg& unlambda(const Arg& a) { return a; }
template <class Arg>
inline const non_lambda_functor<Arg> unlambda(const lambda_functor<Arg>& a)
{
return non_lambda_functor<Arg>(a);
}
// Due to a language restriction, lambda functors cannot be made to
// accept non-const rvalue arguments. Usually iterators do not return
// temporaries, but sometimes they do. That's why a workaround is provided.
// Note, that this potentially breaks const correctness, so be careful!
template <class Arg>
inline const const_incorrect_lambda_functor<Arg>
break_const(const lambda_functor<Arg>& lf)
{
return const_incorrect_lambda_functor<Arg>(lf);
}
template <class Arg>
inline const const_parameter_lambda_functor<Arg>
const_parameters(const lambda_functor<Arg>& lf)
{
return const_parameter_lambda_functor<Arg>(lf);
}
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,486 @@
// return_type_traits.hpp -- Boost Lambda Library ---------------------------
// 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_RETURN_TYPE_TRAITS_HPP
#define BOOST_LAMBDA_RETURN_TYPE_TRAITS_HPP
#include <cstddef> // needed for the ptrdiff_t
namespace boost {
namespace lambda {
// 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
// should never be entered at all, and the use of ret<> does this.
// However, for nullary lambda functors, return type deduction is always
// entered, and there seems to be no way around this.
// (the return type is part of the prototype of the non-template
// operator()(). The prototype is instantiated, even though the body
// is not.)
// So, in the case the return type deduction should fail, it should not
// 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 {};
}
// Much of the type deduction code for standard arithmetic types
// from Gary Powell
template<class A, class B, class C>
struct open_args {
typedef A type1;
typedef B type2;
typedef C type3;
};
// -- return type -------------------------------------
// 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> 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
// Unary actions (result from unary operators)
// do not have a default return type.
template<class Act, class A> struct return_type_1 {
typedef typename
detail::return_type_deduction_failure<return_type_1> type;
};
// read the comments for return_type_2_protect
namespace detail {
template <class A>
class protect_conversion {
// T -> const T
// T& -> T&
// const T& -> const T
// function& -> function&
// const array& -> const array&
// lambda functors are not stored as references
// function reference types are function reference types
typedef typename boost::remove_reference<A>::type A1;
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> 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
// (if protect) has been used.
// Thus, if one of the parameter types is a lambda functor, the result
// is a lambda functor as well.
// 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
// 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)
// The return type is a subclass of lambda_functor, which has a converting
// copy constructor. It can copy any lambda functor, that has the same
// action type and code, and a copy compatible argument tuple.
template <class Act, class A, class B> struct return_type_2_protect {
typedef typename
detail::IF<
is_lambda_functor<A>::value || is_lambda_functor<B>::value,
lambda_functor<
lambda_functor_args<
action<2, Act>,
tuple<typename detail::protect_conversion<A>::type,
typename detail::protect_conversion<B>::type>,
combine_arities<A, B>::value
>
>,
typename return_type_2<Act, A, B>::type
>::RET 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;
};
template <class Arg, class Open>
struct return_type<const lambda_functor<Arg>, Open> {
typedef typename return_type<Arg, Open>::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;
};
// 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;
};
template <class Open>
struct return_type<placeholder<FIRST>, Open> {
typedef typename Open::type1 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;
};
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>
struct return_type<lambda_functor_args<action<2, Act>, Args, Code>, Open> {
private:
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>
struct return_type<lambda_functor_args<action<I, Act>, Args, Code>, Open> {
private:
typedef typename detail::map_to_return_types<Args, Open>::type actual_args;
public:
typedef typename return_type_N<Act, actual_args>::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>
struct return_type<lambda_functor_args<action<2, other_action<comma_action> >, Args, Code>, Open> {
private:
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;
};
// 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;
};
} // namespace lambda
} // namespace boost
#endif

View File

@@ -0,0 +1,192 @@
// -- select_functions.hpp -- Boost Lambda Library --------------------------
// 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://lambda.cs.utu.fi
#ifndef BOOST_LAMBDA_SELECT_FUNCTIONS_HPP
#define BOOST_LAMBDA_SELECT_FUNCTIONS_HPP
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&, B&, 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&, 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&) {
return op.template ret_call<RET>(a, b);
}
};
template <> struct selector<THIRD> {
template<class RET, class Op, class A, class B, class C>
static RET select(Op& op, A& a, B& b, C& c) {
return op.template ret_call<RET>(a, b, c);
}
};
// select functions -------------------------------
template<class Any, class A, class B, class C>
inline Any& select(Any& any, A&, B&, C&) { return any; }
template<class A, class B, class C>
inline A& select(const lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
template<class A, class B, class C>
inline A& select(lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
template<class A, class B, class C>
inline B& select(const lambda_functor<placeholder<SECOND> >&, A&, B& b, C&) {
return b;
}
template<class 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);
}
// ------------------------------------------------------------------------
// 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.
// The first implementation used function templates with an explicitly
// specified template parameter.
// However, this resulted in ambiguous calls (at least with gcc 2.95.2
// and edg 2.44). Not sure whether the compilers were right or wrong.
template<class RET> struct ret_selector
{
// TODO: add checks that RET is of correct type
template<class Any, class A, class B, class C>
static Any& select(Any& any, A&, B&, C&) { return any; }
template<class A, class B, class C>
static A& select(const lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
template<class A, class B, class C>
static A& select(lambda_functor<placeholder<FIRST> >&, A& a, B&, C&) {
return a;
}
template<class 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);
}
};
} // namespace detail
} // namespace lambda
} // namespace boost
#endif

View File

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

@@ -0,0 +1,34 @@
// -- lambda.hpp -- Boost Lambda Library -----------------------------------
// 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://lambda.cs.utu.fi
#ifndef BOOST_LAMBDA_LAMBDA_HPP
#define BOOST_LAMBDA_LAMBDA_HPP
#include "boost/lambda/core.hpp"
#ifdef BOOST_NO_FDECL_TEMPLATES_AS_TEMPLATE_TEMPLATE_PARAMS
#include <istream>
#include <ostream>
#endif
#include "boost/lambda/detail/operator_actions.hpp"
#include "boost/lambda/detail/operator_lambda_functor_base.hpp"
#include "boost/lambda/detail/operator_return_type_traits.hpp"
#include "boost/lambda/detail/operators.hpp"
#include "boost/lambda/detail/member_ptr.hpp"
#endif

89
test/Makefile Executable file
View File

@@ -0,0 +1,89 @@
BOOST = ../../..
CXX = gcc3
EXTRAFLAGS = -pedantic -Wno-long-long -ftemplate-depth-50
LIBS = -lstdc++
#CXX = KCC
#EXTRAFLAGS = --strict --display_error_number --diag_suppress 450 --max_pending_instantiations 50
#LIBS =
INCLUDES = -I$(BOOST)
CXXFLAGS = $(INCLUDES) $(EXTRAFLAGS)
LIBFLAGS = $(LIBS)
AR = ar
.SUFFIXES: .cpp .o
SOURCES = \
is_instance_of_test.cpp \
operator_tests_simple.cpp \
member_pointer_test.cpp \
control_structures.cpp \
switch_construct.cpp \
bind_tests_simple.cpp \
bind_tests_advanced.cpp \
bll_and_function.cpp \
constructor_tests.cpp \
extending_return_type_traits.cpp \
bind_tests_simple_function_references.cpp \
exception_test.cpp \
cast_test.cpp \
phoenix_control_structures_test.cpp \
# Create lists of object files from the source file lists.
OBJECTS = ${SOURCES:.cpp=.o}
TARGETS = ${SOURCES:.cpp=.exe}
all: $(TARGETS)
%.exe: %.o
$(CXX) $(LIBFLAGS) $(CXXFLAGS) -o $@ $<
%.o: %.cpp
$(CXX) $(CXXFLAGS) -o $@ -c $<
%.dep: %.cpp
set -e; $(CXX) -M $(INCLUDES) -c $< \
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
[ -s $@ ] || rm -f $@
DEP_FILES = $(SOURCES:.cpp=.dep)
include $(DEP_FILES)
clean:
/bin/rm -rf $(TARGETS) $(OBJECTS) $(DEP_FILES)
run:
./is_instance_of_test.exe
./member_pointer_test.exe
./operator_tests_simple.exe
./control_structures.exe
./switch_construct.exe
./extending_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_function_references.exe
./exception_test.exe
./phoenix_control_structures_test.exe

View File

@@ -0,0 +1,6 @@
gcc 2.96
cannot compile
exception_test.cpp (internal compiler error)

View File

@@ -0,0 +1,347 @@
// bind_tests_advanced.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/bind.hpp"
#include "boost/any.hpp"
#include <iostream>
#include <functional>
#include <algorithm>
using namespace boost::lambda;
int sum_0() { return 0; }
int sum_1(int a) { return a; }
int sum_2(int a, int b) { return a+b; }
int product_2(int a, int b) { return a*b; }
// unary function that returns a pointer to a binary function
typedef int (*fptr_type)(int, int);
fptr_type sum_or_product(bool x) {
return x ? sum_2 : product_2;
}
// a nullary functor that returns a pointer to a unary function that
// returns a pointer to a binary function.
struct which_one {
typedef fptr_type (*result_type)(bool x);
template <class T> struct sig { typedef result_type type; };
result_type operator()() const { return sum_or_product; }
};
void test_nested_binds()
{
int j = 2; int k = 3;
// bind calls can be nested (the target function can be a lambda functor)
// The interpretation is, that the innermost lambda functor returns something
// that is bindable (another lambda functor, function pointer ...)
bool condition;
condition = true;
BOOST_TEST(bind(bind(&sum_or_product, _1), 1, 2)(condition)==3);
BOOST_TEST(bind(bind(&sum_or_product, _1), _2, _3)(condition, j, k)==5);
condition = false;
BOOST_TEST(bind(bind(&sum_or_product, _1), 1, 2)(condition)==2);
BOOST_TEST(bind(bind(&sum_or_product, _1), _2, _3)(condition, j, k)==6);
which_one wo;
BOOST_TEST(bind(bind(bind(wo), _1), _2, _3)(condition, j, k)==6);
return;
}
// unlambda -------------------------------------------------
// Sometimes it may be necessary to prevent the argument substitution of
// taking place. For example, we may end up with a nested bind expression
// inadvertently when using the target function is received as a parameter
template<class F>
int call_with_100(const F& f) {
// bind(f, _1)(make_const(100));
// This would result in;
// bind(_1 + 1, _1)(make_const(100)) , which would be a compile time error
return bind(unlambda(f), _1)(make_const(100));
// for other functors than lambda functors, unlambda has no effect
// (except for making them const)
}
template<class F>
int call_with_101(const F& f) {
return bind(unlambda(f), _1)(make_const(101));
}
void test_unlambda() {
int i = 1;
BOOST_TEST(unlambda(_1 + _2)(i, i) == 2);
BOOST_TEST(unlambda(++var(i))() == 2);
BOOST_TEST(call_with_100(_1 + 1) == 101);
BOOST_TEST(call_with_101(_1 + 1) == 102);
BOOST_TEST(call_with_100(bind(std_functor(std::bind1st(std::plus<int>(), 1)), _1)) == 101);
// std_functor insturcts LL that the functor defines a result_type typedef
// rather than a sig template.
bind(std_functor(std::plus<int>()), _1, _2)(i, i);
}
// protect ------------------------------------------------------------
// protect protects a lambda functor from argument substitution.
// protect is useful e.g. with nested stl algorithm calls.
namespace ll {
struct for_each {
// note, std::for_each returns it's last argument
// We want the same behaviour from our ll::for_each.
// However, the functor can be called with any arguments, and
// the return type thus depends on the argument types.
// 1. Provide a sig class member template:
// The return type deduction system instantiate this class as:
// sig<Args>::type, where Args is a boost::tuples::cons-list
// The head type is the function object type itself
// cv-qualified (so it is possilbe to provide different return types
// for differently cv-qualified operator()'s.
// The tail type is the list of the types of the actual arguments the
// function was called with.
// So sig should contain a typedef type, which defines a mapping from
// the operator() arguments to its return type.
// Note, that it is possible to provide different sigs for the same functor
// if the functor has several operator()'s, even if they have different
// number of arguments.
// Note, that the argument types in Args are guaranteed to be non-reference
// types, but they can have cv-qualifiers.
template <class Args>
struct sig {
typedef typename boost::remove_const<
typename boost::tuples::element<3, Args>::type
>::type type;
};
template <class A, class B, class C>
C
operator()(const A& a, const B& b, const C& c) const
{ return std::for_each(a, b, c);}
};
} // end of ll namespace
void test_protect()
{
int i = 0;
int b[3][5];
int* a[3];
for(int j=0; j<3; ++j) a[j] = b[j];
std::for_each(a, a+3,
bind(ll::for_each(), _1, _1 + 5, protect(_1 = ++var(i))));
// This is how you could output the values (it is uncommented, no output
// from a regression test file):
// std::for_each(a, a+3,
// bind(ll::for_each(), _1, _1 + 5,
// std::cout << constant("\nLine ") << (&_1 - a) << " : "
// << protect(_1)
// )
// );
int sum = 0;
std::for_each(a, a+3,
bind(ll::for_each(), _1, _1 + 5,
protect(sum += _1))
);
BOOST_TEST(sum == (1+15)*15/2);
sum = 0;
std::for_each(a, a+3,
bind(ll::for_each(), _1, _1 + 5,
sum += 1 + protect(_1)) // add element count
);
BOOST_TEST(sum == (1+15)*15/2 + 15);
(1 + protect(_1))(sum);
int k = 0;
((k += constant(1)) += protect(constant(2)))();
BOOST_TEST(k==1);
k = 0;
((k += constant(1)) += protect(constant(2)))()();
BOOST_TEST(k==3);
// note, the following doesn't work:
// ((var(k) = constant(1)) = protect(constant(2)))();
// (var(k) = constant(1))() returns int& and thus the
// second assignment fails.
// We should have something like:
// bind(var, var(k) = constant(1)) = protect(constant(2)))();
// But currently var is not bindable.
// The same goes with ret. A bindable ret could be handy sometimes as well
// (protect(std::cout << _1), std::cout << _1)(i)(j); does not work
// because the comma operator tries to store the result of the evaluation
// of std::cout << _1 as a copy (and you can't copy std::ostream).
// something like this:
// (protect(std::cout << _1), bind(ref, std::cout << _1))(i)(j);
// the stuff below works, but we do not want extra output to
// cout, must be changed to stringstreams but stringstreams do not
// work due to a bug in the type deduction. Will be fixed...
#if 0
// But for now, ref is not bindable. There are other ways around this:
int x = 1, y = 2;
(protect(std::cout << _1), (std::cout << _1, 0))(x)(y);
// added one dummy value to make the argument to comma an int
// instead of ostream&
// Note, the same problem is more apparent without protect
// (std::cout << 1, std::cout << constant(2))(); // does not work
(boost::ref(std::cout << 1), std::cout << constant(2))(); // this does
#endif
}
void test_lambda_functors_as_arguments_to_lambda_functors() {
// lambda functor is a function object, and can therefore be used
// as an argument to another lambda functors function call object.
// Note however, that the argument/type substitution is not entered again.
// This means, that something like this will not work:
(_1 + _2)(_1, make_const(7));
(_1 + _2)(bind(&sum_0), make_const(7));
// or it does work, but the effect is not to call
// sum_0() + 7, but rather
// bind(sum_0) + 7, which results in another lambda functor
// (lambda functor + int) and can be called again
BOOST_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
// the return type must be defined within the bind call. Lambda functors
// do define the sig template, so if the return type deduction system
// covers the case, there is no need to specify the return type
// explicitly.
int a = 5, b = 6;
// Let type deduction find out the return type
BOOST_TEST(bind(_1, _2, _3)(unlambda(_1 + _2), a, b) == 11);
//specify it yourself:
BOOST_TEST(bind(_1, _2, _3)(ret<int>(_1 + _2), a, b) == 11);
BOOST_TEST(ret<int>(bind(_1, _2, _3))(_1 + _2, a, b) == 11);
BOOST_TEST(bind<int>(_1, _2, _3)(_1 + _2, a, b) == 11);
bind(_1,1.0)(_1+_1);
return;
}
void test_const_parameters() {
// (_1 + _2)(1, 2); // this would fail,
// Either make arguments const:
BOOST_TEST((_1 + _2)(make_const(1), make_const(2)) == 3);
// Or use const_parameters:
BOOST_TEST(const_parameters(_1 + _2)(1, 2) == 3);
}
void test_break_const()
{
// break_const breaks constness! Be careful!
// You need this only if you need to have side effects on some argument(s)
// and some arguments are non-const rvalues:
// E.g.
int i = 1;
// (_1 += _2)(i, 2) // fails, 2 is a non-const rvalue
// const_parameters(_1 += _2)(i, 2) // fails, side-effect to i
break_const(_1 += _2)(i, 2); // ok
BOOST_TEST(i == 3);
}
int test_main(int, char *[]) {
test_nested_binds();
test_unlambda();
test_protect();
test_lambda_functors_as_arguments_to_lambda_functors();
test_const_parameters();
test_break_const();
return 0;
}

141
test/bind_tests_simple.cpp Normal file
View File

@@ -0,0 +1,141 @@
// bind_tests_simple.cpp --------------------------------
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
#include "boost/lambda/bind.hpp"
#include <iostream>
using namespace std;
using namespace boost::lambda;
int sum_of_args_0() { return 0; }
int sum_of_args_1(int a) { return a; }
int sum_of_args_2(int a, int b) { return a+b; }
int sum_of_args_3(int a, int b, int c) { return a+b+c; }
int sum_of_args_4(int a, int b, int c, int d) { return a+b+c+d; }
int sum_of_args_5(int a, int b, int c, int d, int e) { return a+b+c+d+e; }
int sum_of_args_6(int a, int b, int c, int d, int e, int f) { return a+b+c+d+e+f; }
int sum_of_args_7(int a, int b, int c, int d, int e, int f, int g) { return a+b+c+d+e+f+g; }
int sum_of_args_8(int a, int b, int c, int d, int e, int f, int g, int h) { return a+b+c+d+e+f+g+h; }
int sum_of_args_9(int a, int b, int c, int d, int e, int f, int g, int h, int i) { return a+b+c+d+e+f+g+h+i; }
// ----------------------------
class A {
int i;
public:
A(int n) : i(n) {};
int add(const int& j) { return i + j; }
};
void test_member_functions()
{
using boost::ref;
A a(10);
int i = 1;
BOOST_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);
}
int test_main(int, char *[]) {
int i = 1; int j = 2; int k = 3;
int result;
// bind all parameters
BOOST_TEST(bind(&sum_of_args_0)()==0);
BOOST_TEST(bind(&sum_of_args_1, 1)()==1);
BOOST_TEST(bind(&sum_of_args_2, 1, 2)()==3);
BOOST_TEST(bind(&sum_of_args_3, 1, 2, 3)()==6);
BOOST_TEST(bind(&sum_of_args_4, 1, 2, 3, 4)()==10);
BOOST_TEST(bind(&sum_of_args_5, 1, 2, 3, 4, 5)()==15);
BOOST_TEST(bind(&sum_of_args_6, 1, 2, 3, 4, 5, 6)()==21);
BOOST_TEST(bind(&sum_of_args_7, 1, 2, 3, 4, 5, 6, 7)()==28);
BOOST_TEST(bind(&sum_of_args_8, 1, 2, 3, 4, 5, 6, 7, 8)()==36);
BOOST_TEST(bind(&sum_of_args_9, 1, 2, 3, 4, 5, 6, 7, 8, 9)()==45);
// first parameter open
BOOST_TEST(bind(&sum_of_args_0)()==0);
BOOST_TEST(bind(&sum_of_args_1, _1)(i)==1);
BOOST_TEST(bind(&sum_of_args_2, _1, 2)(i)==3);
BOOST_TEST(bind(&sum_of_args_3, _1, 2, 3)(i)==6);
BOOST_TEST(bind(&sum_of_args_4, _1, 2, 3, 4)(i)==10);
BOOST_TEST(bind(&sum_of_args_5, _1, 2, 3, 4, 5)(i)==15);
BOOST_TEST(bind(&sum_of_args_6, _1, 2, 3, 4, 5, 6)(i)==21);
BOOST_TEST(bind(&sum_of_args_7, _1, 2, 3, 4, 5, 6, 7)(i)==28);
BOOST_TEST(bind(&sum_of_args_8, _1, 2, 3, 4, 5, 6, 7, 8)(i)==36);
BOOST_TEST(bind(&sum_of_args_9, _1, 2, 3, 4, 5, 6, 7, 8, 9)(i)==45);
// two open arguments
BOOST_TEST(bind(&sum_of_args_0)()==0);
BOOST_TEST(bind(&sum_of_args_1, _1)(i)==1);
BOOST_TEST(bind(&sum_of_args_2, _1, _2)(i, j)==3);
BOOST_TEST(bind(&sum_of_args_3, _1, _2, 3)(i, j)==6);
BOOST_TEST(bind(&sum_of_args_4, _1, _2, 3, 4)(i, j)==10);
BOOST_TEST(bind(&sum_of_args_5, _1, _2, 3, 4, 5)(i, j)==15);
BOOST_TEST(bind(&sum_of_args_6, _1, _2, 3, 4, 5, 6)(i, j)==21);
BOOST_TEST(bind(&sum_of_args_7, _1, _2, 3, 4, 5, 6, 7)(i, j)==28);
BOOST_TEST(bind(&sum_of_args_8, _1, _2, 3, 4, 5, 6, 7, 8)(i, j)==36);
BOOST_TEST(bind(&sum_of_args_9, _1, _2, 3, 4, 5, 6, 7, 8, 9)(i, j)==45);
// three open arguments
BOOST_TEST(bind(&sum_of_args_0)()==0);
BOOST_TEST(bind(&sum_of_args_1, _1)(i)==1);
BOOST_TEST(bind(&sum_of_args_2, _1, _2)(i, j)==3);
BOOST_TEST(bind(&sum_of_args_3, _1, _2, _3)(i, j, k)==6);
BOOST_TEST(bind(&sum_of_args_4, _1, _2, _3, 4)(i, j, k)==10);
BOOST_TEST(bind(&sum_of_args_5, _1, _2, _3, 4, 5)(i, j, k)==15);
BOOST_TEST(bind(&sum_of_args_6, _1, _2, _3, 4, 5, 6)(i, j, k)==21);
BOOST_TEST(bind(&sum_of_args_7, _1, _2, _3, 4, 5, 6, 7)(i, j, k)==28);
BOOST_TEST(bind(&sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8)(i, j, k)==36);
BOOST_TEST(bind(&sum_of_args_9, _1, _2, _3, 4, 5, 6, 7, 8, 9)(i, j, k)==45);
// function compositions with bind
BOOST_TEST(bind(&sum_of_args_3, bind(&sum_of_args_2, _1, 2), 2, 3)(i)==8);
BOOST_TEST(
bind(&sum_of_args_9,
bind(&sum_of_args_0), // 0
bind(&sum_of_args_1, _1), // 1
bind(&sum_of_args_2, _1, _2), // 3
bind(&sum_of_args_3, _1, _2, _3), // 6
bind(&sum_of_args_4, _1, _2, _3, 4), // 10
bind(&sum_of_args_5, _1, _2, _3, 4, 5), // 15
bind(&sum_of_args_6, _1, _2, _3, 4, 5, 6), // 21
bind(&sum_of_args_7, _1, _2, _3, 4, 5, 6, 7), // 28
bind(&sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8) // 36
)(i, j, k) == 120);
// deeper nesting
result =
bind(&sum_of_args_1, // 12
bind(&sum_of_args_4, // 12
bind(&sum_of_args_2, // 3
bind(&sum_of_args_1, // 1
bind(&sum_of_args_1, _1) // 1
),
_2),
_2,
_3,
4)
)(i, j, k);
BOOST_TEST(result == 12);
test_member_functions();
return 0;
}

View File

@@ -0,0 +1,139 @@
// bind_tests_simple.cpp --------------------------------
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
#include "boost/lambda/bind.hpp"
#include <iostream>
using namespace std;
using namespace boost::lambda;
int sum_of_args_0() { return 0; }
int sum_of_args_1(int a) { return a; }
int sum_of_args_2(int a, int b) { return a+b; }
int sum_of_args_3(int a, int b, int c) { return a+b+c; }
int sum_of_args_4(int a, int b, int c, int d) { return a+b+c+d; }
int sum_of_args_5(int a, int b, int c, int d, int e) { return a+b+c+d+e; }
int sum_of_args_6(int a, int b, int c, int d, int e, int f) { return a+b+c+d+e+f; }
int sum_of_args_7(int a, int b, int c, int d, int e, int f, int g) { return a+b+c+d+e+f+g; }
int sum_of_args_8(int a, int b, int c, int d, int e, int f, int g, int h) { return a+b+c+d+e+f+g+h; }
int sum_of_args_9(int a, int b, int c, int d, int e, int f, int g, int h, int i) { return a+b+c+d+e+f+g+h+i; }
// ----------------------------
class A {
int i;
public:
A(int n) : i(n) {};
int add(const int& j) { return i + j; }
};
void test_member_functions()
{
using boost::ref;
A a(10);
int i = 1;
BOOST_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);
}
int test_main(int, char *[]) {
int i = 1; int j = 2; int k = 3;
int result;
// bind all parameters
BOOST_TEST(bind(sum_of_args_0)()==0);
BOOST_TEST(bind(sum_of_args_1, 1)()==1);
BOOST_TEST(bind(sum_of_args_2, 1, 2)()==3);
BOOST_TEST(bind(sum_of_args_3, 1, 2, 3)()==6);
BOOST_TEST(bind(sum_of_args_4, 1, 2, 3, 4)()==10);
BOOST_TEST(bind(sum_of_args_5, 1, 2, 3, 4, 5)()==15);
BOOST_TEST(bind(sum_of_args_6, 1, 2, 3, 4, 5, 6)()==21);
BOOST_TEST(bind(sum_of_args_7, 1, 2, 3, 4, 5, 6, 7)()==28);
BOOST_TEST(bind(sum_of_args_8, 1, 2, 3, 4, 5, 6, 7, 8)()==36);
BOOST_TEST(bind(sum_of_args_9, 1, 2, 3, 4, 5, 6, 7, 8, 9)()==45);
// first parameter open
BOOST_TEST(bind(sum_of_args_0)()==0);
BOOST_TEST(bind(sum_of_args_1, _1)(i)==1);
BOOST_TEST(bind(sum_of_args_2, _1, 2)(i)==3);
BOOST_TEST(bind(sum_of_args_3, _1, 2, 3)(i)==6);
BOOST_TEST(bind(sum_of_args_4, _1, 2, 3, 4)(i)==10);
BOOST_TEST(bind(sum_of_args_5, _1, 2, 3, 4, 5)(i)==15);
BOOST_TEST(bind(sum_of_args_6, _1, 2, 3, 4, 5, 6)(i)==21);
BOOST_TEST(bind(sum_of_args_7, _1, 2, 3, 4, 5, 6, 7)(i)==28);
BOOST_TEST(bind(sum_of_args_8, _1, 2, 3, 4, 5, 6, 7, 8)(i)==36);
BOOST_TEST(bind(sum_of_args_9, _1, 2, 3, 4, 5, 6, 7, 8, 9)(i)==45);
// two open arguments
BOOST_TEST(bind(sum_of_args_0)()==0);
BOOST_TEST(bind(sum_of_args_1, _1)(i)==1);
BOOST_TEST(bind(sum_of_args_2, _1, _2)(i, j)==3);
BOOST_TEST(bind(sum_of_args_3, _1, _2, 3)(i, j)==6);
BOOST_TEST(bind(sum_of_args_4, _1, _2, 3, 4)(i, j)==10);
BOOST_TEST(bind(sum_of_args_5, _1, _2, 3, 4, 5)(i, j)==15);
BOOST_TEST(bind(sum_of_args_6, _1, _2, 3, 4, 5, 6)(i, j)==21);
BOOST_TEST(bind(sum_of_args_7, _1, _2, 3, 4, 5, 6, 7)(i, j)==28);
BOOST_TEST(bind(sum_of_args_8, _1, _2, 3, 4, 5, 6, 7, 8)(i, j)==36);
BOOST_TEST(bind(sum_of_args_9, _1, _2, 3, 4, 5, 6, 7, 8, 9)(i, j)==45);
// three open arguments
BOOST_TEST(bind(sum_of_args_0)()==0);
BOOST_TEST(bind(sum_of_args_1, _1)(i)==1);
BOOST_TEST(bind(sum_of_args_2, _1, _2)(i, j)==3);
BOOST_TEST(bind(sum_of_args_3, _1, _2, _3)(i, j, k)==6);
BOOST_TEST(bind(sum_of_args_4, _1, _2, _3, 4)(i, j, k)==10);
BOOST_TEST(bind(sum_of_args_5, _1, _2, _3, 4, 5)(i, j, k)==15);
BOOST_TEST(bind(sum_of_args_6, _1, _2, _3, 4, 5, 6)(i, j, k)==21);
BOOST_TEST(bind(sum_of_args_7, _1, _2, _3, 4, 5, 6, 7)(i, j, k)==28);
BOOST_TEST(bind(sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8)(i, j, k)==36);
BOOST_TEST(bind(sum_of_args_9, _1, _2, _3, 4, 5, 6, 7, 8, 9)(i, j, k)==45);
// function compositions with bind
BOOST_TEST(bind(sum_of_args_3, bind(sum_of_args_2, _1, 2), 2, 3)(i)==8);
BOOST_TEST(
bind(sum_of_args_9,
bind(sum_of_args_0), // 0
bind(sum_of_args_1, _1), // 1
bind(sum_of_args_2, _1, _2), // 3
bind(sum_of_args_3, _1, _2, _3), // 6
bind(sum_of_args_4, _1, _2, _3, 4), // 10
bind(sum_of_args_5, _1, _2, _3, 4, 5), // 15
bind(sum_of_args_6, _1, _2, _3, 4, 5, 6), // 21
bind(sum_of_args_7, _1, _2, _3, 4, 5, 6, 7), // 28
bind(sum_of_args_8, _1, _2, _3, 4, 5, 6, 7, 8) // 36
)(i, j, k) == 120);
// deeper nesting
result =
bind(sum_of_args_1, // 12
bind(sum_of_args_4, // 12
bind(sum_of_args_2, // 3
bind(sum_of_args_1, // 1
bind(sum_of_args_1, _1) // 1
),
_2),
_2,
_3,
4)
)(i, j, k);
BOOST_TEST(result == 12);
test_member_functions();
return 0;
}

60
test/bll_and_function.cpp Normal file
View File

@@ -0,0 +1,60 @@
// bll_and_function.cpp --------------------------------
// test using BLL and boost::function
#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/function.hpp"
#include <vector>
#include <map>
#include <set>
#include <string>
using namespace boost::lambda;
using namespace std;
void test_function() {
boost::function<int, int, int> f;
f = _1 + _2;
BOOST_TEST(f(1, 2)== 3);
int i=1; int j=2;
boost::function<int&, int&, int> g = _1 += _2;
g(i, j);
BOOST_TEST(i==3);
int* sum = new int();
*sum = 0;
boost::function<int&, int> counter = *sum += _1;
counter(5); // ok, sum* = 5;
BOOST_TEST(*sum == 5);
delete sum;
// The next statement would lead to a dangling reference
// counter(3); // error, *sum does not exist anymore
}
int test_main(int, char *[]) {
test_function();
return 0;
}

96
test/cast_test.cpp Normal file
View File

@@ -0,0 +1,96 @@
// cast_tests.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/casts.hpp"
#include <string>
using namespace boost::lambda;
using namespace std;
class base {
int x;
public:
virtual std::string class_name() const { return "const base"; }
virtual std::string class_name() { return "base"; }
};
class derived : public base {
int y[100];
public:
virtual std::string class_name() const { return "const derived"; }
virtual std::string class_name() { return "derived"; }
};
void do_test() {
derived *p_derived = new derived;
base *p_base = new base;
base *b = 0;
derived *d = 0;
(var(b) = ll_static_cast<base *>(p_derived))();
(var(d) = ll_static_cast<derived *>(b))();
BOOST_TEST(b->class_name() == "derived");
BOOST_TEST(d->class_name() == "derived");
(var(b) = ll_dynamic_cast<derived *>(b))();
BOOST_TEST(b != 0);
BOOST_TEST(b->class_name() == "derived");
(var(d) = ll_dynamic_cast<derived *>(p_base))();
BOOST_TEST(d == 0);
const derived* p_const_derived = p_derived;
BOOST_TEST(p_const_derived->class_name() == "const derived");
(var(d) = ll_const_cast<derived *>(p_const_derived))();
BOOST_TEST(d->class_name() == "derived");
int i = 10;
char* cp = reinterpret_cast<char*>(&i);
int* ip;
(var(ip) = ll_reinterpret_cast<int *>(cp))();
BOOST_TEST(*ip == 10);
// typeid
BOOST_TEST(string(ll_typeid(d)().name()) == string(typeid(d).name()));
// sizeof
BOOST_TEST(ll_sizeof(_1)(p_derived) == sizeof(p_derived));
BOOST_TEST(ll_sizeof(_1)(*p_derived) == sizeof(*p_derived));
BOOST_TEST(ll_sizeof(_1)(p_base) == sizeof(p_base));
BOOST_TEST(ll_sizeof(_1)(*p_base) == sizeof(*p_base));
int an_array[100];
BOOST_TEST(ll_sizeof(_1)(an_array) == 100 * sizeof(int));
delete p_derived;
delete p_base;
}
int test_main(int, char *[]) {
do_test();
return 0;
}

250
test/constructor_tests.cpp Normal file
View File

@@ -0,0 +1,250 @@
// constructor_tests.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/bind.hpp"
#include "boost/lambda/construct.hpp"
#include <iostream>
#include <algorithm>
#include <vector>
using namespace boost::lambda;
using namespace std;
template<class T>
bool check_tuple(int n, const T& t)
{
return (t.get_head() == n) && check_tuple(n+1, t.get_tail());
}
template <>
bool check_tuple(int n, const null_type& ) { return true; }
void constructor_all_lengths()
{
bool ok;
ok = check_tuple(
1,
bind(constructor<tuple<int> >(),
1)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int> >(),
1, 2)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int> >(),
1, 2, 3)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int, int> >(),
1, 2, 3, 4)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int, int, int> >(),
1, 2, 3, 4, 5)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6, 7)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6, 7, 8)()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
bind(constructor<tuple<int, int, int, int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6, 7, 8, 9)()
);
BOOST_TEST(ok);
}
void new_ptr_all_lengths()
{
bool ok;
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int> >(),
1))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int> >(),
1, 2))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int> >(),
1, 2, 3))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int, int> >(),
1, 2, 3, 4))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int, int, int> >(),
1, 2, 3, 4, 5))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6, 7))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6, 7, 8))()
);
BOOST_TEST(ok);
ok = check_tuple(
1,
*(bind(new_ptr<tuple<int, int, int, int, int, int, int, int, int> >(),
1, 2, 3, 4, 5, 6, 7, 8, 9))()
);
BOOST_TEST(ok);
}
class is_destructor_called {
bool& b;
public:
is_destructor_called(bool& bb) : b(bb) { b = false; }
~is_destructor_called() { b = true; }
};
void test_destructor ()
{
char space[sizeof(is_destructor_called)];
bool flag;
is_destructor_called* idc = new(space) is_destructor_called(flag);
BOOST_TEST(flag == false);
bind(destructor(), _1)(idc);
BOOST_TEST(flag == true);
idc = new(space) is_destructor_called(flag);
BOOST_TEST(flag == false);
bind(destructor(), _1)(*idc);
BOOST_TEST(flag == true);
}
class count_deletes {
public:
static int count;
~count_deletes() { ++count; }
};
int count_deletes::count = 0;
void test_news_and_deletes ()
{
int* i[10];
for_each(i, i+10, _1 = bind(new_ptr<int>(), 2));
int count_errors = 0;
for_each(i, i+10, (*_1 == 2) || ++var(count_errors));
BOOST_TEST(count_errors == 0);
count_deletes* ct[10];
for_each(ct, ct+10, _1 = bind(new_ptr<count_deletes>()));
count_deletes::count = 0;
for_each(ct, ct+10, bind(delete_ptr(), _1));
BOOST_TEST(count_deletes::count == 10);
}
void test_array_new_and_delete()
{
count_deletes* c;
(_1 = bind(new_array<count_deletes>(), 5))(c);
count_deletes::count = 0;
bind(delete_array(), _1)(c);
BOOST_TEST(count_deletes::count == 5);
}
void delayed_construction()
{
vector<int> x(3);
vector<int> y(3);
fill(x.begin(), x.end(), 0);
fill(y.begin(), y.end(), 1);
vector<pair<int, int> > v;
transform(x.begin(), x.end(), y.begin(), back_inserter(v),
bind(constructor<pair<int, int> >(), _1, _2) );
}
int test_main(int, char *[]) {
constructor_all_lengths();
new_ptr_all_lengths();
delayed_construction();
test_destructor();
test_news_and_deletes();
test_array_new_and_delete();
return 0;
}

100
test/control_structures.cpp Normal file
View File

@@ -0,0 +1,100 @@
#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 <algorithm>
#include <vector>
using namespace boost;
using namespace boost::lambda;
// 2 container for_each
template <class InputIter1, class InputIter2, class Function>
Function for_each(InputIter1 first, InputIter1 last,
InputIter2 first2, Function f) {
for ( ; first != last; ++first, ++first2)
f(*first, *first2);
return f;
}
void simple_loops() {
// for loops ---------------------------------------------------------
int i;
int arithmetic_series = 0;
for_loop(_1 = 0, _1 < 10, _1++, arithmetic_series += _1)(i);
BOOST_TEST(arithmetic_series == 45);
// no body case
for_loop(var(i) = 0, var(i) < 100, ++var(i))();
BOOST_TEST(i == 100);
// while loops -------------------------------------------------------
int a = 0, b = 0, c = 0;
while_loop((_1 + _2) >= (_1 * _2), (++_1, ++_2, ++_3))(a, b, c);
BOOST_TEST(c == 3);
int count;
count = 0; i = 0;
while_loop(_1++ < 10, ++var(count))(i);
BOOST_TEST(count == 10);
// note that the first parameter of do_while_loop is the condition
count = 0; i = 0;
do_while_loop(_1++ < 10, ++var(count))(i);
BOOST_TEST(count == 11);
a = 0;
do_while_loop(constant(false), _1++)(a);
BOOST_TEST(a == 1);
// no body cases
a = 40; b = 30;
while_loop(--_1 > _2)(a, b);
BOOST_TEST(a == b);
// (the no body case for do_while_loop is pretty redundant)
a = 40; b = 30;
do_while_loop(--_1 > _2)(a, b);
BOOST_TEST(a == b);
}
void simple_ifs () {
int value = 42;
if_then(_1 < 0, _1 = 0)(value);
BOOST_TEST(value == 42);
value = -42;
if_then(_1 < 0, _1 = -_1)(value);
BOOST_TEST(value == 42);
int min;
if_then_else(_1 < _2, var(min) = _1, var(min) = _2)
(make_const(1), make_const(2));
BOOST_TEST(min == 1);
if_then_else(_1 < _2, var(min) = _1, var(min) = _2)
(make_const(5), make_const(3));
BOOST_TEST(min == 3);
int x, y;
x = -1; y = 1;
BOOST_TEST(if_then_else_return(_1 < _2, _2, _1)(x, y) == std::max(x ,y));
BOOST_TEST(if_then_else_return(_1 < _2, _2, _1)(y, x) == std::max(x ,y));
}
int test_main(int, char *[])
{
simple_loops();
simple_ifs();
return 0;
}

595
test/exception_test.cpp Normal file
View File

@@ -0,0 +1,595 @@
#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/exceptions.hpp"
#include "boost/lambda/bind.hpp"
#include<iostream>
#include<algorithm>
#include <cstdlib>
#include <iostream>
using namespace boost::lambda;
using namespace std;
// to prevent unused variables warnings
template <class T> void dummy(const T& t) {}
void erroneous_exception_related_lambda_expressions() {
int i = 0;
dummy(i);
// Uncommenting any of the below code lines should result in a compile
// time error
// this should fail (a rethrow binder outside of catch
// rethrow()();
// this should fail too for the same reason
// try_catch(rethrow(), catch_all(cout << constant("Howdy")))();
// this fails too (_e outside of catch_exception)
// (_1 + _2 + _e)(i, i, i);
// and this (_e outside of catch_exception)
// try_catch( throw_exception(1), catch_all(cout << _e));
// and this (_3 in catch_exception
// try_catch( throw_exception(1), catch_exception<int>(cout << _3));
}
class A1 {};
class A2 {};
class A3 {};
class A4 {};
class A5 {};
class A6 {};
class A7 {};
class A8 {};
class A9 {};
void throw_AX(int j) {
int i = j;
switch(i) {
case 1: throw A1();
case 2: throw A2();
case 3: throw A3();
case 4: throw A4();
case 5: throw A5();
case 6: throw A6();
case 7: throw A7();
case 8: throw A8();
case 9: throw A9();
}
}
void test_different_number_of_catch_blocks() {
int ecount;
// no catch(...) cases
ecount = 0;
for(int i=1; i<=1; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 1);
ecount = 0;
for(int i=1; i<=2; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 2);
ecount = 0;
for(int i=1; i<=3; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 3);
ecount = 0;
for(int i=1; i<=4; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 4);
ecount = 0;
for(int i=1; i<=5; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 5);
ecount = 0;
for(int i=1; i<=6; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 6);
ecount = 0;
for(int i=1; i<=7; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
),
catch_exception<A7>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 7);
ecount = 0;
for(int i=1; i<=8; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
),
catch_exception<A7>(
var(ecount)++
),
catch_exception<A8>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 8);
ecount = 0;
for(int i=1; i<=9; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
),
catch_exception<A7>(
var(ecount)++
),
catch_exception<A8>(
var(ecount)++
),
catch_exception<A9>(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 9);
// with catch(...) blocks
ecount = 0;
for(int i=1; i<=1; i++)
{
try_catch(
bind(throw_AX, _1),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 1);
ecount = 0;
for(int i=1; i<=2; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 2);
ecount = 0;
for(int i=1; i<=3; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 3);
ecount = 0;
for(int i=1; i<=4; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 4);
ecount = 0;
for(int i=1; i<=5; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 5);
ecount = 0;
for(int i=1; i<=6; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 6);
ecount = 0;
for(int i=1; i<=7; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 7);
ecount = 0;
for(int i=1; i<=8; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
),
catch_exception<A7>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 8);
ecount = 0;
for(int i=1; i<=9; i++)
{
try_catch(
bind(throw_AX, _1),
catch_exception<A1>(
var(ecount)++
),
catch_exception<A2>(
var(ecount)++
),
catch_exception<A3>(
var(ecount)++
),
catch_exception<A4>(
var(ecount)++
),
catch_exception<A5>(
var(ecount)++
),
catch_exception<A6>(
var(ecount)++
),
catch_exception<A7>(
var(ecount)++
),
catch_exception<A8>(
var(ecount)++
),
catch_all(
var(ecount)++
)
)(i);
}
BOOST_TEST(ecount == 9);
}
void return_type_matching() {
// Rules for return types of the lambda functors in try and catch parts:
// 1. The try part dictates the return type of the whole
// try_catch lambda functor
// 2. If return type of try part is void, catch parts can return anything,
// but the return types are ignored
// 3. If the return type of the try part is A, then each catch return type
// must be implicitly convertible to A, or then it must throw for sure
int i = 1;
BOOST_TEST(
try_catch(
_1 + 1,
catch_exception<int>((&_1, rethrow())), // no match, but ok since throws
catch_exception<char>(_e) // ok, char convertible to int
)(i)
== 2
);
// note that while e.g. char is convertible to int, it is not convertible
// to int&, (some lambda functors return references)
// try_catch(
// _1 += 1,
// catch_exception<char>(_e) // NOT ok, char not convertible to int&
// )(i);
// if you don't care about the return type, you can use make_void
try_catch(
make_void(_1 += 1),
catch_exception<char>(_e) // since try is void, catch can return anything
)(i);
BOOST_TEST(i == 2);
try_catch(
(_1 += 1, throw_exception('a')),
catch_exception<char>(_e) // since try throws, it is void,
// so catch can return anything
)(i);
BOOST_TEST(i == 3);
char a = 'a';
try_catch(
try_catch(
throw_exception(1),
catch_exception<int>(throw_exception('b'))
),
catch_exception<char>( _1 = _e )
)(a);
BOOST_TEST(a == 'b');
}
int test_main(int, char *[]) {
try
{
test_different_number_of_catch_blocks();
return_type_matching();
}
catch (int x)
{
BOOST_TEST(false);
}
catch(...)
{
BOOST_TEST(false);
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,373 @@
// extending_return_type_traits.cpp --------------------------------
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
#include "boost/lambda/bind.hpp"
#include "boost/lambda/lambda.hpp"
#include <iostream>
#include <functional>
#include <algorithm>
class A {};
class B {};
using namespace boost::lambda;
B operator--(const A&, int) { return B(); }
B operator--(A&) { return B(); }
B operator++(const A&, int) { return B(); }
B operator++(A&) { return B(); }
B operator-(const A&) { return B(); }
B operator+(const A&) { return B(); }
B operator!(const A&) { return B(); }
B operator&(const A&) { return B(); }
B operator*(const A&) { return B(); }
namespace boost {
namespace lambda {
// unary + and -
template<class Act>
struct plain_return_type_1<unary_arithmetic_action<Act>, A > {
typedef B type;
};
// post incr/decr
template<class Act>
struct plain_return_type_1<post_increment_decrement_action<Act>, A > {
typedef B type;
};
// pre incr/decr
template<class Act>
struct plain_return_type_1<pre_increment_decrement_action<Act>, A > {
typedef B type;
};
// !
template<>
struct plain_return_type_1<logical_action<not_action>, A> {
typedef B type;
};
// &
template<>
struct plain_return_type_1<other_action<addressof_action>, A> {
typedef B type;
};
// *
template<>
struct plain_return_type_1<other_action<contentsof_action>, A> {
typedef B type;
};
} // lambda
} // boost
void ok(B b) {}
void test_unary_operators()
{
A a; int i = 1;
ok((++_1)(a));
ok((--_1)(a));
ok((_1++)(a));
ok((_1--)(a));
ok((+_1)(a));
ok((-_1)(a));
ok((!_1)(a));
ok((&_1)(a));
ok((*_1)(a));
BOOST_TEST((*_1)(make_const(&i)) == 1);
}
class X {};
class Y {};
class Z {};
Z operator+(const X&, const Y&) { return Z(); }
Z operator-(const X&, const Y&) { return Z(); }
X operator*(const X&, const Y&) { return X(); }
Z operator/(const X&, const Y&) { return Z(); }
Z operator%(const X&, const Y&) { return Z(); }
class XX {};
class YY {};
class ZZ {};
class VV {};
// it is possible to support differently cv-qualified versions
YY operator*(XX&, YY&) { return YY(); }
ZZ operator*(const XX&, const YY&) { return ZZ(); }
XX operator*(volatile XX&, volatile YY&) { return XX(); }
VV operator*(const volatile XX&, const volatile YY&) { return VV(); }
// the traits can be more complex:
template <class T>
class my_vector {};
template<class A, class B>
my_vector<typename return_type_2<arithmetic_action<plus_action>, A&, B&>::type>
operator+(const my_vector<A>& a, const my_vector<B>& b)
{
typedef typename
return_type_2<arithmetic_action<plus_action>, A&, B&>::type res_type;
return my_vector<res_type>();
}
// bitwise ops:
X operator<<(const X&, const Y&) { return X(); }
Z operator>>(const X&, const Y&) { return Z(); }
Z operator&(const X&, const Y&) { return Z(); }
Z operator|(const X&, const Y&) { return Z(); }
Z operator^(const X&, const Y&) { return Z(); }
// comparison ops:
X operator<(const X&, const Y&) { return X(); }
Z operator>(const X&, const Y&) { return Z(); }
Z operator<=(const X&, const Y&) { return Z(); }
Z operator>=(const X&, const Y&) { return Z(); }
Z operator==(const X&, const Y&) { return Z(); }
Z operator!=(const X&, const Y&) { return Z(); }
// logical
X operator&&(const X&, const Y&) { return X(); }
Z operator||(const X&, const Y&) { return Z(); }
// arithh assignment
Z operator+=( X&, const Y&) { return Z(); }
Z operator-=( X&, const Y&) { return Z(); }
Y operator*=( X&, const Y&) { return Y(); }
Z operator/=( X&, const Y&) { return Z(); }
Z operator%=( X&, const Y&) { return Z(); }
// bitwise assignment
Z operator<<=( X&, const Y&) { return Z(); }
Z operator>>=( X&, const Y&) { return Z(); }
Y operator&=( X&, const Y&) { return Y(); }
Z operator|=( X&, const Y&) { return Z(); }
Z operator^=( X&, const Y&) { return Z(); }
// assignment
class Assign {
public:
void operator=(const Assign& a) {}
X operator[](const int& i) { return X(); }
};
namespace boost {
namespace lambda {
// you can do action groups
template<class Act>
struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
typedef Z type;
};
// or specialize the exact action
template<>
struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
typedef X type;
};
// if you want to make a distinction between differently cv-qualified
// types, you need to specialize on a different level:
template<>
struct return_type_2<arithmetic_action<multiply_action>, XX, YY> {
typedef YY type;
};
template<>
struct return_type_2<arithmetic_action<multiply_action>, const XX, const YY> {
typedef ZZ type;
};
template<>
struct return_type_2<arithmetic_action<multiply_action>, volatile XX, volatile YY> {
typedef XX type;
};
template<>
struct return_type_2<arithmetic_action<multiply_action>, volatile const XX, const volatile YY> {
typedef VV type;
};
// the mapping can be more complex:
template<class A, class B>
struct plain_return_type_2<arithmetic_action<plus_action>, my_vector<A>, my_vector<B> > {
typedef typename
return_type_2<arithmetic_action<plus_action>, A&, B&>::type res_type;
typedef my_vector<res_type> type;
};
// bitwise binary:
// you can do action groups
template<class Act>
struct plain_return_type_2<bitwise_action<Act>, X, Y> {
typedef Z type;
};
// or specialize the exact action
template<>
struct plain_return_type_2<bitwise_action<leftshift_action>, X, Y> {
typedef X type;
};
// comparison binary:
// you can do action groups
template<class Act>
struct plain_return_type_2<relational_action<Act>, X, Y> {
typedef Z type;
};
// or specialize the exact action
template<>
struct plain_return_type_2<relational_action<less_action>, X, Y> {
typedef X type;
};
// logical binary:
// you can do action groups
template<class Act>
struct plain_return_type_2<logical_action<Act>, X, Y> {
typedef Z type;
};
// or specialize the exact action
template<>
struct plain_return_type_2<logical_action<and_action>, X, Y> {
typedef X type;
};
// arithmetic assignment :
// you can do action groups
template<class Act>
struct plain_return_type_2<arithmetic_assignment_action<Act>, X, Y> {
typedef Z type;
};
// or specialize the exact action
template<>
struct plain_return_type_2<arithmetic_assignment_action<multiply_action>, X, Y> {
typedef Y type;
};
// arithmetic assignment :
// you can do action groups
template<class Act>
struct plain_return_type_2<bitwise_assignment_action<Act>, X, Y> {
typedef Z type;
};
// or specialize the exact action
template<>
struct plain_return_type_2<bitwise_assignment_action<and_action>, X, Y> {
typedef Y type;
};
// assignment
template<>
struct plain_return_type_2<other_action<assignment_action>, Assign, Assign> {
typedef void type;
};
// subscript
template<>
struct plain_return_type_2<other_action<subscript_action>, Assign, int> {
typedef X type;
};
} // end lambda
} // end boost
void test_binary_operators() {
X x; Y y;
(_1 + _2)(x, y);
(_1 - _2)(x, y);
(_1 * _2)(x, y);
(_1 / _2)(x, y);
(_1 % _2)(x, y);
// make a distinction between differently cv-qualified operators
XX xx; YY yy;
const XX& cxx = xx;
const YY& cyy = yy;
volatile XX& vxx = xx;
volatile YY& vyy = yy;
const volatile XX& cvxx = xx;
const volatile YY& cvyy = yy;
ZZ dummy1 = (_1 * _2)(cxx, cyy);
YY dummy2 = (_1 * _2)(xx, yy);
XX dummy3 = (_1 * _2)(vxx, vyy);
VV dummy4 = (_1 * _2)(cvxx, cvyy);
my_vector<int> v1; my_vector<double> v2;
my_vector<double> d = (_1 + _2)(v1, v2);
// bitwise
(_1 << _2)(x, y);
(_1 >> _2)(x, y);
(_1 | _2)(x, y);
(_1 & _2)(x, y);
(_1 ^ _2)(x, y);
// comparison
(_1 < _2)(x, y);
(_1 > _2)(x, y);
(_1 <= _2)(x, y);
(_1 >= _2)(x, y);
(_1 == _2)(x, y);
(_1 != _2)(x, y);
// logical
(_1 || _2)(x, y);
(_1 && _2)(x, y);
// arithmetic assignment
(_1 += _2)(x, y);
(_1 -= _2)(x, y);
(_1 *= _2)(x, y);
(_1 /= _2)(x, y);
(_1 %= _2)(x, y);
// bitwise assignment
(_1 <<= _2)(x, y);
(_1 >>= _2)(x, y);
(_1 |= _2)(x, y);
(_1 &= _2)(x, y);
(_1 ^= _2)(x, y);
}
int test_main(int, char *[]) {
test_unary_operators();
test_binary_operators();
return 0;
}

View File

@@ -0,0 +1,68 @@
// is_convertible_to_template_test.cpp ----------------------------
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
#include "boost/lambda/detail/is_instance_of.hpp"
#include <iostream>
template <class T1> struct A1 {};
template <class T1, class T2> struct A2 {};
template <class T1, class T2, class T3> struct A3 {};
template <class T1, class T2, class T3, class T4> struct A4 {};
class B1 : public A1<int> {};
class B2 : public A2<int,int> {};
class B3 : public A3<int,int,int> {};
class B4 : public A4<int,int,int,int> {};
// classes that are convertible to classes that derive from A instances
// This is not enough to make the test succeed
class C1 { public: operator A1<int>() { return A1<int>(); } };
class C2 { public: operator B2() { return B2(); } };
class C3 { public: operator B3() { return B3(); } };
class C4 { public: operator B4() { return B4(); } };
// test that the result is really a constant
// (in an alternative implementation, gcc 3.0.2. claimed that it was
// a non-constant)
template <bool b> class X {};
// this should compile
X<boost::lambda::is_instance_of_2<int, A2>::value> x;
int test_main(int, char *[]) {
using boost::lambda::is_instance_of_1;
using boost::lambda::is_instance_of_2;
using boost::lambda::is_instance_of_3;
using boost::lambda::is_instance_of_4;
BOOST_TEST((is_instance_of_1<B1, A1>::value == true));
BOOST_TEST((is_instance_of_1<A1<float>, A1>::value == true));
BOOST_TEST((is_instance_of_1<int, A1>::value == false));
BOOST_TEST((is_instance_of_1<C1, A1>::value == false));
BOOST_TEST((is_instance_of_2<B2, A2>::value == true));
BOOST_TEST((is_instance_of_2<A2<int, float>, A2>::value == true));
BOOST_TEST((is_instance_of_2<int, A2>::value == false));
BOOST_TEST((is_instance_of_2<C2, A2>::value == false));
BOOST_TEST((is_instance_of_3<B3, A3>::value == true));
BOOST_TEST((is_instance_of_3<A3<int, float, char>, A3>::value == true));
BOOST_TEST((is_instance_of_3<int, A3>::value == false));
BOOST_TEST((is_instance_of_3<C3, A3>::value == false));
BOOST_TEST((is_instance_of_4<B4, A4>::value == true));
BOOST_TEST((is_instance_of_4<A4<int, float, char, double>, A4>::value == true));
BOOST_TEST((is_instance_of_4<int, A4>::value == false));
BOOST_TEST((is_instance_of_4<C4, A4>::value == false));
return 0;
}

View File

@@ -0,0 +1,181 @@
// member_pointer_test.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/bind.hpp"
#include <string>
using namespace boost::lambda;
using namespace std;
struct my_struct {
my_struct(int x) : mem(x) {};
int mem;
int fooc() const { return mem; }
int foo() { return mem; }
int foo1c(int y) const { return y + mem; }
int foo1(int y) { return y + mem; }
int foo2c(int y, int x) const { return y + x + mem; }
int foo2(int y, int x) { return y + x + mem; }
int foo3c(int y, int x, int z) const { return y + x + z + mem; }
int foo3(int y, int x, int z ){ return y + x + z + mem; }
int foo4c(int a1, int a2, int a3, int a4) const { return a1+a2+a3+a4+mem; }
int foo4(int a1, int a2, int a3, int a4){ return a1+a2+a3+a4+mem; }
int foo3default(int y = 1, int x = 2, int z = 3) { return y + x + z + mem; }
};
my_struct x(3);
void pointer_to_data_member_tests() {
// int i = 0;
my_struct *y = &x;
BOOST_TEST((_1 ->* &my_struct::mem)(y) == 3);
(_1 ->* &my_struct::mem)(y) = 4;
BOOST_TEST(x.mem == 4);
((_1 ->* &my_struct::mem) = 5)(y);
BOOST_TEST(x.mem == 5);
// &my_struct::mem is a temporary, must be constified
((y ->* _1) = 6)(make_const(&my_struct::mem));
BOOST_TEST(x.mem == 6);
((_1 ->* _2) = 7)(y, make_const(&my_struct::mem));
BOOST_TEST(x.mem == 7);
}
void pointer_to_member_function_tests() {
my_struct *y = new my_struct(1);
BOOST_TEST( (_1 ->* &my_struct::foo)(y)() == (y->mem));
BOOST_TEST( (_1 ->* &my_struct::fooc)(y)() == (y->mem));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo))() == (y->mem));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::fooc))() == (y->mem));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo))() == (y->mem));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::fooc))() == (y->mem));
BOOST_TEST( (_1 ->* &my_struct::foo1)(y)(1) == (y->mem+1));
BOOST_TEST( (_1 ->* &my_struct::foo1c)(y)(1) == (y->mem+1));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo1))(1) == (y->mem+1));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo1c))(1) == (y->mem+1));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo1))(1) == (y->mem+1));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo1c))(1) == (y->mem+1));
BOOST_TEST( (_1 ->* &my_struct::foo2)(y)(1,2) == (y->mem+1+2));
BOOST_TEST( (_1 ->* &my_struct::foo2c)(y)(1,2) == (y->mem+1+2));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo2))(1,2) == (y->mem+1+2));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo2c))(1,2) == (y->mem+1+2));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo2))(1,2) == (y->mem+1+2));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo2c))(1,2) == (y->mem+1+2));
BOOST_TEST( (_1 ->* &my_struct::foo3)(y)(1,2,3) == (y->mem+1+2+3));
BOOST_TEST( (_1 ->* &my_struct::foo3c)(y)(1,2,3) == (y->mem+1+2+3));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo3))(1,2,3) == (y->mem+1+2+3));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo3c))(1,2,3) == (y->mem+1+2+3));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo3))(1,2,3) == (y->mem+1+2+3));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo3c))(1,2,3) == (y->mem+1+2+3));
BOOST_TEST( (_1 ->* &my_struct::foo4)(y)(1,2,3,4) == (y->mem+1+2+3+4));
BOOST_TEST( (_1 ->* &my_struct::foo4c)(y)(1,2,3,4) == (y->mem+1+2+3+4));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo4))(1,2,3,4) == (y->mem+1+2+3+4));
BOOST_TEST( (y ->* _1)(make_const(&my_struct::foo4c))(1,2,3,4) == (y->mem+1+2+3+4));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo4))(1,2,3,4) == (y->mem+1+2+3+4));
BOOST_TEST( (_1 ->* _2)(y, make_const(&my_struct::foo4c))(1,2,3,4) == (y->mem+1+2+3+4));
// member functions with default values do not work (inherent language issue)
// BOOST_TEST( (_1 ->* &my_struct::foo3default)(y)() == (y->mem+1+2+3));
}
class A {};
class B {};
class C {};
class D {};
// ->* can be overloaded to do anything
bool operator->*(A a, B b) {
return false;
}
bool operator->*(B b, A a) {
return true;
}
// let's provide specializations to take care of the return type deduction.
// Note, that you need to provide all four cases for non-const and const
// or use the plain_return_type_2 template.
namespace boost {
namespace lambda {
template <>
struct return_type_2<other_action<member_pointer_action>, B, A> {
typedef bool type;
};
template<>
struct return_type_2<other_action<member_pointer_action>, const B, A> {
typedef bool type;
};
template<>
struct return_type_2<other_action<member_pointer_action>, B, const A> {
typedef bool type;
};
template<>
struct return_type_2<other_action<member_pointer_action>, const B, const A> {
typedef bool type;
};
} // lambda
} // boost
void test_overloaded_pointer_to_member()
{
A a; B b;
// this won't work, can't deduce the return type
// BOOST_TEST((_1->*_2)(a, b) == false);
// ret<bool> gives the return type
BOOST_TEST(ret<bool>(_1->*_2)(a, b) == false);
BOOST_TEST(ret<bool>(a->*_1)(b) == false);
BOOST_TEST(ret<bool>(_1->*b)(a) == false);
BOOST_TEST((ret<bool>((var(a))->*b))() == false);
BOOST_TEST((ret<bool>((var(a))->*var(b)))() == false);
// this is ok without ret<bool> due to the return_type_2 spcialization above
BOOST_TEST((_1->*_2)(b, a) == true);
BOOST_TEST((b->*_1)(a) == true);
BOOST_TEST((_1->*a)(b) == true);
BOOST_TEST((var(b)->*a)() == true);
return;
}
int test_main(int, char *[]) {
pointer_to_data_member_tests();
pointer_to_member_function_tests();
test_overloaded_pointer_to_member();
return 0;
}

View File

@@ -0,0 +1,384 @@
// operator_tests_simple.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 <vector>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
using namespace boost;
using namespace boost::lambda;
class unary_plus_tester {};
unary_plus_tester operator+(const unary_plus_tester& a) { return a; }
void cout_tests()
{
// standard ostream and istream operators work
// stringstreams etc. do not work:
// ostringstream os;
// os << 1
// This should the derived basic_ostream instance (or a reference to it)
// but now the type deduction returns a reference to ostringstream.
// must be fixed.
using std::cout;
ostringstream os;
int i = 10;
ret<std::ostream&>(os << _1)(i);
ret<std::ostream&>(os << constant("FOO"))();
BOOST_TEST(os.str() == std::string("10FOO"));
// 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);
}
void arithmetic_operators() {
int i = 1; int j = 2; int k = 3;
using namespace std;
using namespace boost::lambda;
BOOST_TEST((_1 + 1)(i)==2);
BOOST_TEST(((_1 + 1) * _2)(i, j)==4);
BOOST_TEST((_1 - 1)(i)==0);
BOOST_TEST((_1 * 2)(j)==4);
BOOST_TEST((_1 / 2)(j)==1);
BOOST_TEST((_1 % 2)(k)==1);
BOOST_TEST((-_1)(i) == -1);
BOOST_TEST((+_1)(i) == 1);
// test that unary plus really does something
unary_plus_tester u;
unary_plus_tester up = (+_1)(u);
}
void bitwise_operators() {
unsigned int ui = 2;
BOOST_TEST((_1 << 1)(ui)==(2 << 1));
BOOST_TEST((_1 >> 1)(ui)==(2 >> 1));
BOOST_TEST((_1 & 1)(ui)==(2 & 1));
BOOST_TEST((_1 | 1)(ui)==(2 | 1));
BOOST_TEST((_1 ^ 1)(ui)==(2 ^ 1));
BOOST_TEST((~_1)(ui)==~2);
}
void comparison_operators() {
int i = 0, j = 1;
BOOST_TEST((_1 < _2)(i, j) == true);
BOOST_TEST((_1 <= _2)(i, j) == true);
BOOST_TEST((_1 == _2)(i, j) == false);
BOOST_TEST((_1 != _2)(i, j) == true);
BOOST_TEST((_1 > _2)(i, j) == false);
BOOST_TEST((_1 >= _2)(i, j) == false);
BOOST_TEST((!(_1 < _2))(i, j) == false);
BOOST_TEST((!(_1 <= _2))(i, j) == false);
BOOST_TEST((!(_1 == _2))(i, j) == true);
BOOST_TEST((!(_1 != _2))(i, j) == false);
BOOST_TEST((!(_1 > _2))(i, j) == true);
BOOST_TEST((!(_1 >= _2))(i, j) == true);
}
void logical_operators() {
bool t = true, f = false;
BOOST_TEST((_1 && _2)(t, t) == true);
BOOST_TEST((_1 && _2)(t, f) == false);
BOOST_TEST((_1 && _2)(f, t) == false);
BOOST_TEST((_1 && _2)(f, f) == false);
BOOST_TEST((_1 || _2)(t, t) == true);
BOOST_TEST((_1 || _2)(t, f) == true);
BOOST_TEST((_1 || _2)(f, t) == true);
BOOST_TEST((_1 || _2)(f, f) == false);
BOOST_TEST((!_1)(t) == false);
BOOST_TEST((!_1)(f) == true);
// test short circuiting
int i=0;
(false && ++_1)(i);
BOOST_TEST(i==0);
i = 0;
(true && ++_1)(i);
BOOST_TEST(i==1);
i = 0;
(false || ++_1)(i);
BOOST_TEST(i==1);
i = 0;
(true || ++_1)(i);
BOOST_TEST(i==0);
i = 0;
}
void unary_incs_and_decs() {
int i = 0;
BOOST_TEST(_1++(i) == 0);
BOOST_TEST(i == 1);
i = 0;
BOOST_TEST(_1--(i) == 0);
BOOST_TEST(i == -1);
i = 0;
BOOST_TEST((++_1)(i) == 1);
BOOST_TEST(i == 1);
i = 0;
BOOST_TEST((--_1)(i) == -1);
BOOST_TEST(i == -1);
i = 0;
// the result of prefix -- and ++ are lvalues
(++_1)(i) = 10;
BOOST_TEST(i==10);
i = 0;
(--_1)(i) = 10;
BOOST_TEST(i==10);
i = 0;
}
void compound_operators() {
int i = 1;
// normal variable as the left operand
(i += _1)(make_const(1));
BOOST_TEST(i == 2);
(i -= _1)(make_const(1));
BOOST_TEST(i == 1);
(i *= _1)(make_const(10));
BOOST_TEST(i == 10);
(i /= _1)(make_const(2));
BOOST_TEST(i == 5);
(i %= _1)(make_const(2));
BOOST_TEST(i == 1);
// lambda expression as a left operand
(_1 += 1)(i);
BOOST_TEST(i == 2);
(_1 -= 1)(i);
BOOST_TEST(i == 1);
(_1 *= 10)(i);
BOOST_TEST(i == 10);
(_1 /= 2)(i);
BOOST_TEST(i == 5);
(_1 %= 2)(i);
BOOST_TEST(i == 1);
// shifts
unsigned int ui = 2;
(_1 <<= 1)(ui);
BOOST_TEST(ui==(2 << 1));
ui = 2;
(_1 >>= 1)(ui);
BOOST_TEST(ui==(2 >> 1));
ui = 2;
(ui <<= _1)(make_const(1));
BOOST_TEST(ui==(2 << 1));
ui = 2;
(ui >>= _1)(make_const(1));
BOOST_TEST(ui==(2 >> 1));
// and, or, xor
ui = 2;
(_1 &= 1)(ui);
BOOST_TEST(ui==(2 & 1));
ui = 2;
(_1 |= 1)(ui);
BOOST_TEST(ui==(2 | 1));
ui = 2;
(_1 ^= 1)(ui);
BOOST_TEST(ui==(2 ^ 1));
ui = 2;
(ui &= _1)(make_const(1));
BOOST_TEST(ui==(2 & 1));
ui = 2;
(ui |= _1)(make_const(1));
BOOST_TEST(ui==(2 | 1));
ui = 2;
(ui ^= _1)(make_const(1));
BOOST_TEST(ui==(2 ^ 1));
}
void assignment_and_subscript() {
// assignment and subscript need to be defined as member functions.
// Hence, if you wish to use a normal variable as the left hand argument,
// you must wrap it with var to turn it into a lambda expression
using std::string;
string s;
(_1 = "one")(s);
BOOST_TEST(s == string("one"));
(var(s) = "two")();
BOOST_TEST(s == string("two"));
BOOST_TEST((var(s)[_1])(make_const(2)) == 'o');
BOOST_TEST((_1[2])(s) == 'o');
BOOST_TEST((_1[_2])(s, make_const(2)) == 'o');
// subscript returns lvalue
(var(s)[_1])(make_const(1)) = 'o';
BOOST_TEST(s == "too");
(_1[1])(s) = 'a';
BOOST_TEST(s == "tao");
(_1[_2])(s, make_const(0)) = 'm';
BOOST_TEST(s == "mao");
// TODO: tests for vector, set, map, multimap
}
class A {};
void address_of_and_dereference() {
A a; int i = 42;
BOOST_TEST((&_1)(a) == &a);
BOOST_TEST((*&_1)(i) == 42);
std::vector<int> vi; vi.push_back(1);
std::vector<int>::iterator it = vi.begin();
(*_1 = 7)(it);
BOOST_TEST(vi[0] == 7);
// TODO: Add tests for more complex iterator types
}
void comma() {
int i = 100;
BOOST_TEST((_1 = 10, 2 * _1)(i) == 20);
// TODO: that the return type is the exact type of the right argument
// (that r/l valueness is preserved)
}
void pointer_arithmetic() {
int ia[4] = { 1, 2, 3, 4 };
int* ip = ia;
int* ia_last = &ia[3];
const int cia[4] = { 1, 2, 3, 4 };
const int* cip = cia;
const int* cia_last = &cia[3];
// non-const array
BOOST_TEST((*(_1 + 1))(ia) == 2);
// non-const pointer
BOOST_TEST((*(_1 + 1))(ip) == 2);
BOOST_TEST((*(_1 - 1))(ia_last) == 3);
// const array
BOOST_TEST((*(_1 + 1))(cia) == 2);
// const pointer
BOOST_TEST((*(_1 + 1))(cip) == 2);
BOOST_TEST((*(_1 - 1))(cia_last) == 3);
// pointer arithmetic should not make non-consts const
(*(_1 + 2))(ia) = 0;
(*(_1 + 3))(ip) = 0;
BOOST_TEST(ia[2] == 0);
BOOST_TEST(ia[3] == 0);
// pointer - pointer
BOOST_TEST((_1 - _2)(ia_last, ia) == 3);
BOOST_TEST((_1 - _2)(cia_last, cia) == 3);
BOOST_TEST((ia_last - _1)(ia) == 3);
BOOST_TEST((cia_last - _1)(cia) == 3);
BOOST_TEST((cia_last - _1)(cip) == 3);
}
int test_main(int, char *[]) {
arithmetic_operators();
bitwise_operators();
comparison_operators();
logical_operators();
unary_incs_and_decs();
compound_operators();
assignment_and_subscript();
address_of_and_dereference();
comma();
pointer_arithmetic();
cout_tests();
return 0;
}

View File

@@ -0,0 +1,139 @@
// phoenix_style_control_structures.cpp --------------------------------
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
#include <boost/test/test_tools.hpp> // see "Header Implementation Option"
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/if.hpp"
#include "boost/lambda/loops.hpp"
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <cmath>
#include <cassert>
#include <functional>
using namespace boost::lambda;
using namespace std;
///////////////////////////////////////////////////////////////////////////////
//
// If-else, while, do-while, for tatements
//
///////////////////////////////////////////////////////////////////////////////
int test_main(int, char *[]) {
vector<int> v;
v.clear();
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
v.push_back(8);
v.push_back(9);
v.push_back(10);
int sum = 0;
//////////////////////////////////
for_each(v.begin(), v.end(),
if_(_1 > 3 && _1 <= 8)
[
sum += _1
]
);
BOOST_TEST(sum == 4+5+6+7+8);
int gt = 0, eq = 0, lt = 0;
//////////////////////////////////
for_each(v.begin(), v.end(),
if_(_1 > 5)
[
++var(gt)
]
.else_
[
if_(_1 == 5)
[
++var(eq)
]
.else_
[
++var(lt)
]
]
);
BOOST_TEST(lt==4);
BOOST_TEST(eq==1);
BOOST_TEST(gt==5);
vector<int> t = v;
int counta = 0;
int countb = 0;
//////////////////////////////////
for_each(v.begin(), v.end(),
(
while_(_1--)
[
++var(counta)
],
++var(countb)
)
);
BOOST_TEST(counta == 55);
BOOST_TEST(countb == 10);
v = t;
counta = 0; countb = 0;
//////////////////////////////////
for_each(v.begin(), v.end(),
(
do_
[
++var(counta)
]
.while_(_1--),
++var(countb)
)
);
BOOST_TEST(counta == (2+11)*10/2);
BOOST_TEST(countb == 10);
v = t;
counta = 0; countb = 0;
//////////////////////////////////
int iii;
for_each(v.begin(), v.end(),
(
for_(var(iii) = 0, var(iii) < _1, ++var(iii))
[
++var(counta)
],
++var(countb)
)
);
BOOST_TEST(counta == (1+10)*10/2);
BOOST_TEST(countb == 10);
v = t;
return 0;
}

362
test/switch_construct.cpp Normal file
View File

@@ -0,0 +1,362 @@
// switch_test.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/switch.hpp"
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
// Check that elements 0 -- index are 1, and the rest are 0
bool check(const std::vector<int>& v, int index) {
using namespace boost::lambda;
int counter = 0;
std::vector<int>::const_iterator
result = std::find_if(v.begin(), v.end(),
! if_then_else_return(
var(counter)++ <= index,
_1 == 1,
_1 == 0)
);
return result == v.end();
}
void do_switch_no_defaults_tests() {
using namespace boost::lambda;
int i = 0;
std::vector<int> v,w;
// elements from 0 to 9
std::generate_n(std::back_inserter(v),
10,
var(i)++);
std::fill_n(std::back_inserter(w), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0]))
)
);
BOOST_TEST(check(w, 0));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1]))
)
);
BOOST_TEST(check(w, 1));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2]))
)
);
BOOST_TEST(check(w, 2));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3]))
)
);
BOOST_TEST(check(w, 3));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4]))
)
);
BOOST_TEST(check(w, 4));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5]))
)
);
BOOST_TEST(check(w, 5));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5])),
case_statement<6>(++var(w[6]))
)
);
BOOST_TEST(check(w, 6));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5])),
case_statement<6>(++var(w[6])),
case_statement<7>(++var(w[7]))
)
);
BOOST_TEST(check(w, 7));
std::fill_n(w.begin(), 10, 0);
// ---
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5])),
case_statement<6>(++var(w[6])),
case_statement<7>(++var(w[7])),
case_statement<8>(++var(w[8]))
)
);
BOOST_TEST(check(w, 8));
std::fill_n(w.begin(), 10, 0);
}
void do_switch_yes_defaults_tests() {
using namespace boost::lambda;
int i = 0;
std::vector<int> v,w;
// elements from 0 to 9
std::generate_n(std::back_inserter(v),
10,
var(i)++);
std::fill_n(std::back_inserter(w), 10, 0);
int default_count;
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, -1));
BOOST_TEST(default_count == 10);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 0));
BOOST_TEST(default_count == 9);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 1));
BOOST_TEST(default_count == 8);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 2));
BOOST_TEST(default_count == 7);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 3));
BOOST_TEST(default_count == 6);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 4));
BOOST_TEST(default_count == 5);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 5));
BOOST_TEST(default_count == 4);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5])),
case_statement<6>(++var(w[6])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 6));
BOOST_TEST(default_count == 3);
std::fill_n(w.begin(), 10, 0);
// ---
default_count = 0;
std::for_each(v.begin(), v.end(),
switch_statement(
_1,
case_statement<0>(++var(w[0])),
case_statement<1>(++var(w[1])),
case_statement<2>(++var(w[2])),
case_statement<3>(++var(w[3])),
case_statement<4>(++var(w[4])),
case_statement<5>(++var(w[5])),
case_statement<6>(++var(w[6])),
case_statement<7>(++var(w[7])),
default_statement(++var(default_count))
)
);
BOOST_TEST(check(w, 7));
BOOST_TEST(default_count == 2);
std::fill_n(w.begin(), 10, 0);
}
int test_main(int, char* []) {
do_switch_no_defaults_tests();
do_switch_yes_defaults_tests();
return EXIT_SUCCESS;
}