Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2007-07-17 10:58:43

Maurizio Vitale wrote:
> On Jul 17, 2007, at 2:54 AM, dan marsden wrote:
>> function<int(int&,int&)> f(_0 + _1); // Copy lambda expression into
>> a Boost.Function func
>> Now I've got problems because proto trees are built out of
>> references (to temporaries). So func will blow up later when the
>> temporaries are off the stack
> bitten by this in the past. There's a proto::deep_copy function that
> you can use for converting references to values.

Maurizio, deep_copy() alone will not work here. The user is creating a
lambda expression and assigning it directly to function<>:

   function<int(int&,int&)> f(_0 + _1);

function<> knows nothing about proto expressions, and doesn't know to
call proto::deep_copy().

Dan, this is a job for a custom generator. (Thanks, I haven't had need
of one until now! This'll make a great example.) You're already using a
generator to wrap your expressions. But you also need a deep_copy-ing
generator. Here's the basic idea ...

     #include <iostream>
     #include <boost/xpressive/proto/proto.hpp>
     using namespace boost::proto;

     template<typename Expr>
     struct lambda_expr;

     struct lambda_generator
         template<typename Expr>
         struct apply
             typedef lambda_expr<
                 typename result_of::deep_copy<Expr>::type
> type;

         template<typename Expr>
         static typename apply<Expr>::type make(Expr const &expr)
             typename apply<Expr>::type that = {deep_copy(expr)};
             return that;

     struct lambda_domain
       : domain<lambda_generator>

     template<typename Expr>
     struct lambda_expr
         BOOST_PROTO_EXTENDS(Expr, lambda_expr<Expr>, lambda_domain)
         BOOST_PROTO_EXTENDS_ASSIGN(Expr, lambda_expr<Expr>, lambda_domain)
         BOOST_PROTO_EXTENDS_SUBSCRIPT(Expr, lambda_expr<Expr>,

         // Implement operator() here.

     struct one_tag {};
     lambda_expr<terminal<one_tag>::type> const _1 = {{{}}};

     int main()
         _1 + 42;
         std::cout << typeid(_1+42).name() << std::endl;
         return 0;

Of course, calling deep_copy() in the generator is sub-optimal. Every
part of the tree has been deep_copied already except the top-most node.
When I find time, I'll write a by_value_generator which makes sure
everything in the tree is held by value.

(I'm using the BOOST_PROTO_EXTENDS macros here instead of
proto::extends<> so that _1 can be statically initialized. You may want
to do something similar, if you aren't already.)


Eric Niebler
Boost Consulting
The Astoria Seminar ==>

Boost list run by bdawes at, gregod at, cpdaniel at, john at