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>,
lambda_domain)

         // 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.)

HTH,

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com
The Astoria Seminar ==> http://www.astoriaseminar.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk