
Hi all, consider the following code: std::vector<double> a(10,1.0), b(10,2.0); BOOST_AUTO( temp , proto::as_expr<MixedDomain>(a+b+0.1) ); // is the function proto::as_expr<MixedDomain>() needed? temp[0]; Here the expression a +b+ 0.1 is created by the MixedDomain as it is from the mixed example. And the operator[] is definde by: typedef typename boost::remove_reference< typename boost::result_of<Begin(MixedExpr<Expr> const & )>::type>::type Expr2; typedef typename proto::result_of::eval<Expr2, DereferenceCtx const>::type result_type; result_type operator[](std::size_t index) const { Expr2 expr2 = Begin()(*this); DereferenceCtx const deref = {}; return proto::eval(expr2, deref); } But the code crashes during runtime. The reason is that the number 0.1 is held by reference. So the number 0.1 goes out of scope before i try to evaluate the expression temp[0]; A way to solve this problem is to deep copy the expression with deep_copy. But on the other hand i do not want to copy the two vectors a and b. So i am asking what is the best way to solve this problem? Can this problem be solved by defining a Grammar that copies the number 0.1? Or do i need to extend the deep_copy by deep_copy_if<double>() (a+b+0.1). It should copy the terminal only if it matches the specified type. Thanks for your help. B/Rgds Kim Here is the whole code: //[ Mixed /////////////////////////////////////////////////////////////////////////////// // Copyright 2008 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // This is an example of using BOOST_PROTO_DEFINE_OPERATORS to Protofy // expressions using std::vector<> and std::list, non-proto types. It is a port // of the Mixed example from PETE. // (http://www.codesourcery.com/pooma/download.html). #include <list> #include <cmath> #include <vector> #include <complex> #include <iostream> #include <stdexcept> #include <boost/proto/core.hpp> #include <boost/proto/debug.hpp> #include <boost/proto/context.hpp> #include <boost/proto/transform.hpp> #include <boost/proto/proto_typeof.hpp> #include <boost/proto/deep_copy.hpp> #include <boost/utility/enable_if.hpp> #include <boost/typeof/std/list.hpp> #include <boost/typeof/std/vector.hpp> #include <boost/typeof/std/complex.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/utility/result_of.hpp> #include <boost/typeof/typeof.hpp> namespace proto = boost::proto; namespace mpl = boost::mpl; using proto::_; template<typename Expr> struct MixedExpr; template<typename Iter> struct iterator_wrapper { typedef Iter iterator; iterator_wrapper(Iter it) :it(it) {}; Iter it; }; struct begin_iter :proto::callable { template<class Sig> struct result; template<class This, class Cont> struct result<This(Cont)> : proto::result_of::as_expr< iterator_wrapper<typename boost::remove_reference<Cont>::type::const_iterator> > {}; template<class Cont> typename result<begin_iter(Cont const&)>::type operator()(Cont const& cont) const { iterator_wrapper<typename Cont::const_iterator> it(cont.begin()); return proto::as_expr(it); } }; template<typename Num> struct num_wrapper { typedef Num numeric; num_wrapper(Num num) :num_(num) { //BOOST_MPL_ASSERT( (boost::is_reference<Num>) ); }; Num num_; }; struct begin_num :proto::callable { template<class Sig> struct result; template<class This, class Cont> struct result<This(Cont)> : proto::result_of::make_expr<proto::tag::terminal ,num_wrapper< typename boost::remove_const< typename boost::remove_reference<Cont>::type >::type > > {}; template<class Cont> typename result<begin_num(Cont const)>::type operator()(Cont const cont) const { //BOOST_MPL_ASSERT( (boost::is_reference<result<begin_num(Cont const&)>::type>) ); num_wrapper<Cont> num(cont); return proto::make_expr<proto::tag::terminal>(num); } }; // Here is a grammar that replaces vector and list terminals with their // begin iterators struct Begin : proto::or_< proto::when< proto::terminal<std::vector<_,_> >, begin_iter(proto::_value)> ,proto::when< proto::terminal<std::list<_,_> >, begin_iter(proto::_value)> ,proto::when<proto::terminal<double>, begin_num(proto::_value) > ,proto::when<proto::terminal<_> > ,proto::nary_expr<_ , proto::vararg<Begin> > > {}; struct DereferenceCtx { template<typename Expr,typename EnableIf=void> struct eval : proto::default_eval<Expr, DereferenceCtx const> {}; template<typename Expr> struct eval<Expr, typename boost::enable_if< proto::matches<Expr, proto::terminal< iterator_wrapper<_> > > >::type > { typedef typename proto::result_of::value<Expr>::type IteratorWrapper; typedef typename IteratorWrapper::iterator iterator; typedef typename std::iterator_traits<iterator>::reference result_type; template<typename Expr> result_type operator()(Expr &expr,DereferenceCtx const&) { return *proto::value(expr).it; } }; template<typename Expr> struct eval<Expr, typename boost::enable_if< proto::matches<Expr, proto::terminal< num_wrapper<_> > > >::type > { typedef typename proto::result_of::value<Expr>::type NumWrapper; typedef typename NumWrapper::numeric result_type; template<typename Expr> result_type operator()(Expr &expr,DereferenceCtx const&) { return proto::value(expr).num_; } }; }; struct IncrementCtx { template<typename Expr,typename EnableIf=void> struct eval : proto::null_eval<Expr, IncrementCtx const> {}; template<typename Expr> struct eval<Expr, typename boost::enable_if< proto::matches<Expr, proto::terminal<iterator_wrapper<_> > > >::type> { typedef void result_type; template<typename Expr> result_type operator()(Expr& expr, IncrementCtx const & ) { ++proto::value(expr).it; } }; }; struct AdvanceCtx { std::size_t index_; template<typename Expr,typename EnableIf=void> struct eval : proto::null_eval<Expr, AdvanceCtx const> {}; template<typename Expr> struct eval<Expr, typename boost::enable_if< proto::matches<Expr, proto::terminal<iterator_wrapper<_> > > >::type> { typedef void result_type; template<typename Expr> result_type operator()(Expr& expr, AdvanceCtx const & ctx) { std::advance(proto::value(expr).it, ctx.index_); } }; }; // A grammar which matches all the assignment operators, // so we can easily disable them. struct AssignOps : proto::switch_<struct AssignOpsCases> {}; // Here are the cases used by the switch_ above. struct AssignOpsCases { template<typename Tag, int D = 0> struct case_ : proto::not_<_> {}; template<int D> struct case_< proto::tag::plus_assign, D > : _ {}; template<int D> struct case_< proto::tag::minus_assign, D > : _ {}; template<int D> struct case_< proto::tag::multiplies_assign, D > : _ {}; template<int D> struct case_< proto::tag::divides_assign, D > : _ {}; template<int D> struct case_< proto::tag::modulus_assign, D > : _ {}; template<int D> struct case_< proto::tag::shift_left_assign, D > : _ {}; template<int D> struct case_< proto::tag::shift_right_assign, D > : _ {}; template<int D> struct case_< proto::tag::bitwise_and_assign, D > : _ {}; template<int D> struct case_< proto::tag::bitwise_or_assign, D > : _ {}; template<int D> struct case_< proto::tag::bitwise_xor_assign, D > : _ {}; }; // A vector grammar is a terminal or some op that is not an // assignment op. (Assignment will be handled specially.) struct MixedGrammar : proto::or_< proto::when< proto::terminal<double const&> , begin_num(proto::_value)> , proto::terminal<_> , proto::and_< proto::nary_expr<_, proto::vararg<MixedGrammar> > , proto::not_<AssignOps> > > {}; // Expressions in the vector domain will be wrapped in VectorExpr<> // and must conform to the VectorGrammar struct MixedDomain : proto::domain<proto::generator<MixedExpr>, MixedGrammar> {}; // Here is MixedExpr, a wrapper for expression types in the MixedDomain. template<typename Expr> struct MixedExpr : proto::extends<Expr, MixedExpr<Expr>, MixedDomain> { explicit MixedExpr(Expr const &expr) : proto::extends<Expr, MixedExpr<Expr>, MixedDomain>(expr) {} typedef typename boost::remove_reference< typename boost::result_of<Begin(MixedExpr<Expr> const & )>::type>::type Expr2; typedef typename proto::result_of::eval<Expr2, DereferenceCtx const>::type result_type; result_type operator[](std::size_t index) const { //BOOST_MPL_ASSERT( (boost::is_reference<Expr2>) ); Expr2 expr2 = Begin()(*this); AdvanceCtx const adv = {index}; proto::eval(expr2, adv); DereferenceCtx const deref = {}; return proto::eval(expr2, deref); } private: // hide this: //using proto::extends<Expr, MixedExpr<Expr>, MixedDomain>::operator []; }; // Define a trait type for detecting vector and list terminals, to // be used by the BOOST_PROTO_DEFINE_OPERATORS macro below. template<typename T> struct IsMixed : mpl::false_ {}; template<typename T, typename A> struct IsMixed<std::list<T, A> > : mpl::true_ {}; template<typename T, typename A> struct IsMixed<std::vector<T, A> > : mpl::true_ {}; namespace MixedOps { // This defines all the overloads to make expressions involving // std::vector to build expression templates. BOOST_PROTO_DEFINE_OPERATORS(IsMixed, MixedDomain) struct assign_op { template<typename T, typename U> void operator ()(T &t, U const &u) const { t = u; } }; struct plus_assign_op { template<typename T, typename U> void operator ()(T &t, U const &u) const { t += u; } }; struct minus_assign_op { template<typename T, typename U> void operator ()(T &t, U const &u) const { t -= u; } }; struct sin_ { template<typename Sig> struct result; template<typename This, typename Arg> struct result<This(Arg)> : boost::remove_const<typename boost::remove_reference<Arg>::type> {}; template<typename Arg> Arg operator ()(Arg const &a) const { return std::sin(a); } }; template<typename A> typename proto::result_of::make_expr< proto::tag::function , MixedDomain , sin_ const , A const & >::type sin(A const &a) { return proto::make_expr<proto::tag::function, MixedDomain>(sin_(), boost::ref(a)); } template<typename FwdIter, typename Expr, typename Op> void evaluate(FwdIter begin, FwdIter end, Expr const &expr, Op op) { IncrementCtx const inc = {}; DereferenceCtx const deref = {}; typename boost::result_of<Begin(Expr const &)>::type expr2 = Begin()(expr); for(; begin != end; ++begin) { op(*begin, proto::eval(expr2, deref)); proto::eval(expr2, inc); } } template<typename Vector, typename Expr> Vector& assign(Vector &arr,Expr const &expr) { evaluate(arr.begin(),arr.end(),proto::as_expr<MixedDomain>(expr),assign_op()); return arr; } // Add-assign to a vector from some expression. template<typename T, typename A, typename Expr> std::vector<T, A> &operator +=(std::vector<T, A> &arr, Expr const &expr) { evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op()); return arr; } // Add-assign to a list from some expression. template<typename T, typename A, typename Expr> std::list<T, A> &operator +=(std::list<T, A> &arr, Expr const &expr) { evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), plus_assign_op()); return arr; } // Minus-assign to a vector from some expression. template<typename T, typename A, typename Expr> std::vector<T, A> &operator -=(std::vector<T, A> &arr, Expr const &expr) { evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op()); return arr; } // Minus-assign to a list from some expression. template<typename T, typename A, typename Expr> std::list<T, A> &operator -=(std::list<T, A> &arr, Expr const &expr) { evaluate(arr.begin(), arr.end(), proto::as_expr<MixedDomain>(expr), minus_assign_op()); return arr; } } int main() { using namespace MixedOps; int n = 10; std::vector<int> a,b,c,d; std::list<double> e; std::list<std::complex<double> > f; int i; for(i = 0;i < n; ++i) { a.push_back(i); b.push_back(2*i); c.push_back(3*i); d.push_back(i); e.push_back(0.0); f.push_back(std::complex<double>(1.0, 1.0)); } BOOST_AUTO(temp ,c + a + 0.1 ); for(int i=0, end=n;i<end;++i) std::cout<<temp[i]<<"\t"; //f -= sin(0.1 * e * std::complex<double>(0.2, 1.2)); //std::list<double>::const_iterator ei = e.begin(); //std::list<std::complex<double> >::const_iterator fi = f.begin(); //for (i = 0; i < n; ++i) //{ // std::cout // << "a(" << i << ") = " << a[i] // << "b(" << i << ") = " << b[i] // << "c(" << i << ") = " << c[i] // << "d(" << i << ") = " << d[i] // << "e(" << i << ") = " << *ei++ // << "f(" << i << ") = " << *fi++ // << std::endl; //} //boost::array<double,10> sad; } //]