Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] defining function call operators on expressions
From: Eric Niebler (eric_at_[hidden])
Date: 2010-02-28 23:18:45


On 3/1/2010 2:21 PM, Manjunath Kudlur wrote:
> Yeah, got it. I realise now that the passing a domain to make_expr
> wraps all the components of the expression also with the corresponding
> expression class. What I am unable to figure out it how to wrap only
> the final expression I want with program_expr. In this case I want to
> wrap expr<tag::function, vararg<terminal<Var> > > with program_expr.
> Is there an example I can look at that does something similar? Or is
> this the wrong way to look at the problem? Basically, I want to add
> the function call operator to my expressions, but only to expressions
> of certain forms. My thinking is, if I only wrap expressions of that
> certain form with my expression class, I should be OK, no?
>

Ah, you want a different expression interface based on the structure of
the expression being wrapped. There's a straightforward way to do that,
but it's not obvious. See the program below.

   #include <boost/utility/result_of.hpp>
   #include <boost/utility/enable_if.hpp>
   #include <boost/proto/proto.hpp>

   namespace proto = boost::proto;
   using proto::_;

   // This wrapper is for function expressions
   template<typename Expr>
   struct function_expr;

   // This wrapper is for all other expressions
   template<typename Expr>
   struct program_expr;

   struct function_call
     : proto::function< proto::vararg< proto::terminal<_> > >
   {};

   struct program_generator
     : proto::or_<
           // Wrap function expressions in function_expr
           proto::when<
               function_call
               // pod_generator is a function object and
               // so can be used to make this callable
               // transform
             , proto::pod_generator<function_expr>(_)
>
           // Wrap all other expressions in program_expr
         , proto::otherwise<
               proto::pod_generator<program_expr>(_)
>
>
   {};

   // A program_generator satisfies the requirement for
   // a proto generator because it is a unary function
   // object, albeit a rather complicated one.
   struct program_domain
     : proto::domain< program_generator >
   {};

   template<typename Expr>
   struct function_expr
   {
       BOOST_PROTO_BASIC_EXTENDS(Expr, function_expr<Expr>, program_domain)
       BOOST_PROTO_EXTENDS_FUNCTION()
       void I_am_a_function() const {}
   };

   template<typename Expr>
   struct program_expr
   {
       BOOST_PROTO_BASIC_EXTENDS(Expr, program_expr<Expr>, program_domain)
       BOOST_PROTO_EXTENDS_FUNCTION()
       void I_am_not_a_function() const {}
   };

   program_expr<proto::terminal<int>::type> i = {{1}};
   program_expr<proto::terminal<int>::type> j = {{2}};

   int main()
   {
       i.I_am_not_a_function();

       (i + j).I_am_not_a_function();

       i(j).I_am_a_function();

       (i(j) + j(i)).I_am_not_a_function();
   }

-- 
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