[proto]context interface allowing "packaged" node args?

Hi Eric, I need a context with something like the following methods: template< typename Tag, typename Left, typename Right > result_type operator()(expr<Tag, Left, Right> const &expr) const { std::cout<<std::setw(indent) <<""<<"binary_expr:"<<expr.get_instance()<<"\n"; indent+=2; proto::eval(left, *this); proto::eval(right, *this); indent-=2; } where the expression tree node argument remains "packaged": (expr<Tag, Left, Right> const &expr) in contrast to the unpacked version: (Tag, Left const &left, Right const &right) shown in, for example: http://boost-sandbox.sourceforge.net/libs/proto/doc/html/boost_proto/user_s_... IOW, the calculator.html page suggests an interface like: template< typename Tag, typename Left, typename Right > result_type operator()(Tag, Left const &left, Right const &right) const { std::cout<<std::setw(indent)<<""<<"binary_expr\n"; indent+=2; proto::eval(left, *this); proto::eval(right, *this); indent-=2; } where there's no access to the "packaged" extended node, expr<Tag,Left,Right>, where the extension is, for example: struct xmpl_domain; struct xmpl_delta { unsigned const my_instance; static unsigned our_instances; xmpl_delta(void) : my_instance(++our_instances) {} xmpl_delta(xmpl_delta const&) : my_instance(++our_instances) {} void operator=(xmpl_delta const&) {} unsigned get_instance(void)const { return my_instance; } }; unsigned xmpl_delta::our_instances=0; template<typename Expr> struct xmpl_expression : proto::extends<Expr, xmpl_expression<Expr>, xmpl_domain> , xmpl_delta { ... }; I've looked at the formated output of the preprocessed context.hpp; however, I'm still having difficulty figuring out if this "packaged" method interfaces is possible. Any help is appreciated. TIA. -regards, Larry

On 06/01/2007 06:35 AM, Larry Evans wrote: [snip]
where the expression tree node argument remains "packaged":
(expr<Tag, Left, Right> const &expr)
in contrast to the unpacked version:
(Tag, Left const &left, Right const &right)
shown in, for example:
http://boost-sandbox.sourceforge.net/libs/proto/doc/html/boost_proto/user_s_...
Actually, from calculator.html, I guess the packaged version would be: (expr<Tag, args2<Left, Right>, 2> const &expr) [snip]

Larry Evans wrote:
Hi Eric,
I need a context with something like the following methods:
template< typename Tag, typename Left, typename Right > result_type operator()(expr<Tag, Left, Right> const &expr) const { std::cout<<std::setw(indent) <<""<<"binary_expr:"<<expr.get_instance()<<"\n"; indent+=2; proto::eval(left, *this); proto::eval(right, *this); indent-=2; }
where the expression tree node argument remains "packaged":
(expr<Tag, Left, Right> const &expr)
in contrast to the unpacked version:
(Tag, Left const &left, Right const &right)
Sure. Only context types derived from callable_context get unpacked nodes like that. If you don't inherit from callable_context, you'll get the whole node without any modification. The interface is a bit different, though. You'll need something like: struct my_context { template<typename Expr> struct eval { typedef ... result_type; result_type operator()(Expr &expr, my_context &ctx) const { return ...; } }; }; If you want to handle binary nodes specially, you would define the eval member template as: template<typename Expr, long Arity = Expr::arity::value> struct eval and then partially specialize for binary nodes: template<typename Expr> struct eval<Expr, 2> HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

On 06/01/2007 09:36 AM, Eric Niebler wrote:
Larry Evans wrote: [snip]
where the expression tree node argument remains "packaged":
(expr<Tag, Left, Right> const &expr)
[snip] different, though. You'll need something like:
struct my_context { template<typename Expr> struct eval { typedef ... result_type; result_type operator()(Expr &expr, my_context &ctx) const { return ...; } }; };
[snip] Great! I started coding and then thought about creating a "catchall" method to handle any node. I got to here: struct xmpl_context { explicit xmpl_context(unsigned& a_indent) : indent(a_indent) { } template<typename Expr, long Arity = Expr::arity::value> struct eval { typedef void result_type; result_type operator()(Expr &expr, xmpl_context &ctx) const { typedef proto::tagof<Expr>::type tag_type; const char*tag_name=std::typeid(tag_type).name() std::cout<<std::setw(indent) <<""<<tag_name<<".get_instance=" <<expr.get_instance()<<"\n"; indent+=2; for(long ichild=0; ichild<Arity; ++ichild) { proto::eval(proto::arg_c<Expr,ichild>(expr), *this); } indent-=2; } }; private: unsigned& indent; }; ...then realized I needed something like mpl's for_each. I noticed in boost/xpressive/proto/fusion.hpp there's children templates, but they don't look like they'd help. How do I do what's implied by the above for loop? Thanks again. -regards, Larry

