![]() |
Home | Libraries | People | FAQ | More |
In previous sections, we've seen how to compose larger transforms out
of smaller transforms using function types. The smaller transforms from
which larger transforms are composed are primitive transforms,
and Proto provides a bunch of common ones such as _child0
and _value
. In this section
we'll see how to author your own primitive transforms.
![]() |
Note |
---|---|
There are a few reasons why you might want to write your own primitive transforms. For instance, your transform may be complicated, and composing it out of primitives becomes unwieldy. You might also need to work around compiler bugs on legacy compilers that make composing transforms using function types problematic. Finally, you might also decide to define your own primitive transforms to improve compile times. Since Proto can simply invoke a primitive transform directly without having to process arguments or differentiate callable transforms from object transforms, primitive transforms are more efficient. |
Primitive transforms inherit from proto::transform<>
and have a nested impl<>
template that inherits from proto::transform_impl<>
. For example, this is how Proto
defines the _child_c<
transform, which returns the N
>N
-th child of
the current expression:
namespace boost { namespace proto { // A primitive transform that returns N-th child // of the current expression. template<int N> struct _child_c : transform<_child_c<N> > { template<typename Expr, typename State, typename Data> struct impl : transform_impl<Expr, State, Data> { typedef typename result_of::child_c<Expr, N>::type result_type; result_type operator ()( typename impl::expr_param expr , typename impl::state_param state , typename impl::data_param data ) const { return proto::child_c<N>(expr); } }; }; // Note that _child_c<N> is callable, so that // it can be used in callable transforms, as: // _child_c<0>(_child_c<1>) template<int N> struct is_callable<_child_c<N> > : mpl::true_ {}; }}
The proto::transform<>
base class provides the operator()
overloads and the nested result<>
template that make your transform a valid function object. These are
implemented in terms of the nested impl<>
template you define.
The proto::transform_impl<>
base class is a convenience. It provides some nested typedefs that are
generally useful. They are specified in the table below:
Table 1.12. proto::transform_impl<Expr, State, Data> typedefs
typedef |
Equivalent To |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
You'll notice that _child_c::impl::operator()
takes arguments of types expr_param
, state_param
,
and data_param
. The typedefs
make it easy to accept arguments by reference or const reference accordingly.
The only other interesting bit is the is_callable<>
specialization, which will be
described in the next
section.