On 4/23/2012 1:01 PM, Joel Falcou wrote: > Let's say we have a bunch of functions like sum and sqr defined on a > proto domain to return > expression of tag sum_ and sqr_ in this domain. One day we want to make > a norm2(x) function > which is basically sum(sqr(x)). > > My feeling is that I should be able to write it using sqr and sum > expressions. > Alas it seems this results in dandling reference, crash and some sad pandas. > > Then I remember about proto::deep_copy but I have a worries. x is > usually a terminal > holding a huge matrix like value and I just don't want this huge matrix > to be copied. > > What's the correct way to handle such a problem ? How can I build new > function returning > expressions built from expression composition without incurring a huge > amount of copy ?
Right. The canonical way of doing this is as follows: #include <boost/proto/proto.hpp> namespace proto = boost::proto; struct sum_ {}; struct sqr_ {}; namespace result_of { template<typename T> struct sum : proto::result_of::make_expr<sum_, T> {}; template<typename T> struct sqr : proto::result_of::make_expr<sqr_, T> {}; template<typename T> struct norm2 : sum<typename sqr<T>::type> {}; } template<typename T> typename result_of::sum<T &>::type const sum(T &t) { return proto::make_expr<sum_>(boost::ref(t)); } template<typename T> typename result_of::sqr<T &>::type const sqr(T &t) { return proto::make_expr<sqr_>(boost::ref(t)); } template<typename T> typename result_of::norm2<T &>::type const norm2(T &t) { return proto::make_expr<sum_>(proto::make_expr<sqr_>(boost::ref(t))); } int main() { sum(proto::lit(1)); sqr(proto::lit(1)); norm2(proto::lit(1)); } As you can see, the norm2 is not implemented in terms of the sum and sqr functions. That's not really ideal, but it's the only way I know of to get fine grained control over which parts are stored by reference and which by value. You always need to use make_expr to build expression trees that you intend to return from a function. That's true even for the built-in operators. You can't ever return the result of expressions like "a+b*42" ... because of the lifetime issues. You can't use deep_copy for the reason you mentioned. I once had a function proto::implicit_expr, which you could have used like this: template<typename T> typename result_of::norm2<T &>::type const norm2(T &t) { return proto::implicit_expr(sum(sqr(x))); } implicit_expr() returns an object that holds its argument and is convertible to any expression type. The conversion is implemented by trying to implicitly convert all the child expressions, recursively. It sort of worked, but I never worked out all the corner cases, and documenting it would have been a bitch. Perhaps I should take another look. Patches welcome. :-) -- Eric Niebler BoostPro Computing http://www.boostpro.com _______________________________________________ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto