users_manual.qbk

来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 1,963 行 · 第 1/5 页

QBK
1,963
字号
    A    123    Hello World[h2 Extra Arguments]In C and C++, a function can have extra arguments that are not at all used bythe function body itself. These extra arguments are simply ignored.Phoenix also allows extra arguments to be passed. For example, recall ouroriginal `add` function:    add(arg1, arg2)We know now that partially applying this function results to a function thatexpects 2 arguments. However, the library is a bit more lenient and allows thecaller to supply more arguments than is actually required. Thus, `add` actuallyallows 2 /or more/ arguments. For instance, with:    add(arg1, arg2)(x, y, z)the third argument `z` is ignored. Taking this further, in-between arguments arealso ignored. Example:    add(arg1, arg5)(a, b, c, d, e)Here, arguments b, c, and d are ignored. The function `add` takes in the firstargument (`arg1`) and the fifth argument (`arg5`).[note There are a few reasons why enforcing strict arity is notdesireable. A case in point is the callback function. Typical callback functionsprovide more information than is actually needed. Lambda functions are oftenused as callbacks.][endsect][section Values]    #include <boost/spirit/home/phoenix/core/value.hpp>Whenever we see a constant in a partially applied function, an    actor<value<T> >(where T is the type of the constant) is automatically created forus. For instance:    add(arg1, 6)Passing a second argument, `6`, an `actor<value<int> >` is implicitly createdbehind the scenes. This is also equivalent to:    add(arg1, val(6))`val(x)` generates an `actor<value<T> >` where `T` is the type of `x`. In mostcases, there's no need to explicitly use `val`, but, as we'll see later on,there are situations where this is unavoidable.[h2 Evaluating a Value]Like arguments, values are also actors. As such, values can be evaluated.Invoking a value gives the value's identity. Example:    cout << val(3)() << val("Hello World")();prints out "3 Hello World".[endsect][section References]    #include <boost/spirit/home/phoenix/core/reference.hpp>Values are immutable constants. Attempting to modify a value will result in acompile time error. When we want the function to modify the parameter, we use areference instead. For instance, imagine a lazy function `add_assign`:    void add_assign(T& x, T y) { x += y; } // pseudo codeHere, we want the first function argument, x, to be mutable. Obviously, wecannot write:    add_assign(1, 2) // error first argument is immutableIn C++, we can pass in a reference to a variable as the first argument in ourexample above. Yet, by default, the library forces arguments passed to partiallyapplied functions functions to be immutable values (see [link phoenix.primitives.valuesValues]). To achieve our intent, we use:    actor<reference<T> >This is similar to `actor<value<T> >` above but instead holds a reference to avariable.We normally don't instantiate `actor<reference<T> >` objects directly. Instead weuse `ref`. For example (where `i` is an `int` variable):    add_assign(ref(i), 2)[h2 Evaluating a Reference]References are actors. Hence, references can be evaluated. Such invocation givesthe references's identity. Example:    int i = 3;    char const* s = "Hello World";    cout << ref(i)() << ref(s)();prints out "3 Hello World"[endsect][section Constant References]    #include <boost/spirit/home/phoenix/core/reference.hpp>Another free function `cref(cv)` may also be used. `cref(cv)` creates an`actor<reference<T const&> >` object. This is similar to `actor<value<T> >` butwhen the data to be passed as argument to a function is heavy and expensive tocopy by value, the `cref(cv)` offers a lighter alternative.[endsect][section Nothing]    #include <boost/spirit/home/phoenix/core/nothing.hpp>Finally, the `actor<null_actor>` does nothing; (a "bum", if you will :-).There's a sole `actor<null_actor>` instance named "nothing". This actor isactually useful in situations where we don't want to do anything. (See[link phoenix.composite.statement.for__statement for_ Statement] for example).[endsect][endsect][section Composite]Actors may be combined in a multitude of ways to form composites. Composites areactors that are composed of zero or more actors. Composition is hierarchical. Anelement of the composite can be a primitive or again another composite. Theflexibility to arbitrarily compose hierarchical structures allows us to formintricate constructions that model complex functions, statements andexpressions.A composite is-a tuple of 0..N actors. N is the predefined maximum actors acomposite can take.[note You can set `PHOENIX_COMPOSITE_LIMIT`, the predefined maximumactors a composite can take. By default, `PHOENIX_COMPOSITE_LIMIT` is set to`PHOENIX_LIMIT` (See [link phoenix.actors Actors]).]As mentioned, each of the actors A0..AN can, in turn, be another composite,since a composite is itself an actor. This makes the composite a recursivestructure. The actual evaluation is handled by a composite specific eval policy.[section Function]    #include <boost/spirit/home/phoenix/function/function.hpp>The `function` class template provides a mechanism for implementing lazilyevaluated functions. Syntactically, a lazy function looks like an ordinary C/C++ function.The function call looks familiar and feels the same as ordinary C++ functions.However, unlike ordinary functions, the actual function execution is deferred.Unlike ordinary function pointers or functor objects that need to be explicitly bound through the bind function (see [link phoenix.composite.bind Bind]),the argument types of these functions are automatically lazily bound.In order to create a lazy function, we need to implement a model of theFunctionEval concept. For a function that takes `N` arguments, a model of FunctionEval mustprovide:* An `operator()` that implements that takes `N` arguments, and implementsthe function logic.* A nested metafunction `result<A1, ... AN>` that takes the types of the `N` arguments tothe function and returns the result type of the function. (There is a special case for functionobjects that accept no arguments. Such nullary functors are only required to define a typedef`result_type` that reflects the return type of its `operator()`).For example, the following type implements the FunctionEval concept, in order to provide alazy factorial function:    struct factorial_impl    {        template <typename Arg>        struct result        {            typedef Arg type;        };        template <typename Arg>        Arg operator()(Arg n) const        {            return (n <= 0) ? 1 : n * this->operator()(n-1);        }    };(See [@../../example/users_manual/factorial.cpp factorial.cpp])Having implemented the `factorial_impl` type, we can declare and instantiate a lazy`factorial` function this way:    function<factorial_impl> factorial;Invoking a lazy function such as `factorial` does not immediately execute the functionobject `factorial_impl`. Instead, an [link phoenix.actors actor] object iscreated and returned to the caller. Example:    factorial(arg1)does nothing more than return an actor. A second function call will invokethe actual factorial function. Example:    int i = 4;    cout << factorial(arg1)(i);will print out "24".Take note that in certain cases (e.g. for function objects with state), aninstance of the model of FunctionEval may be passed on to the constructor. Example:    function<factorial_impl> factorial(ftor);where ftor is an instance of factorial_impl (this is not necessary in this caseas `factorial_impl` does not require any state).[blurb __alert__ Take care though when using function objects with state because they areoften copied repeatedly, and state may change in one of the copies, rather than theoriginal.][endsect][section Operator]This facility provides a mechanism for lazily evaluating operators.Syntactically, a lazy operator looks and feels like an ordinary C/C++ infix,prefix or postfix operator. The operator application looks the same. However,unlike ordinary operators, the actual operator execution is deferred. Samples:    arg1 + arg2    1 + arg1 * arg2    1 / -arg1    arg1 < 150We have seen the lazy operators in action (see [link phoenix.starter_kitQuick Start]). Let's go back and examine them a little bit further:    find_if(c.begin(), c.end(), arg1 % 2 == 1)Through operator overloading, the expression `arg1 % 2 == 1` actually generatesan actor. This actor object is passed on to STL's `find_if` function. Fromthe viewpoint of STL, the composite is simply a function object expecting asingle argument of the containers value_type. For each element in `c`,the element is passed on as an argument `arg1` to the actor (functionobject). The actor checks if this is an odd value based on the expression`arg1 % 2 == 1` where arg1 is replaced by the container's element.Like lazy functions (see[link phoenix.composite.function function]), lazy operators are not immediately executedwhen invoked. Instead, an actor (see [link phoenix.actors actors])object is created and returned to the caller. Example:    (arg1 + arg2) * arg3does nothing more than return an actor. A second function call will evaluatethe actual operators. Example:    int i = 4, j = 5, k = 6;    cout << ((arg1 + arg2) * arg3)(i, j, k);will print out "54".Operator expressions are lazily evaluated following four simple rules:# A binary operator, except `->*` will be lazily evaluated when  /at least/ one of its operands is an actor object  (see [link phoenix.actors actors]).# Unary operators are lazily evaluted if their argument is an actor object.# Operator `->*` is lazily evaluted if the left hand argument is an actor object.# The result of a lazy operator is an actor object that can in turn allow the  applications of rules 1 and 2.For example, to check the following expression is lazily evaluated:    -(arg1 + 3 + 6)# Following rule 1, `arg1 + 3` is lazily evaluated since `arg1` is an actor  (see [link phoenix.primitives primitives]).# The result of this `arg1 + 3` expression is an actor object, following rule 4.# Continuing, `arg1 + 3 + 6` is again lazily evaluated.  Rule 2.# By rule 4 again, the result of  `arg1 + 3 + 6` is an actor object.# As `arg1 + 3 + 6` is an actor, `-(arg1 + 3 + 6)` is lazily evaluated. Rule 2.Lazy-operator application is highly contagious. In most cases, a single `argN`actor infects all its immediate neighbors within a group (first level orparenthesized expression).Note that at least one operand of any operator must be a valid actorfor lazy evaluation to take effect.  To force lazy evaluation of anordinary expression, we can use `ref(x)`, `val(x)` or `cref(x)` totransform an operand into a valid actor object (see [link phoenix.primitives primitives].For example:     1 << 3;      // Immediately evaluated     val(1) << 3; // Lazily evaluated[h2 Supported operators][h3 Unary operators]    prefix:   ~, !, -, +, ++, --, & (reference), * (dereference)    postfix:  ++, --[h3 Binary operators]    =, [], +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=    +, -, *, /, %, &, |, ^, <<, >>    ==, !=, <, >, <=, >=    &&, ||, ->*[h3 Ternary operator]    if_else(c, a, b)The ternary operator deserves special mention. Since C++ does not allow us tooverload the conditional expression: `c ? a : b`, the if_else pseudo function isprovided for this purpose. The behavior is identical, albeit in a lazy manner.[h3 Member pointer operator]    a->*member_object_pointer    a->*member_function_pointerThe left hand side of the member pointer operator must be an actor returning a pointertype. The right hand side of the member pointer operator may be either a pointer to memberobject or pointer to member function.If the right hand side is a member object pointer, the result is an actor which, when evaluated,returns a reference to that member. For example:    struct A    {        int member;    };    A* a = new A;    ...    (arg1->*&A::member)(a); // returns member a->memberIf the right hand side is a member function pointer, the result is an actor which, when invoked, calls the specified member function. For example:    struct A    {        int func(int);    };    A* a = new A;    int i = 0;    (arg1->*&A::func)(arg2)(a, i); // returns a->func(i)[table Include Files    [[Operators]                    [File]]    [[`-`, `+`, `++`, `--`, `+=`,      `-=`, `*=`, `/=`, `%=`,      `*`, `/`, `%`]                [`#include <boost/spirit/home/phoenix/operator/arithmetic.hpp>`]]    [[`&=`, `|=`, `^=`, `<<=`,      `>>=`, `&`, `|`, `^`, `<<`,      `>>`]                         [`#include <boost/spirit/home/phoenix/operator/bitwise.hpp>`]]    [[`==`, `!=`, `<`,      `<=`, `>`, `>=`]              [`#include <boost/spirit/home/phoenix/operator/comparison.hpp>`]]    [[`<<`, `>>`]                   [`#include <boost/spirit/home/phoenix/operator/io.hpp>`]]    [[`!`, &&, `||`]                [`#include <boost/spirit/home/phoenix/operator/logical.hpp>`]]    [[`&x`, `*p`, `=`, `[]`]        [`#include <boost/spirit/home/phoenix/operator/self.hpp>`]]    [[`if_else(c, a, b)`]           [`#include <boost/spirit/home/phoenix/operator/if_else.hpp>`]]    [[`->*`]                        [`#include <boost/spirit/home/phoenix/operator/member.hpp>`]]][endsect][section Statement][*/Lazy statements.../]The primitives and composite building blocks presented so far are sufficientlypowerful to construct quite elaborate structures. We have presented lazy-functions and lazy-operators. How about lazy-statements? First, an appetizer:Print all odd-numbered contents of an STL container using `std::for_each`([@../../example/users_manual/all_odds.cpp all_odds.cpp]):    for_each(c.begin(), c.end(),

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?