transforms.qbk

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

QBK
1,417
字号
The target of a callable transform can be any function object that implementsthe Boost.ResultOf protocol. Function objects that take up to`BOOST_PROTO_MAX_ARITY` are handled.For callable transforms that take 0, 1, or 2 arguments, special handling is done to see if the transform actually expects 3 arguments, as Proto's primitive transforms do. (This can be detected with meta-programming tricks.) So, even though a transform like `_arg1` requires three parameters: expression, state and visitor; it can be "called" with just one, like `_arg1(_arg2)`. Prototreats this as if were `call<_arg1(_arg2, _state, _visitor)>`.If no transform arguments are specified at all, as in `call<_arg1>`, this isthe same as `_arg1`. For this reason, `call<_arg1>(_arg2)` is the same as`call<_arg1(_arg2)>`.Example:[LazyMakePair2][endsect][section:make [^make<>]]    namespace boost { namespace proto    {        namespace transform        {            template<typename Fun>            struct make;        }        using transform::make;    }}The `make<>` transform is used to construct objects and evaluatetheir constructor arguments. When you use an object transform as in `when< posit<_>, Object(_arg) >`, the `make<>` transform is used behindthe scenes to evaluate `Object(_arg)`. In fact, for any objecttransform, the following short- and long-forms are equivalent:[table    [ [Short From]      [Long Form] ]    [ [ `when< Grammar, Object(Tran1, Tran2...) >` ]      [ `when< Grammar, make< Object(Tran1, Tran2...) > >` ] ]]You might decide to use `make<>` to explicitly differentiate objecttransforms from callable transforms. (See `call<>`.)[tip For users of legacy compilers like MSVC 7.1, `make<>` is useful to workaround compiler bugs. Doubly-nested transforms such as `Object1(Object2(_arg))`cause older compilers problems, but the equivalent `Object1(make<Object2(_arg)>)`solves the problem.]The `make<>` transform checks to see if the resulting object type is a template.If it is, the template type is disassembled to find nested transforms. Protoconsiders the following types to represent transforms:[def __type__ [~type]][def __X__  X\'][def __X0__ X0\'][def __X1__ X1\']* Function types* Function pointer types* Types for which `proto::is_callable<__type__>::value` is `true`When an object transform with a template type such as`Object<X0,X1,...>(Args...)` is evaluated with a given`Expr`, `State`, and `Visitor`, the result type is `make_<Object<X0,X1,...>, Expr, State, Visitor>::type` which isdefined as follows. For each `X` in `X0,X1,...`, do:* If `X` is a template like `Object2<Y0,Y1,...>`, then let `__X__`  be `make_<Object2<Y0,Y1,...>, Expr, State, Visitor>::type`  (which evaluates this procedure recursively). Note whether any  substitutions took place during this operation.* Otherwise, if `X` is a transform, then let `__X__` be  `when<_, X>::result<void(Expr, State, Visitor)>::type`.  Note that a substitution took place.* Otherwise, let `__X__` be `X`, and note that no substitution  took place.* If any substitutions took place in any of the above steps and  `Object<__X0__,__X1__,...>` has a nested `::type` typedef, the  result type is `Object<__X0__,__X1__,...>::type`.* Otherwise, the result type is `Object<__X0__,__X1__,...>`.Note that `when<>` is implemented in terms of `call<>` and `make<>`,so the above procedure is evaluated recursively.Given the above description of the `make_<>` helper, the semanticsof the `make<>` transform is described as follows:[def __AN__ A[~N]][table    [   [Expression]        [Returns]    ]    [   [`make<Object(A0, A1, ... __AN__)>::result<void(Expr, State, Visitor)>::type`]        [`make_<Object, Expr, State, Visitor>::type`]    ]    [   [`make<Object(A0, A1, ... __AN__)>()(expr, state, visitor)`]        [``make_<Object, Expr, State, Visitor>::type(    when<_, A0>()(expr, state, visitor)  , when<_, A1>()(expr, state, visitor)    ...  , when<_, __AN__>()(expr, state, visitor))``]    ]]Objects with constructors that take up to `BOOST_PROTO_MAX_ARITY` are handled.Some types are so-called /aggregates/ that do not have constructors; rather,they use /aggregate initialization/. For these types, you can specialize `proto::is_aggregate<>` and Proto will use a brace initializer list toinitialize the object rather than a constructor. Proto knows that `proto::expr<>`is such an aggregate, so if you use object transforms to "construct" anew node in an expression tree, the right thing happens.If no transform arguments are specified at all, as in `make<Object>`, this isthe same as `make<Object()>`.Example:[LazyMakePair][endsect][section:bind [^bind<>]]    namespace boost { namespace proto    {        namespace transform        {            template<typename Fun>            struct bind;        }        using transform::bind;    }}Sometimes you would like a higher-order transform that returns anothertransform to be evaluated. This can happen when you have a transformwhose behavior needs to be parameterized on the current state of thetransformation. For these situations, you can use the `bind<>` transform,which is essentially an invocation of the `make<>` transform (to evaluateany nested transforms and create the higher-order transform) followedby an invocation of `call<>` (to actually execute the higher-ordertransform).The behavior of `bind<>` is easily specified in terms of `make<>` and`call<>`.[table    [   [Expression]        [Returns]    ]    [   [`bind<Object(A0, A1, ... __AN__)>::result<void(Expr, State, Visitor)>::type`]        [``call<    make<Object>::result<void(Expr, State, Visitor)>::type(A0, A1, ... __AN__)>::result<void(Expr, State, Visitor)>::type``]    ]    [   [`bind<Object(A0, A1, ... __AN__)>()(expr, state, visitor)`]        [``call<    make<Object>::result<void(Expr, State, Visitor)>::type(A0, A1, ... __AN__)>()(expr, state, visitor)``]    ]]If no transform arguments are specified at all, as in `bind<Object>`, this isthe same as `bind<Object(_expr, _state, _visitor)>`.[endsect][section:when [^when<>]]    namespace boost { namespace proto    {        namespace transform        {            template<typename Grammar, typename Transform = Grammar>            struct when;        }        using transform::when;    }}`when<>` associates a grammar rule with a transform. It can be usedin a grammar in place of the rule; that is, it behaves as a grammarrule. Expression tree nodes that match the grammar rule are processedwith the associated transform; that is, `when<>` also behaves likea transform.When no transform is specified, as with `when< posit<Calculator> >`,the grammar is treated as the transform. Every grammar element hasa default transform. For most, such as `posit<>`, the default transformis `pass_through<>`.The `when<>` transform is easily specified in terms of `call<>`,`make<>`, and the `is_callable<>` trait.[table    [   [Expression]        [Returns]    ]    [   [`when<Grammar, R(A0, A1, ... __AN__)>::result<void(Expr, State, Visitor)>::type`]        [``mpl::if_<    is_callable<R>  , call<R(A0, A1, ... __AN__)>  , make<R(A0, A1, ... __AN__)>>::type::result<void(Expr, State, Visitor)>::type``]    ]    [   [`when<Grammar, R(A0, A1, ... __AN__)>()(expr, state, visitor)`]        [``mpl::if_<    is_callable<R>  , call<R(A0, A1, ... __AN__)>  , make<R(A0, A1, ... __AN__)>>::type()(expr, state, visitor)``]    ]]If no transform arguments are specified, as in `when<Grammar, _arg>`, thetransform is assumed to be callable; that is, it is equivalent to`when<Grammar, call<_arg> >`.[endsect][section:fold [^fold<>] and [^reverse_fold<>]]    namespace boost { namespace proto    {        namespace transform        {            template<typename Sequence, typename State0, typename Fun>            struct fold;            template<typename Sequence, typename State0, typename Fun>            struct reverse_fold;        }        using transform::fold;        using transform::reverse_fold;    }}The transforms `fold<>` and `reverse_fold<>` are akin to the`std::accumulate()` algorithm in the STL, or the `fold()` algorithm inBoost.Fusion. They iterate over some sequence andaccumulate some state at each element. The `fold<>`transform iterates over the children in order, starting with the 0th child.The `reverse_fold<>` transform does it in reverse order, starting with the Nthchild. (Note that for building things like cons lists, you'll often want tobuilt it back-to-front with `reverse_fold<>`.)Both `fold<>` and `reverse_fold<>` are implemented in terms of `fusion::fold<>`.The three template parameters must each be Proto transforms. The have the followingmeaning:* `Sequence`: A Proto transform that returns a Fusion sequence.* `State`: A Proto transform that returns the initial state of the fold.* `Fun`: A Proto transform representing the operation to perform at each  iteration of the fold algorithm.Often, the `Sequence` parameter is `proto::_`, which returns the current nodein the Proto expression tree. Tree nodes are valid Fusion sequences, wherethe children are the elements of the sequence.The semantics of the `fold<>` and `reverse_fold<>` transforms can both beunderstood in terms of a helper struct, `as_callable<>`, which binds thevisitor and the `Fun` transform into a binary function object for use by`fusion::fold()`. `as_callable<>` has the following behavior:[table    [   [Expression]        [Returns]    ]    [   [`as_callable<Fun, Visitor>::result<void(Expr, State)>::type`]        [`when<_, Fun>::result<void(Expr, State, Visitor)>::type`]    ]    [   [`as_callable<Fun, Visitor>(visitor)(expr, state)`]        [`when<_, Fun>()(expr, state, visitor)`]    ]]With the above `as_callable<>` adaptor, `fold<>` and `reverse_fold<>`can be easily implemented in terms of `fusion::fold<>`:[table    [   [Expression]        [Returns]    ]    [   [`fold<Sequence, State0, Fun>::result<void(Expr, State, Visitor)>::type`]        [``fusion::result_of::fold<    when<_, Sequence>::result<void(Expr, State, Visitor)>::type  , when<_, State0>::result<void(Expr, State, Visitor)>::type  , as_callable<Fun, Visitor>>::type``]    ]    [   [`fold<Sequence, State0, Fun>()(expr, state, visitor)`]        [``fusion::fold(    when<_, Sequence>()(expr, state, visitor)  , when<_, State0>()(expr, state, visitor)  , as_callable<Fun, Visitor>(visitor))``]    ]    [   [`reverse_fold<Sequence, State0, Fun>::result<void(Expr, State, Visitor)>::type`]        [``fusion::result_of::fold<    fusion::result_of::reverse<        when<_, Sequence>::result<void(Expr, State, Visitor)>::type    >::type  , when<_, State0>::result<void(Expr, State, Visitor)>::type  , as_callable<Fun, Visitor>>::type``]    ]    [   [`reverse_fold<Sequence, State0, Fun>()(expr, state, visitor)`]        [``fusion::fold(    fusion::reverse(        when<_, Sequence>()(expr, state, visitor)    )  , when<_, State0>()(expr, state, visitor)  , as_callable<Fun, Visitor>(visitor))``]    ]][#reverse_fold_example]Example:[AsArgList][endsect][section:fold_tree [^fold_tree<>] and [^reverse_fold_tree<>]]    namespace boost { namespace proto    {        namespace transform        {            template<typename Sequence, typename State0, typename Fun>            struct fold_tree;            template<typename Sequence, typename State0, typename Fun>            struct reverse_fold_tree;        }        using transform::fold;        using transform::reverse_fold;    }}The `fold_tree<>` and `reverse_fold_tree<>` transforms recursively apply the`fold<>` and `reverse_fold<>` transforms to sub-trees that all share a commontag type. This is useful for flattening trees into lists; for example, youmight use `reverse_fold_tree<>` to flatten an expression tree like `a | b | c`into a Fusion list like `cons(a, cons(b, cons(c)))`.

⌨️ 快捷键说明

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