From: Maurizio Vitale (mav_at_[hidden])
Date: 2007-07-17 13:58:22


Eric Niebler <eric_at_[hidden]> writes:

> Maurizio Vitale wrote:
<snip>
>>
>> My mental model was:
>> - proto::deep_copy traverse the expression top-down replacing references with value.
>
> Actually, bottom-up, but yes references are replaced with values.

It is probably terminology, but the following seems top-down to me: you're asked to deep-copy
an expression and you assemble an expression which has the same shape (tag and argcount) of the
original and as children the result of recursive evaluations of deep-copy on the children.

    #define N BOOST_PP_ITERATION()

            template<typename Expr>
            struct deep_copy_impl<Expr, N>
            {
                typedef expr<typename Expr::proto_tag, BOOST_PP_CAT(args, N)<
                    BOOST_PP_ENUM(N, BOOST_PROTO_DEFINE_DEEP_COPY_TYPE, ~)
> > expr_type;
                typedef typename Expr::proto_domain::template apply<expr_type>::type type;

                template<typename Expr2>
                static type call(Expr2 const &expr)
                {
                    expr_type that = {
                        BOOST_PP_ENUM(N, BOOST_PROTO_DEFINE_DEEP_COPY_FUN, ~)
                    };
                    return Expr::proto_domain::make(that);
                }
            };

>
>> - generators are used to wrap expressions as they are built bottom-up
>
> Generators are used whenever you want to customize the result of proto's
> operator overloads.

Yes, and my reading of the behaviour of the specific generator you wrote is that
everytime you construct an expression you evaluate deep_copy on it.
Modulo the number of evaluations of deep_copy, I still don't see any difference
between using deep_copy on the toplevel expression and using the generator for
building an already deep-copied solution (other than, as you point out later in
one case you have to explicitely call deep_copy while in the other expressions
naturally spring to life without references)

>> So, assuming that the expression is properly wrapped in lambda_expr<> why the result
>> of calling proto::expr on the whole expression would be different from using the generator?
>
> Sorry, I don't understand the question.

I guess my question is what is the difference between:

  struct lambda_domain : domain<generator<lambda_expression> > {};
  auto expr = deep_copy(_1 + 42);

and:

  auto expr_1 = _1 + 42; in the case where the generator you provided is used

Aren't expr and expr_1 exactly the same?

> How this helps is that as phoenix expressions are being built, the
> phoenix generator will ensure that all the nodes are held by-value.
> There will never be a need for the user to deep_copy phoenix expressions
> explicitly -- it's done piecemeal by phoenix. So function<> is passed an
> object that does not need to be deep-copied.

I see this difference now and understand the reasons behind your suggestion.
Thanks for the explanation,

       Maurizio