Contains definition of the
proto::make<>
and
proto::protect<>
transforms.
A type annotation in an ObjectTransform which instructs
Proto not to look for a nested ::type within
T after type substitution.
ObjectTransforms are evaluated by
proto::make<>,
which finds all nested transforms and replaces them with the result of their applications.
If any substitutions are performed, the result is first assumed to be a metafunction to be applied;
that is, Proto checks to see if the result has a nested ::type
typedef. If it does, that becomes the result. The purpose of proto::noinvoke<>
is to prevent Proto from looking for a nested ::type typedef
in these situations.
Example:
struct Test
: proto::when<
_
, proto::noinvoke<
// This remove_pointer invocation is bloked by noinvoke
boost::remove_pointer<
// This add_pointer invocation is *not* blocked by noinvoke
boost::add_pointer<_>
>
>()
>
{};
void test_noinvoke()
{
typedef proto::terminal<int>::type Int;
BOOST_MPL_ASSERT((
boost::is_same<
boost::result_of<Test(Int)>::type
, boost::remove_pointer<Int *>
>
));
Int i = {42};
boost::remove_pointer<Int *> t = Test()(i);
}
proto::transform< protect<PrimitiveTransform> >
A PrimitiveTransform which prevents another
PrimitiveTransform from being applied in an
ObjectTransform.
When building higher order transforms with
proto::make<>
or
proto::lazy<>
,
you sometimes would like to build types that are parameterized with Proto transforms. In such
lambda-style transforms, Proto will unhelpfully find all nested transforms and apply them, even
if you don't want them to be applied. Consider the following transform, which will replace the
proto::_ in
Bar<proto::_>()
with proto::terminal<int>::type:
template<typename T>
struct Bar
{};
struct Foo :
proto::when<proto::_, Bar<proto::_>() >
{};
proto::terminal<int>::type i = {0};
int main() {
Foo()(i);
std::cout << typeid(Foo()(i)).name() << std::endl;
}
If you actually wanted to default-construct an object of type
Bar<proto::_>, you would have to protect the
_ to prevent it from being applied. You can
use proto::protect<> as follows:
// OK: replace anything with Bar<_>()
struct Foo :
proto::when<proto::_, Bar<proto::protect<proto::_> >() >
{};
PrimitiveTransform
proto::transform< make<T> >
A PrimitiveTransform that computes a type by evaluating
any nested transforms and then constructs an object of that type.
The purpose of proto::make<> is to annotate a transform as
an ObjectTransform so that
proto::when<> knows
how to apply it.
For the full description of the behavior of the
proto::make<>
transform, see the documentation for the nested
proto::make::impl<>
class template.
proto::transform_impl< Expr, State, Data >
see-below
proto::make<T>::impl<Expr, State, Data>::result_type is
computed as follows:
If T is an ObjectTransform of the form
Object(A0,…An) or
Object(A0,…An ...),
then let O be the return type
Object. Otherwise, let O
be T. The result_type typedef is
then computed as follows:
If proto::is_transform<O>::value is
true, then let the result type be
boost::result_of<proto::when<_, O>(Expr, State, Data)>::type
.
Note that a substitution took place.
If O is a template like
proto::noinvoke<S<X0,…Xn> >,
then the result type is calculated as follows:
For each i in
[0,n], let
Xi'
be
boost::result_of<proto::make<Xi>(Expr, State, Data)>::type
(which evaluates this procedure recursively). Note that a substitution took place. (In this case,
Proto merely assumes that a substitution took place for the sake of compile-time efficiency. There
would be no reason to use proto::noinvoke<>
otherwise.)
The result type is
S<X0',…Xn'>
.
If O is a template like
S<X0,…Xn>,
then the result type is calculated as follows:
For each i in
[0,n], let
Xi'
be
boost::result_of<proto::make<Xi>(Expr, State, Data)>::type
(which evaluates this procedure recursively). Note whether any substitutions took place during
this operation.
If any substitutions took place in the above step and
S<X0',…Xn'>
has a nested
type typedef, the result type is
S<X0',…Xn'>::type
.
Otherwise, the result type is
S<X0',…Xn'>
.
Otherwise, the result type is O, and note that no
substitution took place.
Note that proto::when<> is implemented
in terms of proto::call<>
and proto::make<>, so the
above procedure is evaluated recursively.
result_type
typename impl::expr_param
typename impl::state_param
typename impl::data_param
proto::make<T>::impl<Expr,State,Data>::operator()
behaves as follows:
If T is of the form
O(A0,…An), then:
If
proto::is_aggregate<result_type>::value
is true, then construct
and return an object that as follows:
result_type that = {
proto::when<_, A0>()(expr, state, data),
…
proto::when<_, An>()(expr, state, data)
};
Otherwise, construct
and return an object that as follows:
result_type that(
proto::when<_, A0>()(expr, state, data),
…
proto::when<_, An>()(expr, state, data)
);
If T is of the form
O(A0,…An ...),
then let T' be O(A0,…An-1, S),
where S is a type sequence computed from the unpacking expression An
as described in the reference for proto::pack. Then, return:
proto::make<T'>()(expr, state, data)
Otherwise, construct and return an object that
as follows: result_type that = result_type();