Boost logo

Boost Users :

Subject: Re: [Boost-users] [Proto?][Phoenix?] : Advice on creating lazy data structures
From: Eric Niebler (eric_at_[hidden])
Date: 2010-04-02 21:39:34


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

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net