Larry Evans <cppljevans@cox-internet.com> writes:
struct xmpl_context { explicit xmpl_context(unsigned& a_indent) : indent(a_indent) { }
template<typename Expr, long Arity = Expr::arity::value> struct eval {
typedef void result_type; result_type operator()(Expr &expr, xmpl_context &ctx) const { typedef proto::tagof<Expr>::type tag_type; const char*tag_name=std::typeid(tag_type).name() std::cout<<std::setw(indent) <<""<<tag_name<<".get_instance=" <<expr.get_instance()<<"\n"; indent+=2; for(long ichild=0; ichild<Arity; ++ichild) { proto::eval(proto::arg_c<Expr,ichild>(expr), *this); } indent-=2; } };
private: unsigned& indent;
};
I noticed in boost/xpressive/proto/fusion.hpp there's children templates, but they don't look like they'd help. How do I do what's implied by the above for loop?
It seems to me you're duplicating what display_expr does (in debug.hpp), but if the question is more general and you need to do something else you can look at proto::transform::fold (or fold_to_list if you need more persistence). calc3.cpp shows how to use fold from the ::apply side, struct CalculatorGrammar : proto::or_< // placeholders have a non-zero arity ... placeholder_arity< proto::terminal< arg<_> > > // Any other terminals have arity 0 ... , proto::trans::always< proto::terminal<_>, mpl::int_<0> > // For any non-terminals, find the arity of the children and // take the maximum. This is recursive. , proto::trans::fold< // This matches any non-terminal for which the children // are themselves calculator expressions. proto::nary_expr<_, proto::vararg< max_arity< CalculatorGrammar > > > > > {}; I've never used it myself, but I presume that if max_arity had a ::call member (which in the example hasn't) then it would be called at run-time when CalculatorGrammar::call(,,) is evaluated and the state would be the result of calling max_arity::call on the previous element in the list of arguments. Eric will surely correct any false information I might be inadvertently spreading... Regards, Maurizio

On 06/01/2007 03:34 PM, Maurizio Vitale wrote:
Larry Evans <cppljevans@cox-internet.com> writes: [snip]
struct xmpl_context { explicit xmpl_context(unsigned& a_indent) : indent(a_indent) { }
template<typename Expr, long Arity = Expr::arity::value> struct eval {
typedef void result_type; result_type operator()(Expr &expr, xmpl_context &ctx) const { typedef proto::tagof<Expr>::type tag_type; const char*tag_name=std::typeid(tag_type).name() std::cout<<std::setw(indent) <<""<<tag_name<<".get_instance=" <<expr.get_instance()<<"\n"; indent+=2; for(long ichild=0; ichild<Arity; ++ichild) { proto::eval(proto::arg_c<Expr,ichild>(expr), *this); } indent-=2; } };
private: unsigned& indent;
};
I noticed in boost/xpressive/proto/fusion.hpp there's children templates, but they don't look like they'd help. How do I do what's implied by the above for loop?
It seems to me you're duplicating what display_expr does (in debug.hpp), but if the question is more general and you need to do something else you can look at proto::transform::fold (or fold_to_list if you need more persistence).
You're almost right about duplicating display_expr; however, my purpose was to see if I could access and printout the extension, xmpl_delta that was shown in my earlier post. Of course this xmpl_delta is not my ultimate goal, but, hopefully, it will show me, at least partly, how to achieve that ultimate goal. (BTW, that goal is the calculation of first and follow attributes of the grammar subexpressions as done here: http://svn.boost.org/trac/boost/browser/sandbox/boost/grammar_pipeline/eff/p... IOW, xmpl_delta would be replaced by the lookahead_attributes found on line 89 of productions.hpp. ). BTW, I have made some progress in solving the problem. It looks like: struct xmpl_context { explicit xmpl_context(unsigned& a_indent) : indent(a_indent) { } template<typename Expr, long Arity = Expr::arity::value> struct eval { struct eval_child_i { Expr const& my_parent; xmpl_context& my_context; eval_child_i ( Expr const& a_parent , xmpl_context& a_context ) : my_parent(a_parent) , my_context(a_context) {} template<long Index> void operator()(mpl::integral_c<long,Index>&) { proto::eval(proto::arg_c<Expr,Index>(my_parent),my_context); } }; typedef unsigned result_type; result_type operator()(Expr const &expr, xmpl_context &ctx) { typedef typename proto::tag_of<Expr>::type tag_type; const char*tag_name=typeid(tag_type).name(); std::cout<<std::setw(ctx.indent)<<""<<tag_name<<".get_instance="<<expr.get_instance()<<"\n"; ctx.indent+=2; typedef typename mpl::range_c<long,0,Arity>::type indices_type; eval_child_i a_eval_child(expr,ctx); mpl::for_each<indices_type>(a_eval_child); ctx.indent-=2; return ctx.indent; } }; private: unsigned& indent; }; However, I'm still getting compile errors: extend_transform_xmpl.cpp:142: instantiated from here extend_transform_xmpl.cpp:59: error: no matching function for call to 'arg_c(const xmpl_expression<boost::proto::expr<boost::proto::tag::terminal, boost::proto::args1<arg_id<1u> >, 1l> >&)' and still investigating. Thanks for the suggestions. -regards, Larry [snip]

However, I'm still getting compile errors:
extend_transform_xmpl.cpp:142: instantiated from here extend_transform_xmpl.cpp:59: error: no matching function for call to 'arg_c(const xmpl_expression<boost::proto::expr<boost::proto::tag::terminal, boost::proto::args1<arg_id<1u> >, 1l> >&)'
I'm not sure if I parse the error message correctly, but I think you have to instantiate arg_c with the index. E.g. arg_c<0>(expr). Regards, Maurizio

Larry Evans wrote:
for(long ichild=0; ichild<Arity; ++ichild) { proto::eval(proto::arg_c<Expr,ichild>(expr), *this); }
That's really not going to work. If you #include proto/fusion.hpp, you can use fusion::for_each on the children nodes as follows: fusion::for_each( proto::children_of(expr), myfunc() );
template<long Index> void operator()(mpl::integral_c<long,Index>&) {
proto::eval(proto::arg_c<Expr,Index>(my_parent),my_context);
And yours is another way to skin the cat, but this line needs to be: proto::eval(proto::arg_c<Index>(my_parent),my_context); HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

On 06/01/2007 04:56 PM, Eric Niebler wrote:
Larry Evans wrote:
for(long ichild=0; ichild<Arity; ++ichild) { proto::eval(proto::arg_c<Expr,ichild>(expr), *this); }
That's really not going to work. Yeah, I knew. I was just using it to illustrate my intension. If you #include proto/fusion.hpp, you can use fusion::for_each on the children nodes as follows:
fusion::for_each( proto::children_of(expr), myfunc() );
Yes! Much simpler. All I had to do was define template<typename Child> void xmpl_context::operator()(Child const& a_child) { proto::eval(a_child.*this) } and then in xmpl_context::eval<Expr>::operator()(a_expr, a_ctx) do: fusion::for_each(proto::children_of(a_expr),a_ctx) Thanks.

Eric, just for my understanding, your suggestion is also the only way to proceed when the result type depends on Expr, right? Thanks, Maurizio On Jun 1, 2007, at 10:36 AM, Eric Niebler wrote:
Larry Evans wrote:
Hi Eric,
I need a context with something like the following methods:
template< typename Tag, typename Left, typename Right > result_type operator()(expr<Tag, Left, Right> const &expr) const { std::cout<<std::setw(indent) <<""<<"binary_expr:"<<expr.get_instance()<<"\n"; indent+=2; proto::eval(left, *this); proto::eval(right, *this); indent-=2; }
where the expression tree node argument remains "packaged":
(expr<Tag, Left, Right> const &expr)
in contrast to the unpacked version:
(Tag, Left const &left, Right const &right)
Sure. Only context types derived from callable_context get unpacked nodes like that. If you don't inherit from callable_context, you'll get the whole node without any modification. The interface is a bit different, though. You'll need something like:
struct my_context { template<typename Expr> struct eval { typedef ... result_type; result_type operator()(Expr &expr, my_context &ctx) const { return ...; } }; };
If you want to handle binary nodes specially, you would define the eval member template as:
template<typename Expr, long Arity = Expr::arity::value> struct eval
and then partially specialize for binary nodes:
template<typename Expr> struct eval<Expr, 2>
HTH,
-- Eric Niebler Boost Consulting www.boost-consulting.com _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

(Sorry for the delay, I'm just back from a week-long vacation.) Maurizio Vitale wrote:
On Jun 1, 2007, at 10:36 AM, Eric Niebler wrote:
Only context types derived from callable_context get unpacked nodes like that. If you don't inherit from callable_context, you'll get the whole node without any modification. The interface is a bit different, though. You'll need something like:
struct my_context { template<typename Expr> struct eval { typedef ... result_type; result_type operator()(Expr &expr, my_context &ctx) const { return ...; } }; };
If you want to handle binary nodes specially, you would define the eval member template as:
template<typename Expr, long Arity = Expr::arity::value> struct eval
and then partially specialize for binary nodes:
template<typename Expr> struct eval<Expr, 2>
Eric, just for my understanding, your suggestion is also the only way to proceed when the result type depends on Expr, right?
Not so. If your context type inherits from callable_context, you can define a nested result class template for calculating the return type. In this way, the return type can be made to depend on the expression type. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com

On Aug 27, 2007, at 11:54 AM, Eric Niebler wrote:
(Sorry for the delay, I'm just back from a week-long vacation.)
Not a problem, I know all about your whereabouts from your posts. Avid reader of yours I am...
Maurizio Vitale wrote:
On Jun 1, 2007, at 10:36 AM, Eric Niebler wrote:
Only context types derived from callable_context get unpacked nodes like that. If you don't inherit from callable_context, you'll get the whole node without any modification. The interface is a bit different, though. You'll need something like:
struct my_context { template<typename Expr> struct eval { typedef ... result_type; result_type operator()(Expr &expr, my_context &ctx) const { return ...; } }; };
If you want to handle binary nodes specially, you would define the eval member template as:
template<typename Expr, long Arity = Expr::arity::value> struct eval
and then partially specialize for binary nodes:
template<typename Expr> struct eval<Expr, 2>
Eric, just for my understanding, your suggestion is also the only way to proceed when the result type depends on Expr, right?
Not so. If your context type inherits from callable_context, you can define a nested result class template for calculating the return type. In this way, the return type can be made to depend on the expression type.
but you still need to explicitly pass the expression type to the context, like this: template<typename Expr> struct my_context : callabla_context<my_context<Expr> > { typedef Functor_Of<Expr>::type result_type; .... }; or am I missing a way to get to Expr in a class inheriting from callable_context? you cannot overload operator()() or you ruin the unpackaging done by callable_context. I'm using the above in my code (even though I did forget about it when asking), so if there was a better way I'd be glad to hear. Regards, Maurizio

Maurizio Vitale wrote:
On Aug 27, 2007, at 11:54 AM, Eric Niebler wrote:
(Sorry for the delay, I'm just back from a week-long vacation.)
Not a problem, I know all about your whereabouts from your posts. Avid reader of yours I am...
I'm flattered!
If your context type inherits from callable_context, you can define a nested result class template for calculating the return type. In this way, the return type can be made to depend on the expression type.
but you still need to explicitly pass the expression type to the context, like this:
template<typename Expr> struct my_context : callabla_context<my_context<Expr> > { typedef Functor_Of<Expr>::type result_type; .... };
or am I missing a way to get to Expr in a class inheriting from callable_context? you cannot overload operator()() or you ruin the unpackaging done by callable_context.
I'm using the above in my code (even though I did forget about it when asking), so if there was a better way I'd be glad to hear.
Right, so when you inherit from callable_context, it unpacks the expression and sends it to your operator(). You can't get at the expression object or its type before it was unpacked. If you need that, then callable_context isn't right for you. Just to clarify what I said earlier, a binary plus node would get passed to your context like: struct my_context : callable_context<my_context> { // ... template<class Left, class Right> some-type operator()(tag::plus, Left const& l, Right const& r) { return something; } }; my_context is "callable" in that it must satisfy the result_of protocol. So it must either have a result_type typedef, or a nested result<> class template. So, you could partially specialize the result<> template to calculate the return type of plus operations like: template<class Sig> struct result; template<class This, class Left, class Right> struct result<This(tag::plus, Left const &, Right const &)> { typedef some-type type; }; HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com
participants (4)
-
Eric Niebler
-
Larry Evans
-
Maurizio Vitale
-
Maurizio Vitale