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 + -
显示快捷键?