
On 3/30/2010 12:48 PM, Manjunath Kudlur wrote:
Thanks, Eric. That was an Ah-ha moment for me. I tried a different variation of your program. I changed point to a templated tuple<typename X, typename Y> and declared the terminals x and y with proto::_ template arguments. Here is the complete program :
<snip> Sorry for the delay. I've been away from my computer. This is indeed a tricky problem. The trick is to realize that grammars can be made open and extensible in a variety of ways. The simple is to define a customization point. What you need is a way to plug into an existing grammar new classes and members. Define a get_member_ptr template that users of your grammar can use to make it aware of third-party types. Code attached below: #include <cassert> #include <iostream> #include <boost/proto/proto.hpp> namespace proto = boost::proto; using proto::_; template<typename T> struct type2type {}; template<typename T> struct tag {}; template<typename T, typename MemTag> struct get_mem_ptr; struct get_mem_ptr_wrap : proto::callable { template<typename Sig> struct result; template<typename This, typename T, typename MemTag> struct result<This(type2type<T>, tag<MemTag> const &)> : boost::result_of<get_mem_ptr<T, MemTag>()> {}; template<typename T, typename MemTag> typename boost::result_of<get_mem_ptr<T, MemTag>()>::type operator()(type2type<T>, tag<MemTag> const &) const { return get_mem_ptr<T, MemTag>()(); } }; template<typename X, typename Y> struct pair { X x; Y y; }; struct x_tag {}; struct y_tag {}; template<typename X, typename Y> struct get_mem_ptr<pair<X, Y>, x_tag> { typedef X pair<X, Y>::*result_type; result_type operator()() const { return &pair<X, Y>::x; } }; template<typename X, typename Y> struct get_mem_ptr<pair<X, Y>, y_tag> { typedef Y pair<X, Y>::*result_type; result_type operator()() const { return &pair<X, Y>::y; } }; proto::terminal<tag<x_tag> >::type const x = {{}}; proto::terminal<tag<y_tag> >::type const y = {{}}; struct arg_ {}; proto::terminal<arg_>::type arg = {{}}; struct micro_lambda : proto::or_< proto::when< proto::mem_ptr<_, proto::terminal<tag<_> > > , micro_lambda( proto::_make_mem_ptr( proto::_left , proto::_make_terminal( get_mem_ptr_wrap( type2type<micro_lambda(proto::_left)>() , proto::_value(proto::_right) ) ) ) ) > , proto::when< proto::terminal<arg_> , proto::_state > , proto::otherwise< proto::_default<micro_lambda> > > {} eval; int main() { pair<int, float> p = {2,4.f}; float r = eval( arg->*x + arg->*y, p ); assert( r == p.x + p.y ); std::cout << r << std::endl; eval( arg->*x *= 21, p ); assert( p.x == 42 ); std::cout << p.x << std::endl; } Note that the x and y globals are no longer raw member pointer terminals but tags. The grammar recognizes tags and uses them to look up the actual member pointer. It also needs to know the class type, so that is calculated and also passed along. This code runs compiles and runs fine with gcc. Msvc doesn't like it. But maybe you can sort that out. -- Eric Niebler BoostPro Computing http://www.boostpro.com