12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452 |
- <?xml version="1.0" encoding="ISO-Latin-1"?>
- <!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
- "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
- <library name="Lambda" dirname="lambda" id="lambda"
- last-revision="$Date$"
- xmlns:xi="http://www.w3.org/2001/XInclude">
- <libraryinfo>
- <author>
- <firstname>Jaakko</firstname>
- <surname>Järvi</surname>
- <email>jarvi at cs tamu edu</email>
- </author>
- <copyright>
- <year>1999</year>
- <year>2000</year>
- <year>2001</year>
- <year>2002</year>
- <year>2003</year>
- <year>2004</year>
- <holder>Jaakko Järvi</holder>
- <holder>Gary Powell</holder>
- </copyright>
- <legalnotice>
- <para>Use, modification and distribution is subject to the Boost
- Software License, Version 1.0. (See accompanying file
- <filename>LICENSE_1_0.txt</filename> or copy at <ulink
- url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</ulink>)</para>
- </legalnotice>
- <librarypurpose>Define small unnamed function objects at the actual call site, and more</librarypurpose>
- <librarycategory name="category:higher-order"/>
- </libraryinfo>
- <title>Boost.Lambda</title>
- <!-- -->
- <section id="introduction">
- <title>In a nutshell</title>
- <para>
- The Boost Lambda Library (BLL in the sequel) is a C++ template
- library, which implements a form of <emphasis>lambda abstractions</emphasis> for C++.
- The term originates from functional programming and lambda calculus, where a lambda abstraction defines an unnamed function.
- The primary motivation for the BLL is to provide flexible and
- convenient means to define unnamed function objects for STL algorithms.
- In explaining what the library is about, a line of code says more than a thousand words; the
- following line outputs the elements of some STL container
- <literal>a</literal> separated by spaces:
- <programlisting><![CDATA[for_each(a.begin(), a.end(), std::cout << _1 << ' ');]]></programlisting>
- The expression <literal><![CDATA[std::cout << _1 << ' ']]></literal> defines a unary function object.
- The variable <literal>_1</literal> is the parameter of this function, a <emphasis>placeholder</emphasis> for the actual argument.
- Within each iteration of <literal>for_each</literal>, the function is
- called with an element of <literal>a</literal> as the actual argument.
- This actual argument is substituted for the placeholder, and the <quote>body</quote> of the function is evaluated.
- </para>
- <para>The essence of BLL is letting you define small unnamed function objects, such as the one above, directly on the call site of an STL algorithm.
- </para>
- </section>
- <section id="lambda.getting_started">
- <title>Getting Started</title>
- <section>
- <title>Installing the library</title>
-
- <para>
- The library consists of include files only, hence there is no
- installation procedure. The <literal>boost</literal> include directory
- must be on the include path.
- There are a number of include files that give different functionality:
- <!-- TODO: tarkista vielä riippuvuudet-->
- <itemizedlist>
- <listitem><para>
- <filename>lambda/lambda.hpp</filename> defines lambda expressions for different C++
- operators, see <xref linkend="lambda.operator_expressions"/>.
- </para></listitem>
- <listitem><para>
- <filename>lambda/bind.hpp</filename> defines <literal>bind</literal> functions for up to 9 arguments, see <xref linkend="lambda.bind_expressions"/>.</para></listitem>
- <listitem><para>
- <filename>lambda/if.hpp</filename> defines lambda function equivalents for if statements and the conditional operator, see <xref linkend="lambda.lambda_expressions_for_control_structures"/> (includes <filename>lambda.hpp</filename>).
- </para></listitem>
- <listitem><para>
- <filename>lambda/loops.hpp</filename> defines lambda function equivalent for looping constructs, see <xref linkend="lambda.lambda_expressions_for_control_structures"/>.
- </para></listitem>
- <listitem><para>
- <filename>lambda/switch.hpp</filename> defines lambda function equivalent for the switch statement, see <xref linkend="lambda.lambda_expressions_for_control_structures"/>.
- </para></listitem>
- <listitem><para>
- <filename>lambda/construct.hpp</filename> provides tools for writing lambda expressions with constructor, destructor, new and delete invocations, see <xref linkend="lambda.construction_and_destruction"/> (includes <filename>lambda.hpp</filename>).
- </para></listitem>
- <listitem><para>
- <filename>lambda/casts.hpp</filename> provides lambda versions of different casts, as well as <literal>sizeof</literal> and <literal>typeid</literal>, see <xref linkend="lambda.cast_expressions"/>.
- </para></listitem>
- <listitem><para>
- <filename>lambda/exceptions.hpp</filename> gives tools for throwing and catching
- exceptions within lambda functions, <xref linkend="lambda.exceptions"/> (includes
- <filename>lambda.hpp</filename>).
- </para></listitem>
- <listitem><para>
- <filename>lambda/algorithm.hpp</filename> and <filename>lambda/numeric.hpp</filename> (cf. standard <filename>algortihm</filename> and <filename>numeric</filename> headers) allow nested STL algorithm invocations, see <xref linkend="lambda.nested_stl_algorithms"/>.
- </para></listitem>
- </itemizedlist>
- Any other header files in the package are for internal use.
- Additionally, the library depends on two other Boost Libraries, the
- <emphasis>Tuple</emphasis> <xref linkend="cit:boost::tuple"/> and the <emphasis>type_traits</emphasis> <xref linkend="cit:boost::type_traits"/> libraries, and on the <filename>boost/ref.hpp</filename> header.
- </para>
- <para>
- All definitions are placed in the namespace <literal>boost::lambda</literal> and its subnamespaces.
- </para>
- </section>
- <section>
- <title>Conventions used in this document</title>
- <para>In most code examples, we omit the namespace prefixes for names in the <literal moreinfo="none">std</literal> and <literal moreinfo="none">boost::lambda</literal> namespaces.
- Implicit using declarations
- <programlisting>
- using namespace std;
- using namespace boost::lambda;
- </programlisting>
- are assumed to be in effect.
- </para>
- </section>
- </section>
- <section>
- <title>Introduction</title>
- <section>
- <title>Motivation</title>
- <para>The Standard Template Library (STL)
- <xref role="citation" linkend="cit:stepanov:94"/>, now part of the C++ Standard Library <xref role="citation" linkend="cit:c++:98"/>, is a generic container and algorithm library.
- Typically STL algorithms operate on container elements via <emphasis>function objects</emphasis>. These function objects are passed as arguments to the algorithms.
- </para>
- <para>
- Any C++ construct that can be called with the function call syntax
- is a function object.
- The STL contains predefined function objects for some common cases (such as <literal>plus</literal>, <literal>less</literal> and <literal>not1</literal>).
- As an example, one possible implementation for the standard <literal>plus</literal> template is:
- <programlisting>
- <![CDATA[template <class T>
- struct plus : public binary_function<T, T, T> {
- T operator()(const T& i, const T& j) const {
- return i + j;
- }
- };]]>
- </programlisting>
- The base class <literal><![CDATA[binary_function<T, T, T>]]></literal> contains typedefs for the argument and return types of the function object, which are needed to make the function object <emphasis>adaptable</emphasis>.
- </para>
- <para>
- In addition to the basic function object classes, such as the one above,
- the STL contains <emphasis>binder</emphasis> templates for creating a unary function object from an adaptable binary function object by fixing one of the arguments to a constant value.
- For example, instead of having to explicitly write a function object class like:
- <programlisting>
- <![CDATA[class plus_1 {
- int _i;
- public:
- plus_1(const int& i) : _i(i) {}
- int operator()(const int& j) { return _i + j; }
- };]]>
- </programlisting>
- the equivalent functionality can be achieved with the <literal moreinfo="none">plus</literal> template and one of the binder templates (<literal moreinfo="none">bind1st</literal>).
- E.g., the following two expressions create function objects with identical functionalities;
- when invoked, both return the result of adding <literal moreinfo="none">1</literal> to the argument of the function object:
- <programlisting>
- <![CDATA[plus_1(1)
- bind1st(plus<int>(), 1)]]>
- </programlisting>
- The subexpression <literal><![CDATA[plus<int>()]]></literal> in the latter line is a binary function object which computes the sum of two integers, and <literal>bind1st</literal> invokes this function object partially binding the first argument to <literal>1</literal>.
- As an example of using the above function object, the following code adds <literal>1</literal> to each element of some container <literal>a</literal> and outputs the results into the standard output stream <literal>cout</literal>.
- <programlisting>
- <![CDATA[transform(a.begin(), a.end(), ostream_iterator<int>(cout),
- bind1st(plus<int>(), 1));]]>
- </programlisting>
- </para>
- <para>
- To make the binder templates more generally applicable, the STL contains <emphasis>adaptors</emphasis> for making
- pointers or references to functions, and pointers to member functions,
- adaptable.
- Finally, some STL implementations contain function composition operations as
- extensions to the standard <xref linkend="cit:sgi:02"/>.
- </para>
- <para>
- All these tools aim at one goal: to make it possible to specify
- <emphasis>unnamed functions</emphasis> in a call of an STL algorithm,
- in other words, to pass code fragments as an argument to a function.
- However, this goal is attained only partially.
- The simple example above shows that the definition of unnamed functions
- with the standard tools is cumbersome.
- Complex expressions involving functors, adaptors, binders and
- function composition operations tend to be difficult to comprehend.
- In addition to this, there are significant restrictions in applying
- the standard tools. E.g. the standard binders allow only one argument
- of a binary function to be bound; there are no binders for
- 3-ary, 4-ary etc. functions.
- </para>
- <para>
- The Boost Lambda Library provides solutions for the problems described above:
- <itemizedlist>
- <listitem>
- <para>
- Unnamed functions can be created easily with an intuitive syntax.
- The above example can be written as:
- <programlisting>
- <![CDATA[transform(a.begin(), a.end(), ostream_iterator<int>(cout),
- 1 + _1);]]>
- </programlisting>
- or even more intuitively:
- <programlisting>
- <![CDATA[for_each(a.begin(), a.end(), cout << (1 + _1));]]>
- </programlisting>
- </para>
- </listitem>
- <listitem>
- <para>
- Most of the restrictions in argument binding are removed,
- arbitrary arguments of practically any C++ function can be bound.
- </para>
- </listitem>
- <listitem>
- <para>
- Separate function composition operations are not needed,
- as function composition is supported implicitly.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- <section>
- <title>Introduction to lambda expressions</title>
- <para>
- Lambda expression are common in functional programming languages.
- Their syntax varies between languages (and between different forms of lambda calculus), but the basic form of a lambda expressions is:
- <programlisting>
- lambda x<subscript>1</subscript> ... x<subscript>n</subscript>.e
- </programlisting>
- <!-- $\lambda x_1 \cdots x_n . e$ -->
- A lambda expression defines an unnamed function and consists of:
- <itemizedlist>
- <listitem>
- <para>
- the parameters of this function: <literal>x<subscript>1</subscript> ... x<subscript>n</subscript></literal>.
- <!--$x_1 \cdots x_n$-->
- </para>
- </listitem>
- <listitem>
- <para>the expression e which computes the value of the function in terms of the parameters <literal>x<subscript>1</subscript> ... x<subscript>n</subscript></literal>.
- </para>
- </listitem>
- </itemizedlist>
- A simple example of a lambda expression is
- <programlisting>
- lambda x y.x+y
- </programlisting>
- Applying the lambda function means substituting the formal parameters with the actual arguments:
- <programlisting>
- (lambda x y.x+y) 2 3 = 2 + 3 = 5
- </programlisting>
- </para>
- <para>
- In the C++ version of lambda expressions the <literal>lambda x<subscript>1</subscript> ... x<subscript>n</subscript></literal> part is missing and the formal parameters have predefined names.
- In the current version of the library,
- there are three such predefined formal parameters,
- called <emphasis>placeholders</emphasis>:
- <literal>_1</literal>, <literal>_2</literal> and <literal>_3</literal>.
- They refer to the first, second and third argument of the function defined
- by the lambda expression.
-
- For example, the C++ version of the definition
- <programlisting>lambda x y.x+y</programlisting>
- is
- <programlisting>_1 + _2</programlisting>
- </para>
- <para>
- Hence, there is no syntactic keyword for C++ lambda expressions.
- The use of a placeholder as an operand implies that the operator invocation is a lambda expression.
- However, this is true only for operator invocations.
- Lambda expressions containing function calls, control structures, casts etc. require special syntactic constructs.
- Most importantly, function calls need to be wrapped inside a <literal>bind</literal> function.
- As an example, consider the lambda expression:
- <programlisting>lambda x y.foo(x,y)</programlisting>
- Rather than <literal>foo(_1, _2)</literal>, the C++ counterpart for this expression is:
- <programlisting>bind(foo, _1, _2)</programlisting>
- We refer to this type of C++ lambda expressions as <emphasis>bind expressions</emphasis>.
- </para>
- <para>A lambda expression defines a C++ function object, hence function application syntax is like calling any other function object, for instance: <literal>(_1 + _2)(i, j)</literal>.
- </para>
- <section id="lambda.partial_function_application">
- <title>Partial function application</title>
- <para>
- A bind expression is in effect a <emphasis>partial function application</emphasis>.
- In partial function application, some of the arguments of a function are bound to fixed values.
- The result is another function, with possibly fewer arguments.
- When called with the unbound arguments, this new function invokes the original function with the merged argument list of bound and unbound arguments.
- </para>
- <!-- <para>The underlying implementation of the BLL unifies the two types of lambda expressions (bind expressions and lambda expressions consisting of operator calls).
- If operators are regarded as functions, it is easy to see that lambda expressions using operators are partial function applications as well.
- E.g. the lambda expression <literal>_1 + 1</literal> can be seen as syntactic sugar for the pseudo code <literal>bind(operator+, _1, 1)</literal>.
- </para>
- -->
- </section>
- <section id="lambda.terminology">
- <title>Terminology</title>
- <para>
- A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, <emphasis>a functor</emphasis>, when evaluated. We use the name <emphasis>lambda functor</emphasis> to refer to such a function object.
- Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor.
- </para>
- </section>
- </section>
- </section>
- <section id = "lambda.using_library">
- <title>Using the library</title>
- <para>
- The purpose of this section is to introduce the basic functionality of the library.
- There are quite a lot of exceptions and special cases, but discussion of them is postponed until later sections.
- </para>
- <section id = "lambda.introductory_examples">
- <title>Introductory Examples</title>
- <para>
- In this section we give basic examples of using BLL lambda expressions in STL algorithm invocations.
- We start with some simple expressions and work up.
- First, we initialize the elements of a container, say, a <literal>list</literal>, to the value <literal>1</literal>:
- <programlisting>
- <![CDATA[list<int> v(10);
- for_each(v.begin(), v.end(), _1 = 1);]]></programlisting>
- The expression <literal>_1 = 1</literal> creates a lambda functor which assigns the value <literal>1</literal> to every element in <literal>v</literal>.<footnote>
- <para>
- Strictly taken, the C++ standard defines <literal>for_each</literal> as a <emphasis>non-modifying sequence operation</emphasis>, and the function object passed to <literal moreinfo="none">for_each</literal> should not modify its argument.
- The requirements for the arguments of <literal>for_each</literal> are unnecessary strict, since as long as the iterators are <emphasis>mutable</emphasis>, <literal>for_each</literal> accepts a function object that can have side-effects on their argument.
- Nevertheless, it is straightforward to provide another function template with the functionality of<literal>std::for_each</literal> but more fine-grained requirements for its arguments.
- </para>
- </footnote>
- </para>
- <para>
- Next, we create a container of pointers and make them point to the elements in the first container <literal>v</literal>:
- <programlisting>
- <![CDATA[vector<int*> vp(10);
- transform(v.begin(), v.end(), vp.begin(), &_1);]]></programlisting>
- The expression <literal><![CDATA[&_1]]></literal> creates a function object for getting the address of each element in <literal>v</literal>.
- The addresses get assigned to the corresponding elements in <literal>vp</literal>.
- </para>
- <para>
- The next code fragment changes the values in <literal>v</literal>.
- For each element, the function <literal>foo</literal> is called.
- The original value of the element is passed as an argument to <literal>foo</literal>.
- The result of <literal>foo</literal> is assigned back to the element:
- <programlisting>
- <![CDATA[int foo(int);
- for_each(v.begin(), v.end(), _1 = bind(foo, _1));]]></programlisting>
- </para>
- <para>
- The next step is to sort the elements of <literal>vp</literal>:
-
- <programlisting>sort(vp.begin(), vp.end(), *_1 > *_2);</programlisting>
- In this call to <literal>sort</literal>, we are sorting the elements by their contents in descending order.
- </para>
- <para>
- Finally, the following <literal>for_each</literal> call outputs the sorted content of <literal>vp</literal> separated by line breaks:
- <programlisting>
- <![CDATA[for_each(vp.begin(), vp.end(), cout << *_1 << '\n');]]>
- </programlisting>
- Note that a normal (non-lambda) expression as subexpression of a lambda expression is evaluated immediately.
- This may cause surprises.
- For instance, if the previous example is rewritten as
- <programlisting>
- <![CDATA[for_each(vp.begin(), vp.end(), cout << '\n' << *_1);]]>
- </programlisting>
- the subexpression <literal><![CDATA[cout << '\n']]></literal> is evaluated immediately and the effect is to output a single line break, followed by the elements of <literal>vp</literal>.
- The BLL provides functions <literal>constant</literal> and <literal>var</literal> to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions:
- <programlisting>
- <![CDATA[for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);]]>
- </programlisting>
- These functions are described more thoroughly in <xref linkend="lambda.delaying_constants_and_variables"/>
- </para>
- </section>
- <section id="lambda.parameter_and_return_types">
- <title>Parameter and return types of lambda functors</title>
- <para>
- During the invocation of a lambda functor, the actual arguments are substituted for the placeholders.
- The placeholders do not dictate the type of these actual arguments.
- The basic rule is that a lambda function can be called with arguments of any types, as long as the lambda expression with substitutions performed is a valid C++ expression.
- As an example, the expression
- <literal>_1 + _2</literal> creates a binary lambda functor.
- It can be called with two objects of any types <literal>A</literal> and <literal>B</literal> for which <literal>operator+(A,B)</literal> is defined (and for which BLL knows the return type of the operator, see below).
- </para>
- <para>
- C++ lacks a mechanism to query a type of an expression.
- However, this precise mechanism is crucial for the implementation of C++ lambda expressions.
- Consequently, BLL includes a somewhat complex type deduction system which uses a set of traits classes for deducing the resulting type of lambda functions.
- It handles expressions where the operands are of built-in types and many of the expressions with operands of standard library types.
- Many of the user defined types are covered as well, particularly if the user defined operators obey normal conventions in defining the return types.
- </para>
- <!-- TODO: move this forward, and just refer to it. -->
- <para>
- There are, however, cases when the return type cannot be deduced. For example, suppose you have defined:
- <programlisting>C operator+(A, B);</programlisting>
- The following lambda function invocation fails, since the return type cannot be deduced:
- <programlisting>A a; B b; (_1 + _2)(a, b);</programlisting>
- </para>
- <para>
- There are two alternative solutions to this.
- The first is to extend the BLL type deduction system to cover your own types (see <xref linkend="lambda.extending"/>).
- The second is to use a special lambda expression (<literal>ret</literal>) which defines the return type in place (see <xref linkend = "lambda.overriding_deduced_return_type"/>):
- <programlisting><![CDATA[A a; B b; ret<C>(_1 + _2)(a, b);]]></programlisting>
- </para>
- <para>
- For bind expressions, the return type can be defined as a template argument of the bind function as well:
- <programlisting><![CDATA[bind<int>(foo, _1, _2);]]></programlisting>
- <!--
- A rare case, where the <literal><![CDATA[ret<type>(bind(...))]]></literal> syntax does not work, but
- <literal><![CDATA[bind<type>(...)]]></literal> does, is explained in <xref linkend="lambda.nullary_functors_and_ret"/>.
- -->
- </para>
- </section>
- <section id="lambda.actual_arguments_to_lambda_functors">
- <title>About actual arguments to lambda functors</title>
- <!-- <para><emphasis>This section is no longer (or currently) relevant;
- acual arguments can be non-const rvalues.
- The section can, however, become relevant again, if in the future BLL will support
- lambda functors with higher arities than 3.</emphasis></para> -->
- <para>A general restriction for the actual arguments is that they cannot be non-const rvalues.
- For example:
- <programlisting>
- int i = 1; int j = 2;
- (_1 + _2)(i, j); // ok
- (_1 + _2)(1, 2); // error (!)
- </programlisting>
- This restriction is not as bad as it may look.
- Since the lambda functors are most often called inside STL-algorithms,
- the arguments originate from dereferencing iterators and the dereferencing operators seldom return rvalues.
- And for the cases where they do, there are workarounds discussed in
- <xref linkend="lambda.rvalues_as_actual_arguments"/>.
- </para>
- </section>
- <section id="lambda.storing_bound_arguments">
- <title>Storing bound arguments in lambda functions</title>
-
- <para>
- By default, temporary const copies of the bound arguments are stored
- in the lambda functor.
- This means that the value of a bound argument is fixed at the time of the
- creation of the lambda function and remains constant during the lifetime
- of the lambda function object.
- For example:
- <programlisting>
- int i = 1;
- (_1 = 2, _1 + i)(i);
- </programlisting>
- The comma operator is overloaded to combine lambda expressions into a sequence;
- the resulting unary lambda functor first assigns 2 to its argument,
- then adds the value of <literal>i</literal> to it.
- The value of the expression in the last line is 3, not 4.
- In other words, the lambda expression that is created is
- <literal>lambda x.(x = 2, x + 1)</literal> rather than
- <literal>lambda x.(x = 2, x + i)</literal>.
-
- </para>
- <para>
- As said, this is the default behavior for which there are exceptions.
- The exact rules are as follows:
- <itemizedlist>
- <listitem>
- <para>
- The programmer can control the storing mechanism with <literal>ref</literal>
- and <literal>cref</literal> wrappers <xref linkend="cit:boost::ref"/>.
- Wrapping an argument with <literal>ref</literal>, or <literal>cref</literal>,
- instructs the library to store the argument as a reference,
- or as a reference to const respectively.
- For example, if we rewrite the previous example and wrap the variable
- <literal>i</literal> with <literal>ref</literal>,
- we are creating the lambda expression <literal>lambda x.(x = 2, x + i)</literal>
- and the value of the expression in the last line will be 4:
- <programlisting>
- i = 1;
- (_1 = 2, _1 + ref(i))(i);
- </programlisting>
- Note that <literal>ref</literal> and <literal>cref</literal> are different
- from <literal>var</literal> and <literal>constant</literal>.
- While the latter ones create lambda functors, the former do not.
- For example:
- <programlisting>
- int i;
- var(i) = 1; // ok
- ref(i) = 1; // not ok, ref(i) is not a lambda functor
- </programlisting>
- The functions <literal>ref</literal> and <literal>cref</literal> mostly
- exist for historical reasons,
- and <literal>ref</literal> can always
- be replaced with <literal>var</literal>, and <literal>cref</literal> with
- <literal>constant_ref</literal>.
- See <xref linkend="lambda.delaying_constants_and_variables"/> for details.
- The <literal>ref</literal> and <literal>cref</literal> functions are
- general purpose utility functions in Boost, and hence defined directly
- in the <literal moreinfo="none">boost</literal> namespace.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Array types cannot be copied, they are thus stored as const reference by default.
- </para>
- </listitem>
- <listitem>
- <para>
- For some expressions it makes more sense to store the arguments as references.
- For example, the obvious intention of the lambda expression
- <literal>i += _1</literal> is that calls to the lambda functor affect the
- value of the variable <literal>i</literal>,
- rather than some temporary copy of it.
- As another example, the streaming operators take their leftmost argument
- as non-const references.
- The exact rules are:
- <itemizedlist>
- <listitem>
- <para>The left argument of compound assignment operators (<literal>+=</literal>, <literal>*=</literal>, etc.) are stored as references to non-const.</para>
- </listitem>
- <listitem>
- <para>If the left argument of <literal><![CDATA[<<]]></literal> or <literal><![CDATA[>>]]></literal> operator is derived from an instantiation of <literal>basic_ostream</literal> or respectively from <literal>basic_istream</literal>, the argument is stored as a reference to non-const.
- For all other types, the argument is stored as a copy.
- </para>
- </listitem>
- <listitem>
- <para>
- In pointer arithmetic expressions, non-const array types are stored as non-const references.
- This is to prevent pointer arithmetic making non-const arrays const.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- </section>
- <section id="lambda.le_in_details">
- <title>Lambda expressions in details</title>
- <para>
- This section describes different categories of lambda expressions in details.
- We devote a separate section for each of the possible forms of a lambda expression.
- </para>
- <section id="lambda.placeholders">
- <title>Placeholders</title>
- <para>
- The BLL defines three placeholder types: <literal>placeholder1_type</literal>, <literal>placeholder2_type</literal> and <literal>placeholder3_type</literal>.
- BLL has a predefined placeholder variable for each placeholder type: <literal>_1</literal>, <literal>_2</literal> and <literal>_3</literal>.
- However, the user is not forced to use these placeholders.
- It is easy to define placeholders with alternative names.
- This is done by defining new variables of placeholder types.
- For example:
- <programlisting>boost::lambda::placeholder1_type X;
- boost::lambda::placeholder2_type Y;
- boost::lambda::placeholder3_type Z;
- </programlisting>
- With these variables defined, <literal>X += Y * Z</literal> is equivalent to <literal>_1 += _2 * _3</literal>.
- </para>
- <para>
- The use of placeholders in the lambda expression determines whether the resulting function is nullary, unary, binary or 3-ary.
- The highest placeholder index is decisive. For example:
- <programlisting>
- _1 + 5 // unary
- _1 * _1 + _1 // unary
- _1 + _2 // binary
- bind(f, _1, _2, _3) // 3-ary
- _3 + 10 // 3-ary
- </programlisting>
- Note that the last line creates a 3-ary function, which adds <literal>10</literal> to its <emphasis>third</emphasis> argument.
- The first two arguments are discarded.
- Furthermore, lambda functors only have a minimum arity.
- One can always provide more arguments (up the number of supported placeholders)
- that is really needed.
- The remaining arguments are just discarded.
- For example:
- <programlisting>
- int i, j, k;
- _1(i, j, k) // returns i, discards j and k
- (_2 + _2)(i, j, k) // returns j+j, discards i and k
- </programlisting>
- See
- <xref linkend="lambda.why_weak_arity"/> for the design rationale behind this
- functionality.
- </para>
- <para>
- In addition to these three placeholder types, there is also a fourth placeholder type <literal>placeholderE_type</literal>.
- The use of this placeholder is defined in <xref linkend="lambda.exceptions"/> describing exception handling in lambda expressions.
- </para>
- <para>When an actual argument is supplied for a placeholder, the parameter passing mode is always by reference.
- This means that any side-effects to the placeholder are reflected to the actual argument.
- For example:
- <programlisting>
- <![CDATA[int i = 1;
- (_1 += 2)(i); // i is now 3
- (++_1, cout << _1)(i) // i is now 4, outputs 4]]>
- </programlisting>
- </para>
- </section>
- <section id="lambda.operator_expressions">
- <title>Operator expressions</title>
- <para>
- The basic rule is that any C++ operator invocation with at least one argument being a lambda expression is itself a lambda expression.
- Almost all overloadable operators are supported.
- For example, the following is a valid lambda expression:
- <programlisting><![CDATA[cout << _1, _2[_3] = _1 && false]]></programlisting>
- </para>
- <para>
- However, there are some restrictions that originate from the C++ operator overloading rules, and some special cases.
- </para>
- <section>
- <title>Operators that cannot be overloaded</title>
- <para>
- Some operators cannot be overloaded at all (<literal>::</literal>, <literal>.</literal>, <literal>.*</literal>).
- For some operators, the requirements on return types prevent them to be overloaded to create lambda functors.
- These operators are <literal>->.</literal>, <literal>-></literal>, <literal>new</literal>, <literal>new[]</literal>, <literal>delete</literal>, <literal>delete[]</literal> and <literal>?:</literal> (the conditional operator).
- </para>
- </section>
- <section id="lambda.assignment_and_subscript">
- <title>Assignment and subscript operators</title>
- <para>
- These operators must be implemented as class members.
- Consequently, the left operand must be a lambda expression. For example:
- <programlisting>
- int i;
- _1 = i; // ok
- i = _1; // not ok. i is not a lambda expression
- </programlisting>
- There is a simple solution around this limitation, described in <xref linkend="lambda.delaying_constants_and_variables"/>.
- In short,
- the left hand argument can be explicitly turned into a lambda functor by wrapping it with a special <literal>var</literal> function:
- <programlisting>
- var(i) = _1; // ok
- </programlisting>
- </para>
- </section>
- <section id="lambda.logical_operators">
- <title>Logical operators</title>
- <para>
- Logical operators obey the short-circuiting evaluation rules. For example, in the following code, <literal>i</literal> is never incremented:
- <programlisting>
- bool flag = true; int i = 0;
- (_1 || ++_2)(flag, i);
- </programlisting>
- </para>
- </section>
- <section id="lambda.comma_operator">
- <title>Comma operator</title>
- <para>
- Comma operator is the <quote>statement separator</quote> in lambda expressions.
- Since comma is also the separator between arguments in a function call, extra parenthesis are sometimes needed:
- <programlisting>
- for_each(a.begin(), a.end(), (++_1, cout << _1));
- </programlisting>
- Without the extra parenthesis around <literal>++_1, cout << _1</literal>, the code would be interpreted as an attempt to call <literal>for_each</literal> with four arguments.
- </para>
- <para>
- The lambda functor created by the comma operator adheres to the C++ rule of always evaluating the left operand before the right one.
- In the above example, each element of <literal>a</literal> is first incremented, then written to the stream.
- </para>
- </section>
- <section id="lambda.function_call_operator">
- <title>Function call operator</title>
- <para>
- The function call operators have the effect of evaluating the lambda
- functor.
- Calls with too few arguments lead to a compile time error.
- </para>
- </section>
- <section id="lambda.member_pointer_operator">
- <title>Member pointer operator</title>
- <para>
- The member pointer operator <literal>operator->*</literal> can be overloaded freely.
- Hence, for user defined types, member pointer operator is no special case.
- The built-in meaning, however, is a somewhat more complicated case.
- The built-in member pointer operator is applied if the left argument is a pointer to an object of some class <literal>A</literal>, and the right hand argument is a pointer to a member of <literal>A</literal>, or a pointer to a member of a class from which <literal>A</literal> derives.
- We must separate two cases:
- <itemizedlist>
- <listitem>
- <para>The right hand argument is a pointer to a data member.
- In this case the lambda functor simply performs the argument substitution and calls the built-in member pointer operator, which returns a reference to the member pointed to.
- For example:
- <programlisting>
- <![CDATA[struct A { int d; };
- A* a = new A();
- ...
- (a ->* &A::d); // returns a reference to a->d
- (_1 ->* &A::d)(a); // likewise]]>
- </programlisting>
- </para>
- </listitem>
- <listitem>
- <para>
- The right hand argument is a pointer to a member function.
- For a built-in call like this, the result is kind of a delayed member function call.
- Such an expression must be followed by a function argument list, with which the delayed member function call is performed.
- For example:
- <programlisting>
- <![CDATA[struct B { int foo(int); };
- B* b = new B();
- ...
- (b ->* &B::foo) // returns a delayed call to b->foo
- // a function argument list must follow
- (b ->* &B::foo)(1) // ok, calls b->foo(1)
- (_1 ->* &B::foo)(b); // returns a delayed call to b->foo,
- // no effect as such
- (_1 ->* &B::foo)(b)(1); // calls b->foo(1)]]>
- </programlisting>
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- </section>
- <section id="lambda.bind_expressions">
- <title>Bind expressions</title>
- <para>
- Bind expressions can have two forms:
- <!-- TODO: shouldn't really be emphasis, but a variable or something-->
- <programlisting>
- bind(<parameter>target-function</parameter>, <parameter>bind-argument-list</parameter>)
- bind(<parameter>target-member-function</parameter>, <parameter>object-argument</parameter>, <parameter>bind-argument-list</parameter>)
- </programlisting>
- A bind expression delays the call of a function.
- If this <emphasis>target function</emphasis> is <emphasis>n</emphasis>-ary, then the <literal><emphasis>bind-argument-list</emphasis></literal> must contain <emphasis>n</emphasis> arguments as well.
- In the current version of the BLL, <inlineequation>0 <= n <= 9</inlineequation> must hold.
- For member functions, the number of arguments must be at most <inlineequation>8</inlineequation>, as the object argument takes one argument position.
- Basically, the
- <emphasis><literal>bind-argument-list</literal></emphasis> must be a valid argument list for the target function, except that any argument can be replaced with a placeholder, or more generally, with a lambda expression.
- Note that also the target function can be a lambda expression.
- The result of a bind expression is either a nullary, unary, binary or 3-ary function object depending on the use of placeholders in the <emphasis><literal>bind-argument-list</literal></emphasis> (see <xref linkend="lambda.placeholders"/>).
- </para>
- <para>
- The return type of the lambda functor created by the bind expression can be given as an explicitly specified template parameter, as in the following example:
- <programlisting>
- bind<<emphasis>RET</emphasis>>(<emphasis>target-function</emphasis>, <emphasis>bind-argument-list</emphasis>)
- </programlisting>
- This is only necessary if the return type of the target function cannot be deduced.
- </para>
- <para>
- The following sections describe the different types of bind expressions.
- </para>
- <section id="lambda.function_pointers_as_targets">
- <title>Function pointers or references as targets</title>
- <para>The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example:
- <programlisting>
- <![CDATA[X foo(A, B, C); A a; B b; C c;
- bind(foo, _1, _2, c)(a, b);
- bind(&foo, _1, _2, c)(a, b);
- bind(_1, a, b, c)(foo);]]>
- </programlisting>
-
- The return type deduction always succeeds with this type of bind expressions.
- </para>
- <para>
- Note, that in C++ it is possible to take the address of an overloaded function only if the address is assigned to, or used as an initializer of, a variable, the type of which solves the amibiguity, or if an explicit cast expression is used.
- This means that overloaded functions cannot be used in bind expressions directly, e.g.:
- <programlisting>
- <![CDATA[void foo(int);
- void foo(float);
- int i;
- ...
- bind(&foo, _1)(i); // error
- ...
- void (*pf1)(int) = &foo;
- bind(pf1, _1)(i); // ok
- bind(static_cast<void(*)(int)>(&foo), _1)(i); // ok]]>
- </programlisting>
- </para>
- </section>
- <section id="member_functions_as_targets">
- <title>Member functions as targets</title>
- <para>
- The syntax for using pointers to member function in bind expression is:
- <programlisting>
- bind(<parameter>target-member-function</parameter>, <parameter>object-argument</parameter>, <parameter>bind-argument-list</parameter>)
- </programlisting>
- The object argument can be a reference or pointer to the object, the BLL supports both cases with a uniform interface:
- <programlisting>
- <![CDATA[bool A::foo(int) const;
- A a;
- vector<int> ints;
- ...
- find_if(ints.begin(), ints.end(), bind(&A::foo, a, _1));
- find_if(ints.begin(), ints.end(), bind(&A::foo, &a, _1));]]>
- </programlisting>
- Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference:
- <programlisting>
- <![CDATA[bool A::foo(int);
- list<A> refs;
- list<A*> pointers;
- ...
- find_if(refs.begin(), refs.end(), bind(&A::foo, _1, 1));
- find_if(pointers.begin(), pointers.end(), bind(&A::foo, _1, 1));]]>
- </programlisting>
- </para>
- <!--%The exact rules for the object argument (whether it is bound, or supplied in the lambda function invoction) are as follows:
- %If the target function is a pointer to a member function of some class \snip{A}, then the object argument must be an expression of type \snip{B}, where either
- %\begin{itemize}
- %\item \snip{B} = \snip{A} or there is an implicit conversion from \snip{B} to \snip{A}.
- %\item \snip{B} = \snip{A*}.
- %\item \snip{B} = \snip{C*}, where \snip{C} is any class derived form \snip{A}.
- %\end{itemize}
- %For example:
- %\begin{alltt}
- %struct A \{
- % virtual void f();
- % void fc() const;
- %\};
- %
- %struct B : public A \{
- % virtual void f();
- %\};
- %
- %struct C \{
- % operator A const() \{ return A(); \}
- %\};
- %
- % A a; B b; C c;
- % ...
- % bind(&A::f, a)();
- % bind(&A::f, b)(); // calls B::f
- % bind(&A::fc, c)();
- %
- % bind(&A::f, &a)();
- % bind(&A::f, &b)(); // calls B::f
- % bind(&A::f, &c)(); // error: no conversion from C* \(\rightarrow\) A,
- %\end{alltt}
- -->
- <para>
- Even though the interfaces are the same, there are important semantic differences between using a pointer or a reference as the object argument.
- The differences stem from the way <literal>bind</literal>-functions take their parameters, and how the bound parameters are stored within the lambda functor.
- The object argument has the same parameter passing and storing mechanism as any other bind argument slot (see <xref linkend="lambda.storing_bound_arguments"/>); it is passed as a const reference and stored as a const copy in the lambda functor.
- This creates some asymmetry between the lambda functor and the original member function, and between seemingly similar lambda functors. For example:
- <programlisting>
- class A {
- int i; mutable int j;
- public:
- A(int ii, int jj) : i(ii), j(jj) {};
- void set_i(int x) { i = x; };
- void set_j(int x) const { j = x; };
- };
- </programlisting>
- When a pointer is used, the behavior is what the programmer might expect:
- <programlisting>
- <![CDATA[A a(0,0); int k = 1;
- bind(&A::set_i, &a, _1)(k); // a.i == 1
- bind(&A::set_j, &a, _1)(k); // a.j == 1]]>
- </programlisting>
- Even though a const copy of the object argument is stored, the original object <literal>a</literal> is still modified.
- This is since the object argument is a pointer, and the pointer is copied, not the object it points to.
- When we use a reference, the behaviour is different:
- <programlisting>
- <![CDATA[A a(0,0); int k = 1;
- bind(&A::set_i, a, _1)(k); // error; a const copy of a is stored.
- // Cannot call a non-const function set_i
- bind(&A::set_j, a, _1)(k); // a.j == 0, as a copy of a is modified]]>
- </programlisting>
- </para>
- <para>
- To prevent the copying from taking place, one can use the <literal>ref</literal> or <literal>cref</literal> wrappers (<literal>var</literal> and <literal>constant_ref</literal> would do as well):
- <programlisting>
- <![CDATA[bind(&A::set_i, ref(a), _1)(k); // a.j == 1
- bind(&A::set_j, cref(a), _1)(k); // a.j == 1]]>
- </programlisting>
- </para>
- <para>Note that the preceding discussion is relevant only for bound arguments.
- If the object argument is unbound, the parameter passing mode is always by reference.
- Hence, the argument <literal>a</literal> is not copied in the calls to the two lambda functors below:
- <programlisting>
- <![CDATA[A a(0,0);
- bind(&A::set_i, _1, 1)(a); // a.i == 1
- bind(&A::set_j, _1, 1)(a); // a.j == 1]]>
- </programlisting>
- </para>
- </section>
- <section id="lambda.members_variables_as_targets">
- <title>Member variables as targets</title>
- <para>
- A pointer to a member variable is not really a function, but
- the first argument to the <literal>bind</literal> function can nevertheless
- be a pointer to a member variable.
- Invoking such a bind expression returns a reference to the data member.
- For example:
- <programlisting>
- <![CDATA[struct A { int data; };
- A a;
- bind(&A::data, _1)(a) = 1; // a.data == 1]]>
- </programlisting>
- The cv-qualifiers of the object whose member is accessed are respected.
- For example, the following tries to write into a const location:
- <programlisting>
- <![CDATA[const A ca = a;
- bind(&A::data, _1)(ca) = 1; // error]]>
- </programlisting>
- </para>
- </section>
- <section id="lambda.function_objects_as_targets">
- <title>Function objects as targets</title>
- <para>
- Function objects, that is, class objects which have the function call
- operator defined, can be used as target functions.
- In general, BLL cannot deduce the return type of an arbitrary function object.
- However, there are two methods for giving BLL this capability for a certain
- function object class.
- </para>
- <simplesect>
- <title>The result_type typedef</title>
- <para>
- The BLL supports the standard library convention of declaring the return type
- of a function object with a member typedef named <literal>result_type</literal> in the
- function object class.
- Here is a simple example:
- <programlisting>
- <![CDATA[struct A {
- typedef B result_type;
- B operator()(X, Y, Z);
- };]]>
- </programlisting>
- If a function object does not define a <literal>result_type</literal> typedef,
- the method described below (<literal>sig</literal> template)
- is attempted to resolve the return type of the
- function object. If a function object defines both <literal>result_type</literal>
- and <literal>sig</literal>, <literal>result_type</literal> takes precedence.
- </para>
- </simplesect>
- <simplesect>
- <title>The sig template</title>
- <para>
- Another mechanism that make BLL aware of the return type(s) of a function object is defining
- member template struct
- <literal><![CDATA[sig<Args>]]></literal> with a typedef
- <literal>type</literal> that specifies the return type.
- Here is a simple example:
- <programlisting>
- <![CDATA[struct A {
- template <class Args> struct sig { typedef B type; }
- B operator()(X, Y, Z);
- };]]>
- </programlisting>
- The template argument <literal>Args</literal> is a
- <literal>tuple</literal> (or more precisely a <literal>cons</literal> list)
- type <xref linkend="cit:boost::tuple"/>, where the first element
- is the function
- object type itself, and the remaining elements are the types of
- the arguments, with which the function object is being called.
- This may seem overly complex compared to defining the <literal>result_type</literal> typedef.
- Howver, there are two significant restrictions with using just a simple
- typedef to express the return type:
- <orderedlist>
- <listitem>
- <para>
- If the function object defines several function call operators, there is no way to specify different result types for them.
- </para>
- </listitem>
- <listitem>
- <para>
- If the function call operator is a template, the result type may
- depend on the template parameters.
- Hence, the typedef ought to be a template too, which the C++ language
- does not support.
- </para>
- </listitem>
- </orderedlist>
- The following code shows an example, where the return type depends on the type
- of one of the arguments, and how that dependency can be expressed with the
- <literal>sig</literal> template:
- <programlisting>
- <![CDATA[struct A {
- // the return type equals the third argument type:
- template<class T1, class T2, class T3>
- T3 operator()(const T1& t1, const T2& t2, const T3& t3) const;
- template <class Args>
- class sig {
- // get the third argument type (4th element)
- typedef typename
- boost::tuples::element<3, Args>::type T3;
- public:
- typedef typename
- boost::remove_cv<T3>::type type;
- };
- };]]>
- </programlisting>
- The elements of the <literal>Args</literal> tuple are always
- non-reference types.
- Moreover, the element types can have a const or volatile qualifier
- (jointly referred to as <emphasis>cv-qualifiers</emphasis>), or both.
- This is since the cv-qualifiers in the arguments can affect the return type.
- The reason for including the potentially cv-qualified function object
- type itself into the <literal>Args</literal> tuple, is that the function
- object class can contain both const and non-const (or volatile, even
- const volatile) function call operators, and they can each have a different
- return type.
- </para>
- <para>
- The <literal>sig</literal> template can be seen as a
- <emphasis>meta-function</emphasis> that maps the argument type tuple to
- the result type of the call made with arguments of the types in the tuple.
- As the example above demonstrates, the template can end up being somewhat
- complex.
- Typical tasks to be performed are the extraction of the relevant types
- from the tuple, removing cv-qualifiers etc.
- See the Boost type_traits <xref linkend="cit:boost::type_traits"/> and
- Tuple <xref linkend="cit:boost::type_traits"/> libraries
- for tools that can aid in these tasks.
- The <literal>sig</literal> templates are a refined version of a similar
- mechanism first introduced in the FC++ library
- <xref linkend="cit:fc++"/>.
- </para>
- </simplesect>
- </section>
- </section>
- <section id="lambda.overriding_deduced_return_type">
- <title>Overriding the deduced return type</title>
- <para>
- The return type deduction system may not be able to deduce the return types of some user defined operators or bind expressions with class objects.
- <!-- (see the example in <xref linkend="lambda.parameter_and_return_types"/>).-->
- A special lambda expression type is provided for stating the return type explicitly and overriding the deduction system.
- To state that the return type of the lambda functor defined by the lambda expression <literal>e</literal> is <literal>T</literal>, you can write:
- <programlisting><![CDATA[ret<T>(e);]]></programlisting>
- The effect is that the return type deduction is not performed for the lambda expression <literal>e</literal> at all, but instead, <literal>T</literal> is used as the return type.
- Obviously <literal>T</literal> cannot be an arbitrary type, the true result of the lambda functor must be implicitly convertible to <literal>T</literal>.
- For example:
- <programlisting>
- <![CDATA[A a; B b;
- C operator+(A, B);
- int operator*(A, B);
- ...
- ret<D>(_1 + _2)(a, b); // error (C cannot be converted to D)
- ret<C>(_1 + _2)(a, b); // ok
- ret<float>(_1 * _2)(a, b); // ok (int can be converted to float)
- ...
- struct X {
- Y operator(int)();
- };
- ...
- X x; int i;
- bind(x, _1)(i); // error, return type cannot be deduced
- ret<Y>(bind(x, _1))(i); // ok]]>
- </programlisting>
- For bind expressions, there is a short-hand notation that can be used instead of <literal>ret</literal>.
- The last line could alternatively be written as:
- <programlisting><![CDATA[bind<Z>(x, _1)(i);]]></programlisting>
- This feature is modeled after the Boost Bind library <xref linkend="cit:boost::bind"/>.
- </para>
- <para>Note that within nested lambda expressions,
- the <literal>ret</literal> must be used at each subexpression where
- the deduction would otherwise fail.
- For example:
- <programlisting>
- <![CDATA[A a; B b;
- C operator+(A, B); D operator-(C);
- ...
- ret<D>( - (_1 + _2))(a, b); // error
- ret<D>( - ret<C>(_1 + _2))(a, b); // ok]]>
- </programlisting>
- </para>
- <para>If you find yourself using <literal>ret</literal> repeatedly with the same types, it is worth while extending the return type deduction (see <xref linkend="lambda.extending"/>).
- </para>
- <section id="lambda.nullary_functors_and_ret">
- <title>Nullary lambda functors and ret</title>
- <para>
- As stated above, the effect of <literal>ret</literal> is to prevent the return type deduction to be performed.
- However, there is an exception.
- Due to the way the C++ template instantiation works, the compiler is always forced to instantiate the return type deduction templates for zero-argument lambda functors.
- This introduces a slight problem with <literal>ret</literal>, best described with an example:
- <programlisting>
- <![CDATA[struct F { int operator()(int i) const; };
- F f;
- ...
- bind(f, _1); // fails, cannot deduce the return type
- ret<int>(bind(f, _1)); // ok
- ...
- bind(f, 1); // fails, cannot deduce the return type
- ret<int>(bind(f, 1)); // fails as well!]]>
- </programlisting>
- The BLL cannot deduce the return types of the above bind calls, as <literal>F</literal> does not define the typedef <literal>result_type</literal>.
- One would expect <literal>ret</literal> to fix this, but for the nullary lambda functor that results from a bind expression (last line above) this does not work.
- The return type deduction templates are instantiated, even though it would not be necessary and the result is a compilation error.
- </para>
- <para>The solution to this is not to use the <literal>ret</literal> function, but rather define the return type as an explicitly specified template parameter in the <literal>bind</literal> call:
- <programlisting>
- <![CDATA[bind<int>(f, 1); // ok]]>
- </programlisting>
- The lambda functors created with
- <literal>ret<<parameter>T</parameter>>(bind(<parameter>arg-list</parameter>))</literal> and
- <literal>bind<<parameter>T</parameter>>(<parameter>arg-list</parameter>)</literal> have the exact same functionality —
- apart from the fact that for some nullary lambda functors the former does not work while the latter does.
- </para>
- </section>
- </section>
- <section id="lambda.delaying_constants_and_variables">
- <title>Delaying constants and variables</title>
- <para>
- The unary functions <literal>constant</literal>,
- <literal>constant_ref</literal> and <literal>var</literal> turn their argument into a lambda functor, that implements an identity mapping.
- The former two are for constants, the latter for variables.
- The use of these <emphasis>delayed</emphasis> constants and variables is sometimes necessary due to the lack of explicit syntax for lambda expressions.
- For example:
- <programlisting>
- <![CDATA[for_each(a.begin(), a.end(), cout << _1 << ' ');
- for_each(a.begin(), a.end(), cout << ' ' << _1);]]>
- </programlisting>
- The first line outputs the elements of <literal>a</literal> separated by spaces, while the second line outputs a space followed by the elements of <literal>a</literal> without any separators.
- The reason for this is that neither of the operands of
- <literal><![CDATA[cout << ' ']]></literal> is a lambda expression, hence <literal><![CDATA[cout << ' ']]></literal> is evaluated immediately.
- To delay the evaluation of <literal><![CDATA[cout << ' ']]></literal>, one of the operands must be explicitly marked as a lambda expression.
- This is accomplished with the <literal>constant</literal> function:
- <programlisting>
- <![CDATA[for_each(a.begin(), a.end(), cout << constant(' ') << _1);]]>
- </programlisting>
- The call <literal>constant(' ')</literal> creates a nullary lambda functor which stores the character constant <literal>' '</literal>
- and returns a reference to it when invoked.
- The function <literal>constant_ref</literal> is similar, except that it
- stores a constant reference to its argument.
- The <literal>constant</literal> and <literal>consant_ref</literal> are only
- needed when the operator call has side effects, like in the above example.
- </para>
- <para>
- Sometimes we need to delay the evaluation of a variable.
- Suppose we wanted to output the elements of a container in a numbered list:
- <programlisting>
- <![CDATA[int index = 0;
- for_each(a.begin(), a.end(), cout << ++index << ':' << _1 << '\n');
- for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1 << '\n');]]>
- </programlisting>
- The first <literal>for_each</literal> invocation does not do what we want; <literal>index</literal> is incremented only once, and its value is written into the output stream only once.
- By using <literal>var</literal> to make <literal>index</literal> a lambda expression, we get the desired effect.
- <!-- Note that <literal>var</literal> accepts const objects as well, in which case
- calling <literal>var</literal> equals calling <literal>constant_ref</literal>.-->
- </para>
- <para>
- In sum, <literal>var(x)</literal> creates a nullary lambda functor,
- which stores a reference to the variable <literal>x</literal>.
- When the lambda functor is invoked, a reference to <literal>x</literal> is returned.
- </para>
- <simplesect>
- <title>Naming delayed constants and variables</title>
- <para>
- It is possible to predefine and name a delayed variable or constant outside a lambda expression.
- The templates <literal>var_type</literal>, <literal>constant_type</literal>
- and <literal>constant_ref_type</literal> serve for this purpose.
- They are used as:
- <programlisting>
- <![CDATA[var_type<T>::type delayed_i(var(i));
- constant_type<T>::type delayed_c(constant(c));]]>
- </programlisting>
- The first line defines the variable <literal>delayed_i</literal> which is a delayed version of the variable <literal>i</literal> of type <literal>T</literal>.
- Analogously, the second line defines the constant <literal>delayed_c</literal> as a delayed version of the constant <literal>c</literal>.
- For example:
- <programlisting>
- int i = 0; int j;
- for_each(a.begin(), a.end(), (var(j) = _1, _1 = var(i), var(i) = var(j)));
- </programlisting>
- is equivalent to:
- <programlisting>
- <![CDATA[int i = 0; int j;
- var_type<int>::type vi(var(i)), vj(var(j));
- for_each(a.begin(), a.end(), (vj = _1, _1 = vi, vi = vj));]]>
- </programlisting>
- </para>
- <para>
- Here is an example of naming a delayed constant:
- <programlisting>
- <![CDATA[constant_type<char>::type space(constant(' '));
- for_each(a.begin(),a.end(), cout << space << _1);]]>
- </programlisting>
- </para>
- </simplesect>
- <simplesect>
- <title>About assignment and subscript operators</title>
- <para>
- As described in <xref linkend="lambda.assignment_and_subscript"/>, assignment and subscripting operators are always defined as member functions.
- This means, that for expressions of the form
- <literal>x = y</literal> or <literal>x[y]</literal> to be interpreted as lambda expressions, the left-hand operand <literal>x</literal> must be a lambda expression.
- Consequently, it is sometimes necessary to use <literal>var</literal> for this purpose.
- We repeat the example from <xref linkend="lambda.assignment_and_subscript"/>:
- <programlisting>
- int i;
- i = _1; // error
- var(i) = _1; // ok
- </programlisting>
- </para>
- <para>
- Note that the compound assignment operators <literal>+=</literal>, <literal>-=</literal> etc. can be defined as non-member functions, and thus they are interpreted as lambda expressions even if only the right-hand operand is a lambda expression.
- Nevertheless, it is perfectly ok to delay the left operand explicitly.
- For example, <literal>i += _1</literal> is equivalent to <literal>var(i) += _1</literal>.
- </para>
- </simplesect>
- </section>
- <section id="lambda.lambda_expressions_for_control_structures">
- <title>Lambda expressions for control structures</title>
- <para>
- BLL defines several functions to create lambda functors that represent control structures.
- They all take lambda functors as parameters and return <literal>void</literal>.
- To start with an example, the following code outputs all even elements of some container <literal>a</literal>:
- <programlisting>
- <![CDATA[for_each(a.begin(), a.end(),
- if_then(_1 % 2 == 0, cout << _1));]]>
- </programlisting>
- </para>
- <para>
- The BLL supports the following function templates for control structures:
- <programlisting>
- if_then(condition, then_part)
- if_then_else(condition, then_part, else_part)
- if_then_else_return(condition, then_part, else_part)
- while_loop(condition, body)
- while_loop(condition) // no body case
- do_while_loop(condition, body)
- do_while_loop(condition) // no body case
- for_loop(init, condition, increment, body)
- for_loop(init, condition, increment) // no body case
- switch_statement(...)
- </programlisting>
- The return types of all control construct lambda functor is
- <literal>void</literal>, except for <literal>if_then_else_return</literal>,
- which wraps a call to the conditional operator
- <programlisting>
- condition ? then_part : else_part
- </programlisting>
- The return type rules for this operator are somewhat complex.
- Basically, if the branches have the same type, this type is the return type.
- If the type of the branches differ, one branch, say of type
- <literal>A</literal>, must be convertible to the other branch,
- say of type <literal>B</literal>.
- In this situation, the result type is <literal>B</literal>.
- Further, if the common type is an lvalue, the return type will be an lvalue
- too.
- </para>
- <para>
- Delayed variables tend to be commonplace in control structure lambda expressions.
- For instance, here we use the <literal>var</literal> function to turn the arguments of <literal>for_loop</literal> into lambda expressions.
- The effect of the code is to add 1 to each element of a two-dimensional array:
- <programlisting>
- <![CDATA[int a[5][10]; int i;
- for_each(a, a+5,
- for_loop(var(i)=0, var(i)<10, ++var(i),
- _1[var(i)] += 1));]]>
- </programlisting>
- <!--
- As explained in <xref linkend="lambda.delaying_constants_and_variables"/>, we can avoid the repeated use of wrapping of <literal>var</literal> if we define it beforehand:
- <programlisting>
- <![CDATA[int i;
- var_type<int>::type vi(var(i));
- for_each(a, a+5,
- for_loop(vi=0, vi<10, ++vi, _1[vi] += 6));]]>
- </programlisting>
- -->
- </para>
- <para>
- The BLL supports an alternative syntax for control expressions, suggested
- by Joel de Guzmann.
- By overloading the <literal>operator[]</literal> we can
- get a closer resemblance with the built-in control structures:
- <programlisting>
- <![CDATA[if_(condition)[then_part]
- if_(condition)[then_part].else_[else_part]
- while_(condition)[body]
- do_[body].while_(condition)
- for_(init, condition, increment)[body]]]>
- </programlisting>
- For example, using this syntax the <literal>if_then</literal> example above
- can be written as:
- <programlisting>
- <![CDATA[for_each(a.begin(), a.end(),
- if_(_1 % 2 == 0)[ cout << _1 ])]]>
- </programlisting>
- As more experience is gained, we may end up deprecating one or the other
- of these syntaces.
- </para>
- <section id="lambda.switch_statement">
- <title>Switch statement</title>
- </section>
- <para>
- The lambda expressions for <literal>switch</literal> control structures are more complex since the number of cases may vary.
- The general form of a switch lambda expression is:
- <programlisting>
- switch_statement(<parameter>condition</parameter>,
- case_statement<<parameter>label</parameter>>(<parameter>lambda expression</parameter>),
- case_statement<<parameter>label</parameter>>(<parameter>lambda expression</parameter>),
- ...
- default_statement(<parameter>lambda expression</parameter>)
- )
- </programlisting>
- The <literal><parameter>condition</parameter></literal> argument must be a lambda expression that creates a lambda functor with an integral return type.
- The different cases are created with the <literal>case_statement</literal> functions, and the optional default case with the <literal>default_statement</literal> function.
- The case labels are given as explicitly specified template arguments to <literal>case_statement</literal> functions and
- <literal>break</literal> statements are implicitly part of each case.
- For example, <literal><![CDATA[case_statement<1>(a)]]></literal>, where <literal>a</literal> is some lambda functor, generates the code:
- <programlisting>
- case 1:
- <parameter>evaluate lambda functor</parameter> a;
- break;
- </programlisting>
- The <literal>switch_statement</literal> function is specialized for up to 9 case statements.
- </para>
- <para>
- As a concrete example, the following code iterates over some container <literal>v</literal> and ouptuts <quote>zero</quote> for each <literal>0</literal>, <quote>one</quote> for each <literal>1</literal>, and <quote>other: <parameter>n</parameter></quote> for any other value <parameter>n</parameter>.
- Note that another lambda expression is sequenced after the <literal>switch_statement</literal> to output a line break after each element:
- <programlisting>
- <![CDATA[std::for_each(v.begin(), v.end(),
- (
- switch_statement(
- _1,
- case_statement<0>(std::cout << constant("zero")),
- case_statement<1>(std::cout << constant("one")),
- default_statement(cout << constant("other: ") << _1)
- ),
- cout << constant("\n")
- )
- );]]>
- </programlisting>
- </para>
- </section>
- <section id="lambda.exceptions">
- <title>Exceptions</title>
- <para>
- The BLL provides lambda functors that throw and catch exceptions.
- Lambda functors for throwing exceptions are created with the unary function <literal>throw_exception</literal>.
- The argument to this function is the exception to be thrown, or a lambda functor which creates the exception to be thrown.
- A lambda functor for rethrowing exceptions is created with the nullary <literal>rethrow</literal> function.
- </para>
- <para>
- Lambda expressions for handling exceptions are somewhat more complex.
- The general form of a lambda expression for try catch blocks is as follows:
- <programlisting>
- try_catch(
- <parameter>lambda expression</parameter>,
- catch_exception<<parameter>type</parameter>>(<parameter>lambda expression</parameter>),
- catch_exception<<parameter>type</parameter>>(<parameter>lambda expression</parameter>),
- ...
- catch_all(<parameter>lambda expression</parameter>)
- )
- </programlisting>
- The first lambda expression is the try block.
- Each <literal>catch_exception</literal> defines a catch block where the
- explicitly specified template argument defines the type of the exception
- to catch.
- The lambda expression within the <literal>catch_exception</literal> defines
- the actions to take if the exception is caught.
- Note that the resulting exception handlers catch the exceptions as
- references, i.e., <literal>catch_exception<T>(...)</literal>
- results in the catch block:
- <programlisting>
- catch(T& e) { ... }
- </programlisting>
- The last catch block can alternatively be a call to
- <literal>catch_exception<<parameter>type</parameter>></literal>
- or to
- <literal>catch_all</literal>, which is the lambda expression equivalent to
- <literal>catch(...)</literal>.
- </para>
- <para>
- The <xref linkend="ex:exceptions"/> demonstrates the use of the BLL
- exception handling tools.
- The first handler catches exceptions of type <literal>foo_exception</literal>.
- Note the use of <literal>_1</literal> placeholder in the body of the handler.
- </para>
- <para>
- The second handler shows how to throw exceptions, and demonstrates the
- use of the <emphasis>exception placeholder</emphasis> <literal>_e</literal>.
- It is a special placeholder, which refers to the caught exception object
- within the handler body.
- Here we are handling an exception of type <literal>std::exception</literal>,
- which carries a string explaining the cause of the exception.
- This explanation can be queried with the zero-argument member
- function <literal>what</literal>.
- The expression
- <literal>bind(&std::exception::what, _e)</literal> creates the lambda
- function for making that call.
- Note that <literal>_e</literal> cannot be used outside of an exception handler lambda expression.
- <!--Violating this rule is caught by the compiler.-->
- The last line of the second handler constructs a new exception object and
- throws that with <literal>throw exception</literal>.
- Constructing and destructing objects within lambda expressions is
- explained in <xref linkend="lambda.construction_and_destruction"/>
- </para>
- <para>
- Finally, the third handler (<literal>catch_all</literal>) demonstrates
- rethrowing exceptions.
- </para>
- <example id="ex:exceptions">
- <title>Throwing and handling exceptions in lambda expressions.</title>
- <programlisting>
- <![CDATA[for_each(
- a.begin(), a.end(),
- try_catch(
- bind(foo, _1), // foo may throw
- catch_exception<foo_exception>(
- cout << constant("Caught foo_exception: ")
- << "foo was called with argument = " << _1
- ),
- catch_exception<std::exception>(
- cout << constant("Caught std::exception: ")
- << bind(&std::exception::what, _e),
- throw_exception(bind(constructor<bar_exception>(), _1)))
- ),
- catch_all(
- (cout << constant("Unknown"), rethrow())
- )
- )
- );]]>
- </programlisting>
- </example>
- </section>
- <section id="lambda.construction_and_destruction">
- <title>Construction and destruction</title>
- <para>
- Operators <literal>new</literal> and <literal>delete</literal> can be
- overloaded, but their return types are fixed.
- Particularly, the return types cannot be lambda functors,
- which prevents them to be overloaded for lambda expressions.
- It is not possible to take the address of a constructor,
- hence constructors cannot be used as target functions in bind expressions.
- The same is true for destructors.
- As a way around these constraints, BLL defines wrapper classes for
- <literal>new</literal> and <literal>delete</literal> calls,
- as well as for constructors and destructors.
- Instances of these classes are function objects, that can be used as
- target functions of bind expressions.
- For example:
- <programlisting>
- <![CDATA[int* a[10];
- for_each(a, a+10, _1 = bind(new_ptr<int>()));
- for_each(a, a+10, bind(delete_ptr(), _1));]]>
- </programlisting>
- The <literal>new_ptr<int>()</literal> expression creates
- a function object that calls <literal>new int()</literal> when invoked,
- and wrapping that inside <literal>bind</literal> makes it a lambda functor.
- In the same way, the expression <literal>delete_ptr()</literal> creates
- a function object that invokes <literal>delete</literal> on its argument.
- Note that <literal>new_ptr<<parameter>T</parameter>>()</literal>
- can take arguments as well.
- They are passed directly to the constructor invocation and thus allow
- calls to constructors which take arguments.
- </para>
- <para>
- As an example of constructor calls in lambda expressions,
- the following code reads integers from two containers <literal>x</literal>
- and <literal>y</literal>,
- constructs pairs out of them and inserts them into a third container:
- <programlisting>
- <![CDATA[vector<pair<int, int> > v;
- transform(x.begin(), x.end(), y.begin(), back_inserter(v),
- bind(constructor<pair<int, int> >(), _1, _2));]]>
- </programlisting>
- <xref linkend="table:constructor_destructor_fos"/> lists all the function
- objects related to creating and destroying objects,
- showing the expression to create and call the function object,
- and the effect of evaluating that expression.
- </para>
- <table id="table:constructor_destructor_fos">
- <title>Construction and destruction related function objects.</title>
- <tgroup cols="2">
- <thead>
- <row>
- <entry>Function object call</entry>
- <entry>Wrapped expression</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>constructor<T>()(<parameter>arg_list</parameter>)</literal></entry>
- <entry>T(<parameter>arg_list</parameter>)</entry>
- </row>
- <row>
- <entry><literal>destructor()(a)</literal></entry>
- <entry><literal>a.~A()</literal>, where <literal>a</literal> is of type <literal>A</literal></entry>
- </row>
- <row>
- <entry><literal>destructor()(pa)</literal></entry>
- <entry><literal>pa->~A()</literal>, where <literal>pa</literal> is of type <literal>A*</literal></entry>
- </row>
- <row>
- <entry><literal>new_ptr<T>()(<parameter>arg_list</parameter>)</literal></entry>
- <entry><literal>new T(<parameter>arg_list</parameter>)</literal></entry>
- </row>
- <row>
- <entry><literal>new_array<T>()(sz)</literal></entry>
- <entry><literal>new T[sz]</literal></entry>
- </row>
- <row>
- <entry><literal>delete_ptr()(p)</literal></entry>
- <entry><literal>delete p</literal></entry>
- </row>
- <row>
- <entry><literal>delete_array()(p)</literal></entry>
- <entry><literal>delete p[]</literal></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </section>
- <section>
- <title>Special lambda expressions</title>
- <section>
- <title>Preventing argument substitution</title>
- <para>
- When a lambda functor is called, the default behavior is to substitute
- the actual arguments for the placeholders within all subexpressions.
- This section describes the tools to prevent the substitution and
- evaluation of a subexpression, and explains when these tools should be used.
- </para>
- <para>
- The arguments to a bind expression can be arbitrary lambda expressions,
- e.g., other bind expressions.
- For example:
- <programlisting>
- int foo(int); int bar(int);
- ...
- int i;
- bind(foo, bind(bar, _1))(i);
- </programlisting>
- The last line makes the call <literal>foo(bar(i));</literal>
- Note that the first argument in a bind expression, the target function,
- is no exception, and can thus be a bind expression too.
- The innermost lambda functor just has to return something that can be used
- as a target function: another lambda functor, function pointer,
- pointer to member function etc.
- For example, in the following code the innermost lambda functor makes
- a selection between two functions, and returns a pointer to one of them:
- <programlisting>
- int add(int a, int b) { return a+b; }
- int mul(int a, int b) { return a*b; }
- int(*)(int, int) add_or_mul(bool x) {
- return x ? add : mul;
- }
- bool condition; int i; int j;
- ...
- bind(bind(&add_or_mul, _1), _2, _3)(condition, i, j);
- </programlisting>
- </para>
- <section id="lambda.unlambda">
- <title>Unlambda</title>
- <para>A nested bind expression may occur inadvertently,
- if the target function is a variable with a type that depends on a
- template parameter.
- Typically the target function could be a formal parameter of a
- function template.
- In such a case, the programmer may not know whether the target function is a lambda functor or not.
- </para>
- <para>Consider the following function template:
- <programlisting>
- <![CDATA[template<class F>
- int nested(const F& f) {
- int x;
- ...
- bind(f, _1)(x);
- ...
- }]]>
- </programlisting>
- Somewhere inside the function the formal parameter
- <literal>f</literal> is used as a target function in a bind expression.
- In order for this <literal>bind</literal> call to be valid,
- <literal>f</literal> must be a unary function.
- Suppose the following two calls to <literal>nested</literal> are made:
- <programlisting>
- <![CDATA[int foo(int);
- int bar(int, int);
- nested(&foo);
- nested(bind(bar, 1, _1));]]>
- </programlisting>
- Both are unary functions, or function objects, with appropriate argument
- and return types, but the latter will not compile.
- In the latter call, the bind expression inside <literal>nested</literal>
- will become:
- <programlisting>
- bind(bind(bar, 1, _1), _1)
- </programlisting>
- When this is invoked with <literal>x</literal>,
- after substituitions we end up trying to call
- <programlisting>
- bar(1, x)(x)
- </programlisting>
- which is an error.
- The call to <literal>bar</literal> returns int,
- not a unary function or function object.
- </para>
- <para>
- In the example above, the intent of the bind expression in the
- <literal>nested</literal> function is to treat <literal>f</literal>
- as an ordinary function object, instead of a lambda functor.
- The BLL provides the function template <literal>unlambda</literal> to
- express this: a lambda functor wrapped inside <literal>unlambda</literal>
- is not a lambda functor anymore, and does not take part into the
- argument substitution process.
- Note that for all other argument types <literal>unlambda</literal> is
- an identity operation, except for making non-const objects const.
- </para>
- <para>
- Using <literal>unlambda</literal>, the <literal>nested</literal>
- function is written as:
- <programlisting>
- <![CDATA[template<class F>
- int nested(const F& f) {
- int x;
- ...
- bind(unlambda(f), _1)(x);
- ...
- }]]>
- </programlisting>
- </para>
- </section>
- <section>
- <title>Protect</title>
- <para>
- The <literal>protect</literal> function is related to unlambda.
- It is also used to prevent the argument substitution taking place,
- but whereas <literal>unlambda</literal> turns a lambda functor into
- an ordinary function object for good, <literal>protect</literal> does
- this temporarily, for just one evaluation round.
- For example:
- <programlisting>
- int x = 1, y = 10;
- (_1 + protect(_1 + 2))(x)(y);
- </programlisting>
-
- The first call substitutes <literal>x</literal> for the leftmost
- <literal>_1</literal>, and results in another lambda functor
- <literal>x + (_1 + 2)</literal>, which after the call with
- <literal>y</literal> becomes <literal>x + (y + 2)</literal>,
- and thus finally 13.
- </para>
- <para>
- Primary motivation for including <literal>protect</literal> into the library,
- was to allow nested STL algorithm invocations
- (<xref linkend="lambda.nested_stl_algorithms"/>).
- </para>
- </section>
- </section>
- <section id="lambda.rvalues_as_actual_arguments">
- <title>Rvalues as actual arguments to lambda functors</title>
- <!-- <para><emphasis>This section and all of its subsections
- are no longer (or currently) relevant;
- acual arguments can be non-const rvalues and these workarounds are thus
- not needed.
- The section can, however, become relevant again, if in the future BLL will support
- lambda functors with higher arities than 3.</emphasis></para> -->
- <para>
- Actual arguments to the lambda functors cannot be non-const rvalues.
- This is due to a deliberate design decision: either we have this restriction,
- or there can be no side-effects to the actual arguments.
- There are ways around this limitation.
- We repeat the example from section
- <xref linkend="lambda.actual_arguments_to_lambda_functors"/> and list the
- different solutions:
- <programlisting>
- int i = 1; int j = 2;
- (_1 + _2)(i, j); // ok
- (_1 + _2)(1, 2); // error (!)
- </programlisting>
- <orderedlist>
- <listitem>
- <para>
- If the rvalue is of a class type, the return type of the function that
- creates the rvalue should be defined as const.
- Due to an unfortunate language restriction this does not work for
- built-in types, as built-in rvalues cannot be const qualified.
- </para>
- </listitem>
- <listitem>
- <para>
- If the lambda function call is accessible, the <literal>make_const</literal>
- function can be used to <emphasis>constify</emphasis> the rvalue. E.g.:
- <programlisting>
- (_1 + _2)(make_const(1), make_const(2)); // ok
- </programlisting>
- Commonly the lambda function call site is inside a standard algorithm
- function template, preventing this solution to be used.
- </para>
- </listitem>
- <listitem>
- <para>
- If neither of the above is possible, the lambda expression can be wrapped
- in a <literal>const_parameters</literal> function.
- It creates another type of lambda functor, which takes its arguments as
- const references. For example:
- <programlisting>
- const_parameters(_1 + _2)(1, 2); // ok
- </programlisting>
- Note that <literal>const_parameters</literal> makes all arguments const.
- Hence, in the case were one of the arguments is a non-const rvalue,
- and another argument needs to be passed as a non-const reference,
- this approach cannot be used.
- </para>
- </listitem>
- <listitem>
- <para>If none of the above is possible, there is still one solution,
- which unfortunately can break const correctness.
- The solution is yet another lambda functor wrapper, which we have named
- <literal>break_const</literal> to alert the user of the potential dangers
- of this function.
- The <literal>break_const</literal> function creates a lambda functor that
- takes its arguments as const, and casts away constness prior to the call
- to the original wrapped lambda functor.
- For example:
- <programlisting>
- int i;
- ...
- (_1 += _2)(i, 2); // error, 2 is a non-const rvalue
- const_parameters(_1 += _2)(i, 2); // error, i becomes const
- break_const(_1 += _2)(i, 2); // ok, but dangerous
- </programlisting>
- Note, that the results of <literal> break_const</literal> or
- <literal>const_parameters</literal> are not lambda functors,
- so they cannot be used as subexpressions of lambda expressions. For instance:
- <programlisting>
- break_const(_1 + _2) + _3; // fails.
- const_parameters(_1 + _2) + _3; // fails.
- </programlisting>
- However, this kind of code should never be necessary,
- since calls to sub lambda functors are made inside the BLL,
- and are not affected by the non-const rvalue problem.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </section>
- </section>
- <section>
- <title>Casts, sizeof and typeid</title>
- <section id="lambda.cast_expressions">
- <title>
- Cast expressions
- </title>
- <para>
- The BLL defines its counterparts for the four cast expressions
- <literal>static_cast</literal>, <literal>dynamic_cast</literal>,
- <literal>const_cast</literal> and <literal>reinterpret_cast</literal>.
- The BLL versions of the cast expressions have the prefix
- <literal>ll_</literal>.
- The type to cast to is given as an explicitly specified template argument,
- and the sole argument is the expression from which to perform the cast.
- If the argument is a lambda functor, the lambda functor is evaluated first.
- For example, the following code uses <literal>ll_dynamic_cast</literal>
- to count the number of <literal>derived</literal> instances in the container
- <literal>a</literal>:
- <programlisting>
- <![CDATA[class base {};
- class derived : public base {};
- vector<base*> a;
- ...
- int count = 0;
- for_each(a.begin(), a.end(),
- if_then(ll_dynamic_cast<derived*>(_1), ++var(count)));]]>
- </programlisting>
- </para>
- </section>
- <section>
- <title>Sizeof and typeid</title>
- <para>
- The BLL counterparts for these expressions are named
- <literal>ll_sizeof</literal> and <literal>ll_typeid</literal>.
- Both take one argument, which can be a lambda expression.
- The lambda functor created wraps the <literal>sizeof</literal> or
- <literal>typeid</literal> call, and when the lambda functor is called
- the wrapped operation is performed.
- For example:
- <programlisting>
- <![CDATA[vector<base*> a;
- ...
- for_each(a.begin(), a.end(),
- cout << bind(&type_info::name, ll_typeid(*_1)));]]>
- </programlisting>
- Here <literal>ll_typeid</literal> creates a lambda functor for
- calling <literal>typeid</literal> for each element.
- The result of a <literal>typeid</literal> call is an instance of
- the <literal>type_info</literal> class, and the bind expression creates
- a lambda functor for calling the <literal>name</literal> member
- function of that class.
- </para>
- </section>
- </section>
- <section id="lambda.nested_stl_algorithms">
- <title>Nesting STL algorithm invocations</title>
- <para>
- The BLL defines common STL algorithms as function object classes,
- instances of which can be used as target functions in bind expressions.
- For example, the following code iterates over the elements of a
- two-dimensional array, and computes their sum.
- <programlisting>
- int a[100][200];
- int sum = 0;
- std::for_each(a, a + 100,
- bind(ll::for_each(), _1, _1 + 200, protect(sum += _1)));
- </programlisting>
- The BLL versions of the STL algorithms are classes, which define the function call operator (or several overloaded ones) to call the corresponding function templates in the <literal>std</literal> namespace.
- All these structs are placed in the subnamespace <literal>boost::lambda:ll</literal>.
- <!--The supported algorithms are listed in <xref linkend="table:nested_algorithms"/>.-->
- </para>
- <para>
- Note that there is no easy way to express an overloaded member function
- call in a lambda expression.
- This limits the usefulness of nested STL algorithms, as for instance
- the <literal>begin</literal> function has more than one overloaded
- definitions in container templates.
- In general, something analogous to the pseudo-code below cannot be written:
- <programlisting>
- std::for_each(a.begin(), a.end(),
- bind(ll::for_each(), _1.begin(), _1.end(), protect(sum += _1)));
- </programlisting>
- Some aid for common special cases can be provided though.
- The BLL defines two helper function object classes,
- <literal>call_begin</literal> and <literal>call_end</literal>,
- which wrap a call to the <literal>begin</literal> and, respectively,
- <literal>end</literal> functions of a container, and return the
- <literal>const_iterator</literal> type of the container.
- With these helper templates, the above code becomes:
- <programlisting>
- std::for_each(a.begin(), a.end(),
- bind(ll::for_each(),
- bind(call_begin(), _1), bind(call_end(), _1),
- protect(sum += _1)));
- </programlisting>
- </para>
- <!--
- <table id="table:nested_algorithms">
- <title>The nested STL algorithms.</title>
- <tgroup cols="1">
- <thead>
- <trow><entry>Otsikko</entry></trow>
- </thead>
- <tbody>
- <row><entry><literal>for_each</literal></entry></row>
- <row><entry><literal>find</literal></entry></row>
- <row><entry><literal>find_if</literal></entry></row>
- <row><entry><literal>find_end</literal></entry></row>
- <row><entry><literal>find_first_of</literal></entry></row>
- <row><entry><literal>transform</literal></entry></row>
- </tbody>
- </tgroup>
- </table>
- -->
- </section>
- </section>
- <!--
- <section>
- <title>Common gothcas</title>
- calling member functions a.begin()
- calling templated functions ...
- </section>
- -->
- <section id="lambda.extending">
- <title>Extending return type deduction system</title>
- <para>
- <!--The <xref linkend = "lambda.overriding_deduced_return_type"/> showed how to make BLL aware of the return type of a function object in bind expressions.-->
- In this section, we explain how to extend the return type deduction system
- to cover user defined operators.
- In many cases this is not necessary,
- as the BLL defines default return types for operators.
- For example, the default return type for all comparison operators is
- <literal>bool</literal>, and as long as the user defined comparison operators
- have a bool return type, there is no need to write new specializations
- for the return type deduction classes.
- Sometimes this cannot be avoided, though.
- </para>
- <para>
- The overloadable user defined operators are either unary or binary.
- For each arity, there are two traits templates that define the
- return types of the different operators.
- Hence, the return type system can be extended by providing more
- specializations for these templates.
- The templates for unary functors are
- <literal>
- <![CDATA[plain_return_type_1<Action, A>]]>
- </literal>
- and
- <literal>
- <![CDATA[return_type_1<Action, A>]]>
- </literal>, and
- <literal>
- <![CDATA[plain_return_type_2<Action, A, B>]]>
- </literal>
- and
- <literal>
- <![CDATA[return_type_2<Action, A, B>]]>
- </literal>
- respectively for binary functors.
- </para>
- <para>
- The first parameter (<literal>Action</literal>) to all these templates
- is the <emphasis>action</emphasis> class, which specifies the operator.
- Operators with similar return type rules are grouped together into
- <emphasis>action groups</emphasis>,
- and only the action class and action group together define the operator
- unambiguously.
- As an example, the action type
- <literal><![CDATA[arithmetic_action<plus_action>]]></literal> stands for
- <literal>operator+</literal>.
- The complete listing of different action types is shown in
- <xref linkend="table:actions"/>.
- </para>
- <para>
- The latter parameters, <literal>A</literal> in the unary case,
- or <literal>A</literal> and <literal>B</literal> in the binary case,
- stand for the argument types of the operator call.
- The two sets of templates,
- <literal>plain_return_type_<parameter>n</parameter></literal> and
- <literal>return_type_<parameter>n</parameter></literal>
- (<parameter>n</parameter> is 1 or 2) differ in the way how parameter types
- are presented to them.
- For the former templates, the parameter types are always provided as
- non-reference types, and do not have const or volatile qualifiers.
- This makes specializing easy, as commonly one specialization for each
- user defined operator, or operator group, is enough.
- On the other hand, if a particular operator is overloaded for different
- cv-qualifications of the same argument types,
- and the return types of these overloaded versions differ, a more fine-grained control is needed.
- Hence, for the latter templates, the parameter types preserve the
- cv-qualifiers, and are non-reference types as well.
-
- The downside is, that for an overloaded set of operators of the
- kind described above, one may end up needing up to
- 16 <literal>return_type_2</literal> specializations.
- </para>
- <para>
- Suppose the user has overloaded the following operators for some user defined
- types <literal>X</literal>, <literal>Y</literal> and <literal>Z</literal>:
- <programlisting>
- <![CDATA[Z operator+(const X&, const Y&);
- Z operator-(const X&, const Y&);]]>
- </programlisting>
- Now, one can add a specialization stating, that if the left hand argument
- is of type <literal>X</literal>, and the right hand one of type
- <literal>Y</literal>, the return type of all such binary arithmetic
- operators is <literal>Z</literal>:
- <programlisting>
- <![CDATA[namespace boost {
- namespace lambda {
-
- template<class Act>
- struct plain_return_type_2<arithmetic_action<Act>, X, Y> {
- typedef Z type;
- };
- }
- }]]>
- </programlisting>
- Having this specialization defined, BLL is capable of correctly
- deducing the return type of the above two operators.
- Note, that the specializations must be in the same namespace,
- <literal>::boost::lambda</literal>, with the primary template.
- For brevity, we do not show the namespace definitions in the examples below.
- </para>
- <para>
- It is possible to specialize on the level of an individual operator as well,
- in addition to providing a specialization for a group of operators.
- Say, we add a new arithmetic operator for argument types <literal>X</literal>
- and <literal>Y</literal>:
- <programlisting>
- <![CDATA[X operator*(const X&, const Y&);]]>
- </programlisting>
- Our first rule for all arithmetic operators specifies that the return
- type of this operator is <literal>Z</literal>,
- which obviously is not the case.
- Hence, we provide a new rule for the multiplication operator:
- <programlisting>
- <![CDATA[template<>
- struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> {
- typedef X type;
- };]]>
- </programlisting>
- </para>
- <para>
- The specializations can define arbitrary mappings from the argument types
- to the return type.
- Suppose we have some mathematical vector type, templated on the element type:
- <programlisting>
- <![CDATA[template <class T> class my_vector;]]>
- </programlisting>
- Suppose the addition operator is defined between any two
- <literal>my_vector</literal> instantiations,
- as long as the addition operator is defined between their element types.
- Furthermore, the element type of the resulting <literal>my_vector</literal>
- is the same as the result type of the addition between the element types.
- E.g., adding <literal><![CDATA[my_vector<int>]]></literal> and
- <literal><![CDATA[my_vector<double>]]></literal> results in
- <literal><![CDATA[my_vector<double>]]></literal>.
- The BLL has traits classes to perform the implicit built-in and standard
- type conversions between integral, floating point, and complex classes.
- Using BLL tools, the addition operator described above can be defined as:
- <programlisting>
- <![CDATA[template<class A, class B>
- my_vector<typename return_type_2<arithmetic_action<plus_action>, A, B>::type>
- operator+(const my_vector<A>& a, const my_vector<B>& b)
- {
- typedef typename
- return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
- return my_vector<res_type>();
- }]]>
- </programlisting>
- </para>
- <para>
- To allow BLL to deduce the type of <literal>my_vector</literal>
- additions correctly, we can define:
- <programlisting>
- <![CDATA[template<class A, class B>
- class plain_return_type_2<arithmetic_action<plus_action>,
- my_vector<A>, my_vector<B> > {
- typedef typename
- return_type_2<arithmetic_action<plus_action>, A, B>::type res_type;
- public:
- typedef my_vector<res_type> type;
- };]]>
- </programlisting>
- Note, that we are reusing the existing specializations for the
- BLL <literal>return_type_2</literal> template,
- which require that the argument types are references.
- </para>
- <!-- TODO: is an example of specifying the other level needed at all -->
- <!-- TODO: comma operator is a special case for that -->
- <table id = "table:actions">
- <title>Action types</title>
- <tgroup cols="2">
- <tbody>
- <row><entry><literal><![CDATA[+]]></literal></entry><entry><literal><![CDATA[arithmetic_action<plus_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[-]]></literal></entry><entry><literal><![CDATA[arithmetic_action<minus_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[*]]></literal></entry><entry><literal><![CDATA[arithmetic_action<multiply_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[/]]></literal></entry><entry><literal><![CDATA[arithmetic_action<divide_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[%]]></literal></entry><entry><literal><![CDATA[arithmetic_action<remainder_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[+]]></literal></entry><entry><literal><![CDATA[unary_arithmetic_action<plus_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[-]]></literal></entry><entry><literal><![CDATA[unary_arithmetic_action<minus_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[&]]></literal></entry><entry><literal><![CDATA[bitwise_action<and_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[|]]></literal></entry><entry><literal><![CDATA[bitwise_action<or_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[~]]></literal></entry><entry><literal><![CDATA[bitwise_action<not_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[^]]></literal></entry><entry><literal><![CDATA[bitwise_action<xor_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[<<]]></literal></entry><entry><literal><![CDATA[bitwise_action<leftshift_action_no_stream>]]></literal></entry></row>
- <row><entry><literal><![CDATA[>>]]></literal></entry><entry><literal><![CDATA[bitwise_action<rightshift_action_no_stream>]]></literal></entry></row>
- <row><entry><literal><![CDATA[&&]]></literal></entry><entry><literal><![CDATA[logical_action<and_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[||]]></literal></entry><entry><literal><![CDATA[logical_action<or_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[!]]></literal></entry><entry><literal><![CDATA[logical_action<not_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[<]]></literal></entry><entry><literal><![CDATA[relational_action<less_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[>]]></literal></entry><entry><literal><![CDATA[relational_action<greater_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[<=]]></literal></entry><entry><literal><![CDATA[relational_action<lessorequal_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[>=]]></literal></entry><entry><literal><![CDATA[relational_action<greaterorequal_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[==]]></literal></entry><entry><literal><![CDATA[relational_action<equal_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[!=]]></literal></entry><entry><literal><![CDATA[relational_action<notequal_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[+=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<plus_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[-=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<minus_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[*=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<multiply_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[/=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<divide_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[%=]]></literal></entry><entry><literal><![CDATA[arithmetic_assignment_action<remainder_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[&=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<and_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[=|]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<or_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[^=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<xor_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[<<=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<leftshift_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[>>=]]></literal></entry><entry><literal><![CDATA[bitwise_assignment_action<rightshift_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[++]]></literal></entry><entry><literal><![CDATA[pre_increment_decrement_action<increment_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[--]]></literal></entry><entry><literal><![CDATA[pre_increment_decrement_action<decrement_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[++]]></literal></entry><entry><literal><![CDATA[post_increment_decrement_action<increment_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[--]]></literal></entry><entry><literal><![CDATA[post_increment_decrement_action<decrement_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[&]]></literal></entry><entry><literal><![CDATA[other_action<address_of_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[*]]></literal></entry><entry><literal><![CDATA[other_action<contents_of_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[,]]></literal></entry><entry><literal><![CDATA[other_action<comma_action>]]></literal></entry></row>
- <row><entry><literal><![CDATA[->*]]></literal></entry><entry><literal><![CDATA[other_action<member_pointer_action>]]></literal></entry></row>
- </tbody>
- </tgroup>
- </table>
- </section>
- <section>
- <title>Practical considerations</title>
- <section>
- <title>Performance</title>
- <para>In theory, all overhead of using STL algorithms and lambda functors
- compared to hand written loops can be optimized away, just as the overhead
- from standard STL function objects and binders can.
- Depending on the compiler, this can also be true in practice.
- We ran two tests with the GCC 3.0.4 compiler on 1.5 GHz Intel Pentium 4.
- The optimization flag -03 was used.
- </para>
- <para>
- In the first test we compared lambda functors against explicitly written
- function objects.
- We used both of these styles to define unary functions which multiply the
- argument repeatedly by itself.
- We started with the identity function, going up to
- x<superscript>5</superscript>.
- The expressions were called inside a <literal>std::transform</literal> loop,
- reading the argument from one <literal><![CDATA[std::vector<int>]]></literal>
- and placing the result into another.
- The length of the vectors was 100 elements.
- The running times are listed in
- <xref linkend="table:increasing_arithmetic_test"/>.
- We can observe that there is no significant difference between the
- two approaches.
- </para>
- <para>
- In the second test we again used <literal>std::transform</literal> to
- perform an operation to each element in a 100-element long vector.
- This time the element type of the vectors was <literal>double</literal>
- and we started with very simple arithmetic expressions and moved to
- more complex ones.
- The running times are listed in <xref linkend="table:ll_vs_stl_test"/>.
- Here, we also included classic STL style unnamed functions into tests.
- We do not show these expressions, as they get rather complex.
- For example, the
- last expression in <xref linkend="table:ll_vs_stl_test"/> written with
- classic STL tools contains 7 calls to <literal>compose2</literal>,
- 8 calls to <literal>bind1st</literal>
- and altogether 14 constructor invocations for creating
- <literal>multiplies</literal>, <literal>minus</literal>
- and <literal>plus</literal> objects.
- In this test the BLL expressions are a little slower (roughly 10% on average,
- less than 14% in all cases)
- than the corresponding hand-written function objects.
- The performance hit is a bit greater with classic STL expressions,
- up to 27% for the simplest expressios.
- </para>
- <para>
- The tests suggest that the BLL does not introduce a loss of performance
- compared to STL function objects.
- With a reasonable optimizing compiler, one should expect the performance characteristics be comparable to using classic STL.
- Moreover, with simple expressions the performance can be expected to be close
- to that of explicitly written function objects.
- <!-- We repeated both tests with the KAI C++ 4.0f compiler (using +K2 -O3 flags),
- generally considered a good optimizing compiler.
- We do not list the results here, since the running times for the two alternatives in the first test were essentially the same, just as the running times
- for the three different alternatives in the second test.
- These tests suggest there to be no performance penalty at all
- with a good optimizing compiler.
- -->
- Note however, that evaluating a lambda functor consist of a sequence of calls to small functions that are declared inline.
- If the compiler fails to actually expand these functions inline,
- the performance can suffer.
- The running time can more than double if this happens.
- Although the above tests do not include such an expression, we have experienced
- this for some seemingly simple expressions.
- <table id = "table:increasing_arithmetic_test">
- <title>Test 1</title>
- <caption>CPU time of expressions with integer multiplication written as a lambda expression and as a traditional hand-coded function object class.
- The running times are expressed in arbitrary units.</caption>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>expression</entry><entry>lambda expression</entry><entry>hand-coded function object</entry></row>
- </thead>
- <tbody>
- <row>
- <entry>x</entry><entry>240</entry><entry>230</entry>
- </row>
- <row>
- <entry>x*x</entry><entry>340</entry><entry>350</entry>
- </row>
- <row>
- <entry>x*x*x</entry><entry>770</entry><entry>760</entry>
- </row>
- <row>
- <entry>x*x*x*x</entry><entry>1180</entry><entry>1210</entry>
- </row>
- <row>
- <entry>x*x*x*x*x</entry><entry>1950</entry><entry>1910</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </para>
- <!--
- 16:19:49 bench [601] ./arith.out 100 1000000
- Number of elements = 100
- L1 : 240
- L2 : 340
- L3 : 770
- L4 : 1180
- L5 : 1950
- P2 : 1700
- P3 : 2130
- P4 : 2530
- P5 : 3000
- F1 : 230
- F2 : 350
- F3 : 760
- F4 : 1210
- F5 : 1910
- Number of elements = 100
- Number of outer_iters = 1000000
- L1 : 330
- L2 : 350
- L3 : 470
- L4 : 620
- L5 : 1660
- LP : 1230
- C1 : 370
- C2 : 370
- C3 : 500
- C4 : 670
- C5 : 1660
- CP : 1770
- F1 : 290
- F2 : 310
- F3 : 420
- F4 : 600
- F5 : 1460
- FP : 1040
- -->
- <para>
- <table id = "table:ll_vs_stl_test">
- <title>Test 2</title>
- <caption>CPU time of arithmetic expressions written as lambda
- expressions, as classic STL unnamed functions (using <literal>compose2</literal>, <literal>bind1st</literal> etc.) and as traditional hand-coded function object classes.
- Using BLL terminology,
- <literal>a</literal> and <literal>b</literal> are bound arguments in the expressions, and <literal>x</literal> is open.
- All variables were of types <literal>double</literal>.
- The running times are expressed in arbitrary units.</caption>
- <tgroup cols="4">
- <thead>
- <row>
- <entry>expression</entry><entry>lambda expression</entry><entry>classic STL expression</entry><entry>hand-coded function object</entry></row>
- </thead>
- <tbody>
- <row>
- <entry>ax</entry><entry>330</entry><entry>370</entry><entry>290</entry>
- </row>
- <row>
- <entry>-ax</entry><entry>350</entry><entry>370</entry><entry>310</entry>
- </row>
- <row>
- <entry>ax-(a+x)</entry><entry>470</entry><entry>500</entry><entry>420</entry>
- </row>
- <row>
- <entry>(ax-(a+x))(a+x)</entry><entry>620</entry><entry>670</entry><entry>600</entry>
- </row>
- <row>
- <entry>((ax) - (a+x))(bx - (b+x))(ax - (b+x))(bx - (a+x))</entry><entry>1660</entry><entry>1660</entry><entry>1460</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </para>
- <para>Some additional performance testing with an earlier version of the
- library is described
- <xref linkend="cit:jarvi:00"/>.
- </para>
- </section>
- <section>
- <title>About compiling</title>
- <para>The BLL uses templates rather heavily, performing numerous recursive instantiations of the same templates.
- This has (at least) three implications:
- <itemizedlist>
- <listitem>
- <para>
- While it is possible to write incredibly complex lambda expressions, it probably isn't a good idea.
- Compiling such expressions may end up requiring a lot of memory
- at compile time, and being slow to compile.
- </para>
- </listitem>
- <listitem>
- <para>
- The types of lambda functors that result from even the simplest lambda expressions are cryptic.
- Usually the programmer doesn't need to deal with the lambda functor types at all, but in the case of an error in a lambda expression, the compiler usually outputs the types of the lambda functors involved.
- This can make the error messages very long and difficult to interpret, particularly if the compiler outputs the whole chain of template instantiations.
- </para>
- </listitem>
- <listitem>
- <para>
- The C++ Standard suggests a template nesting level of 17 to help detect infinite recursion.
- Complex lambda templates can easily exceed this limit.
- Most compilers allow a greater number of nested templates, but commonly require the limit explicitly increased with a command line argument.
- </para>
- </listitem>
- </itemizedlist></para>
- </section>
- <section>
- <title>Portability</title>
- <para>
- The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL:
- <itemizedlist>
- <listitem>GCC 3.0.4
- </listitem>
- <listitem>KCC 4.0f with EDG 2.43.1
- </listitem>
- <listitem>GCC 2.96 (fails with one test case, the <filename>exception_test.cpp</filename> results in an internal compiler error.
- )
- </listitem>
- </itemizedlist>
- </para>
- <section>
- <title>Test coverage</title>
- <para>The following list describes the test files included and the features that each file covers:
- <itemizedlist>
- <listitem>
- <para>
- <filename>bind_tests_simple.cpp</filename> : Bind expressions of different arities and types of target functions: function pointers, function objects and member functions.
- Function composition with bind expressions.</para>
- </listitem>
- <listitem>
- <para><filename>bind_tests_simple_function_references.cpp</filename> :
- Repeats all tests from <filename moreinfo="none">bind_tests_simple.cpp</filename> where the target function is a function pointer, but uses function references instead.
- </para></listitem>
-
- <listitem>
- <para><filename>bind_tests_advanced.cpp</filename> : Contains tests for nested bind expressions, <literal>unlambda</literal>, <literal>protect</literal>, <literal>const_parameters</literal> and <literal>break_const</literal>.
- Tests passing lambda functors as actual arguments to other lambda functors, currying, and using the <literal>sig</literal> template to specify the return type of a function object.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>operator_tests_simple.cpp</filename> :
- Tests using all operators that are overloaded for lambda expressions, that is, unary and binary arithmetic,
- bitwise,
- comparison,
- logical,
- increment and decrement,
- compound,
- assignment,
- subscrict,
- address of,
- dereference, and comma operators.
- The streaming nature of shift operators is tested, as well as pointer arithmetic with plus and minus operators.
- </para>
- </listitem>
-
- <listitem>
- <para><filename>member_pointer_test.cpp</filename> : The pointer to member operator is complex enough to warrant a separate test file.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>control_structures.cpp</filename> :
- Tests for the looping and if constructs.
- </para></listitem>
- <listitem>
- <para>
- <filename>switch_construct.cpp</filename> :
- Includes tests for all supported arities of the switch statement, both with and without the default case.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>exception_test.cpp</filename> :
- Includes tests for throwing exceptions and for try/catch constructs with varying number of catch blocks.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>constructor_tests.cpp</filename> :
- Contains tests for <literal>constructor</literal>, <literal>destructor</literal>, <literal>new_ptr</literal>, <literal>delete_ptr</literal>, <literal>new_array</literal> and <literal>delete_array</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>cast_test.cpp</filename> : Tests for the four cast expressions, as well as <filename>typeid</filename> and <literal>sizeof</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>extending_return_type_traits.cpp</filename> : Tests extending the return type deduction system for user defined types.
- Contains several user defined operators and the corresponding specializations for the return type deduction templates.
- </para>
- </listitem>
- <listitem>
- <para>
- <filename>is_instance_of_test.cpp</filename> : Includes tests for an internally used traits template, which can detect whether a given type is an instance of a certain template or not.
- </para></listitem>
- <listitem>
- <para>
- <filename>bll_and_function.cpp</filename> :
- Contains tests for using <literal>boost::function</literal> together with lambda functors.
- </para></listitem>
- </itemizedlist>
- </para>
- </section>
- </section>
- </section>
- <section>
- <title>Relation to other Boost libraries</title>
- <section>
- <title>Boost Function</title>
- <para>Sometimes it is convenient to store lambda functors in variables.
- However, the types of even the simplest lambda functors are long and unwieldy, and it is in general unfeasible to declare variables with lambda functor types.
- <emphasis>The Boost Function library</emphasis> <xref linkend="cit:boost::function"/> defines wrappers for arbitrary function objects, for example
- lambda functors; and these wrappers have types that are easy to type out.
- For example:
- <programlisting>
- <![CDATA[boost::function<int(int, int)> f = _1 + _2;
- boost::function<int&(int&)> g = (_1 += 10);
- int i = 1, j = 2;
- f(i, j); // returns 3
- g(i); // sets i to = 11;]]>
- </programlisting>
- The return and parameter types of the wrapped function object must be written explicilty as the template argument to the wrapper template <literal>boost::function</literal>; even when lambda functors, which otherwise have generic parameters, are wrapped.
- Wrapping a function object with <literal>boost::function</literal> introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used.
- Note that storing lambda functors inside <literal>boost::function</literal>
- introduces a danger.
- Certain types of lambda functors may store references to the bound
- arguments, instead as taking copies of the arguments of the lambda expression.
- When temporary lambda functor objects are used
- in STL algorithm invocations this is always safe, as the lambda functor gets
- destructed immediately after the STL algortihm invocation is completed.
- However, a lambda functor wrapped inside <literal>boost::function</literal>
- may continue to exist longer, creating the possibility of dangling references.
- For example:
- <programlisting>
- <![CDATA[int* sum = new int();
- *sum = 0;
- boost::function<int&(int)> counter = *sum += _1;
- counter(5); // ok, *sum = 5;
- delete sum;
- counter(3); // error, *sum does not exist anymore]]>
- </programlisting>
- </para>
- </section>
- <section>
- <title>Boost Bind</title>
- <para>
- <emphasis>The Boost Bind</emphasis> <xref linkend="cit:boost::bind"/> library has partially overlapping functionality with the BLL.
- Basically, the Boost Bind library (BB in the sequel) implements the bind expression part of BLL.
- There are, however, some semantical differerences.
- </para>
- <para>
- The BLL and BB evolved separately, and have different implementations.
- This means that the bind expressions from the BB cannot be used within
- bind expressions, or within other type of lambda expressions, of the BLL.
- The same holds for using BLL bind expressions in the BB.
- The libraries can coexist, however, as
- the names of the BB library are in <literal>boost</literal> namespace,
- whereas the BLL names are in <literal>boost::lambda</literal> namespace.
- </para>
- <para>
- The BLL requires a compiler that is reasonably conformant to the
- C++ standard, whereas the BB library is more portable, and works with
- a larger set of compilers.
- </para>
- <para>
- The following two sections describe what are the semantic differences
- between the bind expressions in BB and BLL.
- </para>
- <section>
- <title>First argument of bind expression</title>
- In BB the first argument of the bind expression, the target function,
- is treated differently from the other arguments,
- as no argument substitution takes place within that argument.
- In BLL the first argument is not a special case in this respect.
- For example:
- <programlisting>
- <![CDATA[template<class F>
- int foo(const F& f) {
- int x;
- ..
- bind(f, _1)(x);
- ...
- }]]>
- </programlisting>
- <programlisting>
- <![CDATA[int bar(int, int);
- nested(bind(bar, 1, _1));]]>
- </programlisting>
- The bind expression inside <literal>foo</literal> becomes:
- <programlisting>
- bind(bind(bar, 1, _1), _1)(x)
- </programlisting>
- The BLL interpretes this as:
- <programlisting>
- bar(1, x)(x)
- </programlisting>
- whereas the BB library as
- <programlisting>
- bar(1, x)
- </programlisting>
- To get this functionality in BLL, the bind expression inside the <literal moreinfo="none">foo</literal> function can be written as:
- <programlisting>
- bind(unlambda(f), _1)(x);
- </programlisting>
- as explained in <xref linkend = "lambda.unlambda"/>.
- </section>
- <para>
- The BB library supports up to nine placeholders, while the BLL
- defines only three placeholders.
- The rationale for not providing more, is that the highest arity of the
- function objects accepted by any STL algorithm is two.
- The placeholder count is easy to increase in the BB library.
- In BLL it is possible, but more laborous.
- The BLL currently passes the actual arguments to the lambda functors
- internally just as they are and does not wrap them inside a tuple object.
- The reason for this is that some widely used compilers are not capable
- of optimizing the intermediate tuple objects away.
- The creation of the intermediate tuples would cause a significant
- performance hit, particularly for the simplest (and thus the most common)
- lambda functors.
- We are working on a hybrid approach, which will allow more placeholders
- but not compromise the performance of simple lambda functors.
- </para>
- </section>
- </section>
- <section>
- <title>Contributors</title>
- The main body of the library was written by Jaakko Järvi and Gary Powell.
- We've got outside help, suggestions and ideas from Jeremy Siek, Peter Higley, Peter Dimov, Valentin Bonnard, William Kempf.
- We would particularly like to mention Joel de Guzmann and his work with
- Phoenix which has influenced BLL significantly, making it considerably simpler
- to extend the library with new features.
- </section>
- <section>
- <title>Rationale for some of the design decisions</title>
- <section id="lambda.why_weak_arity">
- <title>
- Lambda functor arity
- </title>
- <para>
- The highest placeholder index in a lambda expression determines the arity of the resulting function object.
- However, this is just the minimal arity, as the function object can take arbitrarily many arguments; those not needed are discarded.
- Consider the two bind expressions and their invocations below:
- <programlisting>
- bind(g, _3, _3, _3)(x, y, z);
- bind(g, _1, _1, _1)(x, y, z);
- </programlisting>
- This first line discards arguments <literal>x</literal> and
- <literal>y</literal>, and makes the call:
- <programlisting>
- g(z, z, z)
- </programlisting>
- whereas the second line discards arguments <literal>y</literal> and
- <literal>z</literal>, and calls:
- <programlisting>
- g(x, x, x)
- </programlisting>
- In earlier versions of the library, the latter line resulted in a compile
- time error.
- This is basically a tradeoff between safety and flexibility, and the issue
- was extensively discussed during the Boost review period of the library.
- The main points for the <emphasis>strict arity</emphasis> checking
- was that it might
- catch a programming error at an earlier time and that a lambda expression that
- explicitly discards its arguments is easy to write:
- <programlisting>
- (_3, bind(g, _1, _1, _1))(x, y, z);
- </programlisting>
- This lambda expression takes three arguments.
- The left-hand argument of the comma operator does nothing, and as comma
- returns the result of evaluating the right-hand argument we end up with
- the call
- <literal>g(x, x, x)</literal>
- even with the strict arity.
- </para>
- <para>
- The main points against the strict arity checking were that the need to
- discard arguments is commonplace, and should therefore be straightforward,
- and that strict arity checking does not really buy that much more safety,
- particularly as it is not symmetric.
- For example, if the programmer wanted to write the expression
- <literal>_1 + _2</literal> but mistakenly wrote <literal>_1 + 2</literal>,
- with strict arity checking, the complier would spot the error.
- However, if the erroneous expression was <literal>1 + _2</literal> instead,
- the error would go unnoticed.
- Furthermore, weak arity checking simplifies the implementation a bit.
- Following the recommendation of the Boost review, strict arity checking
- was dropped.
- </para>
- </section>
- </section>
- <bibliography>
- <biblioentry id="cit:stepanov:94">
- <abbrev>STL94</abbrev>
- <authorgroup>
- <author>
- <surname>Stepanov</surname>
- <firstname>A. A.</firstname>
- </author>
- <author>
- <surname>Lee</surname>
- <firstname>M.</firstname>
- </author>
- </authorgroup>
- <title>The Standard Template Library</title>
- <orgname>Hewlett-Packard Laboratories</orgname>
- <pubdate>1994</pubdate>
- <bibliomisc>
- <ulink url="http://www.hpl.hp.com/techreports">www.hpl.hp.com/techreports</ulink>
- </bibliomisc>
- </biblioentry>
- <biblioentry id="cit:sgi:02">
- <abbrev>SGI02</abbrev>
- <title>The SGI Standard Template Library</title>
- <pubdate>2002</pubdate>
- <bibliomisc><ulink url="http://www.sgi.com/tech/stl/">www.sgi.com/tech/stl/</ulink></bibliomisc>
- </biblioentry>
-
- <biblioentry id="cit:c++:98">
- <abbrev>C++98</abbrev>
- <title>International Standard, Programming Languages – C++</title>
- <subtitle>ISO/IEC:14882</subtitle>
- <pubdate>1998</pubdate>
- </biblioentry>
- <biblioentry id="cit:jarvi:99">
- <abbrev>Jär99</abbrev>
- <articleinfo>
- <author>
- <surname>Järvi</surname>
- <firstname>Jaakko</firstname>
- </author>
- <title>C++ Function Object Binders Made Easy</title>
- </articleinfo>
- <title>Lecture Notes in Computer Science</title>
- <volumenum>1977</volumenum>
- <publishername>Springer</publishername>
- <pubdate>2000</pubdate>
- </biblioentry>
- <biblioentry id="cit:jarvi:00">
- <abbrev>Jär00</abbrev>
- <author>
- <surname>Järvi</surname>
- <firstname>Jaakko</firstname>
- </author>
- <author>
- <firstname>Gary</firstname>
- <surname>Powell</surname>
- </author>
- <title>The Lambda Library : Lambda Abstraction in C++</title>
- <orgname>Turku Centre for Computer Science</orgname>
- <bibliomisc>Technical Report </bibliomisc>
- <issuenum>378</issuenum>
- <pubdate>2000</pubdate>
- <bibliomisc><ulink url="http://www.tucs.fi/Publications/techreports/TR378.php">www.tucs.fi/publications</ulink></bibliomisc>
- </biblioentry>
- <biblioentry id="cit:jarvi:01">
- <abbrev>Jär01</abbrev>
- <author>
- <surname>Järvi</surname>
- <firstname>Jaakko</firstname>
- </author>
- <author>
- <firstname>Gary</firstname>
- <surname>Powell</surname>
- </author>
- <title>The Lambda Library : Lambda Abstraction in C++</title>
- <confgroup>
- <conftitle>Second Workshop on C++ Template Programming</conftitle>
- <address>Tampa Bay, OOPSLA'01</address>
- </confgroup>
- <pubdate>2001</pubdate>
- <bibliomisc><ulink url="http://www.oonumerics.org/tmpw01/">www.oonumerics.org/tmpw01/</ulink></bibliomisc>
- </biblioentry>
- <biblioentry id="cit:jarvi:03">
- <abbrev>Jär03</abbrev>
- <articleinfo>
- <author>
- <surname>Järvi</surname>
- <firstname>Jaakko</firstname>
- </author>
- <author>
- <firstname>Gary</firstname>
- <surname>Powell</surname>
- </author>
- <author>
- <firstname>Andrew</firstname>
- <surname>Lumsdaine</surname>
- </author>
- <title>The Lambda Library : unnamed functions in C++</title>
- </articleinfo>
- <title>Software - Practice and Expreience</title>
- <volumenum>33:259-291</volumenum>
- <pubdate>2003</pubdate>
- </biblioentry>
- <biblioentry id="cit:boost::tuple">
- <abbrev>tuple</abbrev>
- <title>The Boost Tuple Library</title>
- <bibliomisc><ulink url="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">www.boost.org/libs/tuple/doc/tuple_users_guide.html</ulink>
- </bibliomisc>
- <pubdate>2002</pubdate>
- </biblioentry>
- <biblioentry id="cit:boost::type_traits">
- <abbrev>type_traits</abbrev>
- <title>The Boost type_traits</title>
- <bibliomisc><ulink url="http://www.boost.org/libs/type_traits/index.htm">www.boost.org/libs/type_traits/</ulink>
- </bibliomisc>
- <pubdate>2002</pubdate>
- </biblioentry>
- <biblioentry id="cit:boost::ref">
- <abbrev>ref</abbrev>
- <title>Boost ref</title>
- <bibliomisc><ulink url="http://www.boost.org/libs/bind/ref.html">www.boost.org/libs/bind/ref.html</ulink>
- </bibliomisc>
- <pubdate>2002</pubdate>
- </biblioentry>
- <biblioentry id="cit:boost::bind">
- <abbrev>bind</abbrev>
- <title>Boost Bind Library</title>
- <bibliomisc><ulink url="http://www.boost.org/libs/bind/bind.html">www.boost.org/libs/bind/bind.html</ulink>
- </bibliomisc>
- <pubdate>2002</pubdate>
- </biblioentry>
- <biblioentry id="cit:boost::function">
- <abbrev>function</abbrev>
- <title>Boost Function Library</title>
- <bibliomisc><ulink url="http://www.boost.org/libs/function/">www.boost.org/libs/function/</ulink>
- </bibliomisc>
- <pubdate>2002</pubdate>
- </biblioentry>
- <biblioentry id="cit:fc++">
- <abbrev>fc++</abbrev>
- <title>The FC++ library: Functional Programming in C++</title>
- <author>
- <surname>Smaragdakis</surname>
- <firstname>Yannis</firstname>
- </author>
- <author>
- <firstname>Brian</firstname>
- <surname>McNamara</surname>
- </author>
- <bibliomisc><ulink url="http://yanniss.github.io/fc++/">yanniss.github.io/fc++/ </ulink>
- </bibliomisc>
- <pubdate>2002</pubdate>
- </biblioentry>
- </bibliography>
- </library>
|