
AJD wrote:
Hi,
I've been trying out boost.proto lately and I've noticed that for my expressions it tends to force my operands to be created on the stack. <snip>
The way you were defining your vector terminals confused proto into thinking they needed to be wrapped in your vector_expr wrapper. The extra layer of indirection is what is flummoxing msvc's optimizer. I can only assume you went through those contortions in order to preserve the nice aggregate initialization for your vector terminals. Try the following instead. #include <cstddef> #include <iostream> #include <boost/xpressive/proto/proto.hpp> #include <boost/xpressive/proto/context.hpp> using namespace boost; // This grammar describes which lazy vector expressions // are allowed; namely, vector terminals and addition // and subtraction of lazy vector expressions. struct VectorGrammar : proto::or_< proto::and_< proto::terminal< proto::_ > , proto::if_< is_array<proto::result_of::arg<mpl::_> > > > , proto::plus< VectorGrammar, VectorGrammar > > {}; // Expressions in the lazy vector domain must conform // to the lazy vector grammar struct VectorDomain; // Here is an evaluation context that indexes into a lazy vector // expression, and combines the result. struct subscript_context { subscript_context(std::size_t i) : i(i) { } // Use default_eval for all the operations ... template< typename Expr, typename Tag = typename Expr::proto_tag > struct eval : proto::default_eval< Expr, subscript_context const > { }; // ... except for terminals, which we index with our subscript template< typename Expr > struct eval< Expr, proto::tag::terminal > { typedef typename Expr::value_type result_type; result_type operator ()(Expr const & expr, subscript_context const & ctx) const { return proto::arg(expr)[ctx.i]; } }; private: std::size_t i; }; // Here is the domain-specific expression wrapper, which overrides // operator [] to evaluate the expression using the subscript_context. template< typename Expr > struct vector_expr { BOOST_PROTO_EXTENDS(Expr, vector_expr<Expr>, VectorDomain) // Use the subscript_context to implement subscripting // of a lazy vector expression tree. typename proto::result_of::eval< Expr, subscript_context const >::type operator [](std::size_t i) const { subscript_context const ctx(i); return proto::eval(*this, ctx); } }; template< typename T, typename U = proto::is_proto_expr > struct vector2; template< typename T > struct vector2<T[3]> { BOOST_PROTO_EXTENDS(typename proto::terminal<T[3]>::type, vector2<T[3]>, VectorDomain) typedef T value_type; T & operator [](std::size_t i) { return proto::arg(*this)[i]; } T const & operator [](std::size_t i) const { return proto::arg(*this)[i]; } }; // Tell proto that in the VectorDomain, all // expressions should be wrapped in vector_expr<> struct VectorDomain : proto::domain< proto::pod_generator< vector_expr > , VectorGrammar > { }; int main() { vector2< float[3] > v1 = { 0, 1, 2 }; vector2< float[3] > v2 = { 3, 4, 5 }; vector2< float[3] > v3 = { 6, 7, 8 }; // Add two vectors lazily and get the 2nd element. std::cout << (v1 + v2)[0]; return 0; } For me, the line "std::cout << (v1 + v2)[0]" generates: ; 107 : // Add two vectors lazily and get the 2nd element. ; 108 : std::cout << (v1 + v2)[0]; fldz push ecx fadd QWORD PTR __real@4008000000000000 fstp DWORD PTR tv227[esp+12] fld DWORD PTR tv227[esp+12] fstp DWORD PTR [esp] call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@M@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<< That looks pretty good to me. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com