users_manual.qbk
来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 1,963 行 · 第 1/5 页
QBK
1,963 行
[library Phoenix [quickbook 1.3] [version 2.0] [authors [de Guzman, Joel], [Marsden, Dan]] [copyright 2002 2003 2004 2005 Joel de Guzman, Dan Marsden] [category string-text] [purpose Lambda Expressions in C++] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at [@http://www.boost.org/LICENSE_1_0.txt]) ]][/ September 2002][/ September 2004][/ September 2005][/ Some links][def __note__ [$images/note.png]][def __alert__ [$images/alert.png]][def __tip__ [$images/tip.png]][def __spirit__ [@http://spirit.sourceforge.net Spirit]][def __haskell__ [@http://www.haskell.org Haskell]][def __mpl__ [@http://www.boost.org/libs/mpl/index.html MPL]][def __bll__ [@http://www.boost.org/libs/lambda/doc/index.html BLL]][def __fcpp__ [@http://www.cc.gatech.edu/~yannis/fc++/ FC++]][def __spirit_repo__ [@http://spirit.sourceforge.net/repository/applications/show_contents.php Spirit Repository]][def __spirit_list__ [@https://lists.sourceforge.net/lists/listinfo/spirit-general Spirit Mailing List]][def __spirit_general__ [@news://news.gmane.org/gmane.comp.spirit.general Spirit General NNTP news portal]][def __gmane__ [@http://www.gmane.org Gmane]][def __mlist_archive__ [@http://news.gmane.org/gmane.comp.parsers.spirit.general]][def __forwarding__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm Forwarding Function Problem]][def __boost_mpl__ [@http://boost.org/libs/mpl/doc/index.html Boost.MPL]][def __boost_range__ [@http://boost.org/libs/range/index.html Boost.Range]][section Preface][:['Functional programming is so called because a program consists entirely offunctions. The main program itself is written as a function which receives theprogram's input as its argument and delivers the program's output as its result.Typically the main function is defined in terms of other functions, which inturn are defined in terms of still more functions until at the bottom level thefunctions are language primitives.]][:*John Hughes*-- /Why Functional Programming Matters/][$images/lambda_cpp.png][h2 Description]Phoenix enables Functional Programming (FP) in C++. The design andimplementation of Phoenix is highly influenced by __fcpp__ by Yannis Smaragdakisand Brian McNamara and the __bll__ (Boost Lambda Library) by Jaakko Jaarvi andGary Powell. Phoenix is a blend of FC++ and BLL using the implementationtechniques used in the __spirit__ inline parser. Phoenix version 2, thisversion, will probably be the last release of the library. Phoenix v2 will bethe basis of the Phoenix and __bll__ merger.Phoenix is a header only library. It is extremely modular by design. One canextract and use only a small subset of the full library, literally tearing thelibrary into small pieces, without fear that the pieces won't work anymore. Thelibrary is organized in highly independent modules and layers.[h2 How to use this manual]The Phoenix library is organized in logical modules. This documentationprovides a user's guide and reference for each module in the library. A simpleand clear code example is worth a hundred lines of documentation; therefore, theuser's guide is presented with abundant examples annotated and explained instep-wise manner. The user's guide is based on examples: lots of them.As much as possible, forward information (i.e. citing a specific piece ofinformation that has not yet been discussed) is avoided in the user's manualportion of each module. In many cases, though, it is unavoidable that advancedbut related topics not be interspersed with the normal flow of discussion. Toalleviate this problem, topics categorized as "advanced" may be skipped at firstreading.Some icons are used to mark certain topics indicative of their relevance. Theseicons precede some text to indicate:[table Icons [[Icon] [Name] [Meaning]] [[__note__] [Note] [Information provided is auxiliary but will give the reader a deeper insight into a specific topic. May be skipped.]] [[__alert__] [Alert] [Information provided is of utmost importance.]] [[__tip__] [Tip] [A potentially useful and helpful piece of information.]]]This documentation is automatically generated by Spirit QuickBook documentationtool. QuickBook can be found in the __spirit_repo__.[h2 Support]Please direct all questions to Spirit's mailing list. You can subscribe to the__spirit_list__. The mailing list has a searchable archive. A search link tothis archive is provided in __spirit__'s home page. You may also read and postmessages to the mailing list through __spirit_general__ (thanks to __gmane__).The news group mirrors the mailing list. Here is a link to the archives:__mlist_archive__.[h2 [*/...To my dear daughter, Phoenix/]][endsect][section Introduction][$images/banner.png]The Phoenix library enables FP techniques such as higher order functions,/lambda/ (unnamed functions), /currying/ (partial function application) and lazyevaluation in C++. The focus is more on usefulness and practicality than purity,elegance and strict adherence to FP principles.FP is a programming discipline that is not at all tied to a specific language.FP as a programming discipline can, in fact, be applied to many programminglanguages. In the realm of C++ for instance, we are seeing more FP techniquesbeing applied. C++ is sufficiently rich to support at least some of the mostimportant facets of FP. C++ is a multiparadigm programming language. It is notonly procedural. It is not only object oriented. Beneath the core of thestandard C++ library, a closer look into STL gives us a glimpse of FP already inplace. It is obvious that the authors of STL know and practice FP. In the nearfuture, we shall surely see more FP trickle down into the mainstream.The truth is, most of the FP techniques can coexist quite well with the standardobject oriented and imperative programming paradigms. When we are using STLalgorithms and functors (function objects) for example, we are already doing FP.Phoenix is an evolutionary next step.[endsect][section Starter Kit]Most "quick starts" only get you a few blocks from where you are. From there,you are on your own. Yet, typically, you'd want to get to the next city. Thisstarter kit shall be as minimal as possible, yet packed as much power aspossible.So you are busy and always on the go. You do not wish to spend a lot of timestudying the library. You wish to be spared the details for later when you needit. For now, all you need to do is to get up to speed as quickly as possible andstart using the library. If this is the case, this is the right place to start.This chapter is by no means a thorough discourse of the library. For moreinformation on Phoenix, please take some time to read the rest of the User'sGuide. Yet, if you just want to use the library quickly, now, this chapter willprobably suffice. Rather than taking you to the details of the library, we shalltry to provide you with annotated exemplars instead. Hopefully, this will getyou into high gear quickly.[h2 Functors everywhere]Phoenix is built on function objects (functors). The functor is the mainbuilding block. We compose functors to build more complex functors... to buildmore complex functors... and so on. Almost everything is a functor.[note Functors are so ubiquitous in Phoenix that, in the manual, thewords /"functor"/ and /"function"/ are used interchangeably.][section Values]Values are functions! Examples: val(3) val("Hello, World")The first evaluates to a nullary function (a function taking no arguments) thatreturns an `int`, `3`. The second evaluates to a nullary function that returnsa `char const(&)[13]`, `"Hello, World"`.[h2 Lazy Evaluation]Confused? `val(3)` is a unary function, you say? Yes it is. However, readcarefully: /"evaluates to a nullary function"/. `val(3)` evaluates to (returns) anullary function. Aha! `val(3)` returns a function! So, since `val(3)` returns afunction, you can invoke it. Example: cout << val(3)() << endl;(See [@../../example/users_manual/values.cpp values.cpp])[blurb __tip__ Learn more about values [link phoenix.primitives.values here.]]The second function call (the one with no arguments) calls the nullary functionwhich then returns `3`. The need for a second function call is the reason whythe function is said to be [*/Lazily Evaluated/]. The first call doesn't doanything. You need a second call to finally evaluate the thing. The first calllazily evaluates the function; i.e. doesn't do anything and defers the evaluationfor later.[h2 Callbacks]It may not be immediately apparent how lazy evaluation can be useful by justlooking at the example above. Putting the first and second function call in asingle line is really not very useful. However, thinking of `val(3)` as acallback function (and in most cases they are actually used that way), will makeit clear. Example: template <typename F> void print(F f) { cout << f() << endl; } int main() { print(val(3)); print(val("Hello World")); return 0; }(See [@../../example/users_manual/callback.cpp callback.cpp])[endsect][section References]References are functions. They hold a reference to a value stored somehere.For example, given: int i = 3; char const* s = "Hello World";we create `references` to `i` and `s` this way: ref(i) ref(s)Like `val`, the expressions above evaluates to a nullary function; the first onereturning an `int&`, and the second one returning a `char const*&`.(See [@../../example/users_manual/references.cpp references.cpp])[blurb __tip__ Learn more about references [link phoenix.primitives.references here.]][endsect][section Arguments]Arguments are also functions? You bet!Until now, we have been dealing with expressions returning a nullary function.Arguments, on the other hand, evaluate to an N-ary function. An argumentrepresents the Nth argument. There are a few predefined arguments arg1,arg2, arg3, arg4 and so on (and it's __bll__ counterparts: _1, _2, _3, _4 and soon). Examples: arg1 // one-or-more argument function that returns its first argument arg2 // two-or-more argument function that returns its second argument arg3 // three-or-more argument function that returns its third argument`argN` returns the Nth argument. Examples: int i = 3; char const* s = "Hello World"; cout << arg1(i) << endl; // prints 3 cout << arg2(i, s) << endl; // prints "Hello World"(See [@../../example/users_manual/arguments.cpp arguments.cpp])[blurb __tip__ Learn more about arguments [link phoenix.primitives.arguments here.]][endsect][section Composites]What we have seen so far, are what are called *primitives*. You can think ofprimitives (such as values, references and arguments) as atoms.Things start to get interesting when we start /composing/ primitives to form*composites*. The composites can, in turn, be composed to form even more complexcomposites.[endsect][section Lazy Operators]You can use the usual set of operators to form composites. Examples: arg1 * arg1 ref(x) = arg1 + ref(z) arg1 = arg2 + (3 * arg3) ref(x) = arg1[arg2] // assuming arg1 is indexable and arg2 is a valid indexNote the expression: `3 * arg3`. This expression is actually a short-handequivalent to: `val(3) * arg3`. In most cases, like above, you can get away withit. But in some cases, you will have to explicitly wrap your values in `val`.Rules of thumb:* In a binary expression (e.g. `3 * arg3`), at least one of the operands must be a phoenix primitive or composite.* In a unary expression (e.g. `arg1++`), the single operand must be a phoenix primitive or composite.If these basic rules are not followed, the result is either in error, or isimmediately evaluated. Some examples: ref(x) = 123 // lazy x = 123 // immediate ref(x)[0] // lazy x[0] // immediate ref(x)[ref(i)] // lazy ref(x)[i] // lazy (equivalent to ref(x)[val(i)]) x[ref(i)] // illegal (x is not a phoenix primitive or composite) ref(x[ref(i)]) // illegal (x is not a phoenix primitive or composite)[blurb __tip__ Learn more about operators [link phoenix.composite.operator here.]][h2 First Practical Example]We've covered enough ground to present a real world example. We want to find thefirst odd number in an STL container. Normally we use a functor (functionobject) or a function pointer and pass that in to STL's `find_if` genericfunction:Write a function: bool is_odd(int arg1) { return arg1 % 2 == 1; }Pass a pointer to the function to STL's `find_if` algorithm: find_if(c.begin(), c.end(), &is_odd)Using Phoenix, the same can be achieved directly with a one-liner: find_if(c.begin(), c.end(), arg1 % 2 == 1)The expression `arg1 % 2 == 1` automagically creates a functor with the expectedbehavior. In FP, this unnamed function is called a lambda function. Unlike thefunction pointer version, which is monomorphic (expects and works only with afixed type int argument), the Phoenix version is fully polymorphic and workswith any container (of ints, of longs, of bignum, etc.) as long as its elementscan handle the `arg1 % 2 == 1` expression.(See [@../../example/users_manual/find_if.cpp find_if.cpp])[blurb __tip__ ...[*That's it, we're done]. Well if you wish to know a little bitmore, read on...][endsect][section Lazy Statements]Lazy statements? Sure. There are lazy versions of the C++ statements we all knowand love. For example: if_(arg1 > 5) cout << arg1Say, for example, we wish to print all the elements that are greater than 5(separated by a comma) in a vector. Here's how we write it: for_each(v.begin(), v.end(), if_(arg1 > 5) [ cout << arg1 << ", " ] );(See [@../../example/users_manual/if.cpp if.cpp])[blurb __tip__ Learn more about statements [link phoenix.composite.statement here.]][endsect][section Construct, New, Delete, Casts]You'll probably want to work with objects. There are lazy versions ofconstructor calls, `new`, `delete` and the suite of C++ casts. Examples: construct<std::string>(arg1, arg2) // constructs a std::string from arg1, arg2 new_<std::string>(arg1, arg2) // makes a new std::string from arg1, arg2 delete_(arg1) // deletes arg1 (assumed to be a pointer) static_cast_<int*>(arg1) // static_cast's arg1 to an int*[note Take note that, by convention, names that conflict with C++reserved words are appended with a single trailing underscore `'_'`][blurb __tip__ Learn more about this [link phoenix.composite.object here.]][endsect][section Lazy Functions]As you write more lambda functions, you'll notice certain patterns that you wishto refactor as reusable functions. When you reach that point, you'll wish thatordinary functions can co-exist with phoenix functions. Unfortunately, the/immediate/ nature of plain C++ functions make them incompatible.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?