Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2008-03-10 17:36:19


Cédric Venet wrote:
> Hi,
>
> I decided to try to write a small vector library with proto to test it.
>
> The following worked without problem (I will use extend further on but at
> the moment the as_expr are needed)
>
> proto::display_expr( proto::as_expr(x)+proto::as_expr(y)*proto::as_expr(z)
> , std::cout );
>
> I then added
>
> struct fastvec_reduction_tag {};
> struct sum_ {};
> template<typename A>
> typename proto::result_of::make_expr<
> fastvec_reduction_tag
> // , MixedDomain
> , sum_ const
> , A const &
>> ::type sum(A const &a) {
> return proto::make_expr<fastvec_reduction_tag/*, MixedDomain*/>(sum_(),
> boost::ref(a));
> }
>
> Which work well
>
> proto::display_expr( sum(x) , std::cout );
>
> And now, I would like to create a "function" dot(x,y) which expand to
> sum(x*y).
> I tried:
>
> template<typename A, typename B>
> typename proto::result_of::make_expr<
> fastvec_reduction_tag
> // , MixedDomain
> , sum_ const
> , BOOST_TYPEOF(boost::ref(proto::as_expr(A())*proto::as_expr(B())))
>> const &
>> ::type dot(A const &a, B const &b) {
> return proto::make_expr<fastvec_reduction_tag/*, MixedDomain*/>(sum_(),
> boost::ref(
> proto::as_expr(a)*proto::as_expr(b)
> ));
> }
>
> Which compile but fail at runtime when I do
>
> proto::display_expr( dot(x,y) , std::cout );
>
> (it call << on an invalid vector (type of x and y)).
>
> Is there a ways to create the tree for sum(x*y) directly or should I use a
> transform (create a tree with a dot tag and then transform it with proto)?

The problem you're running into is that as_expr(a) is creating a
temporary object, which is getting held by reference in the expression
tree created by proto's operator* overload. Then you're returning the
tree and letting the references dangle. When creating trees and
returning them from functions, you should be using make_expr()
consistently so that you have explicit control over what gets stored by
reference and by value. Try this:

     #include <iostream>
     #include <boost/xpressive/proto/proto.hpp>
     #include <boost/xpressive/proto/debug.hpp>

     using namespace boost;

     struct fastvec_reduction_tag {};
     struct sum_ {friend
std::ostream&operator<<(std::ostream&s,sum_){return s<<"sum_";}};

     template<typename A>
     typename proto::result_of::make_expr<
         fastvec_reduction_tag
       , sum_ const
       , A const &
>::type sum(A const &a)
     {
         return proto::make_expr<fastvec_reduction_tag>(
             sum_()
           , boost::ref(a)
         );
     }

     template<typename A, typename B>
     typename proto::result_of::make_expr<
         fastvec_reduction_tag
       , sum_ const
       , typename proto::result_of::make_expr<
             proto::tag::multiplies
           , A const &
           , B const &
>::type
>::type dot(A const &a, B const &b)
     {
         return proto::make_expr<fastvec_reduction_tag>(
             sum_()
           , proto::make_expr<proto::tag::multiplies>(
                 boost::ref(a)
               , boost::ref(b)
             )
         );
     }

     int main()
     {
         int x = 0, y = 1;
         proto::display_expr( sum(x) , std::cout );
         proto::display_expr( dot(x,y) , std::cout );

         return 0;
     }

> The page 'users_guide\expression_construction\construction_utils.html' seems
> very complete, but hard to understand how to put it in practice, perhaps you
> could link it to some use in the example.

This might make a good example, in fact. Thanks.

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com

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