Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] defining function call operators on expressions
From: Eric Niebler (eric_at_[hidden])
Date: 2010-03-02 03:11:53


On 3/2/2010 6:24 PM, Joel Falcou wrote:
> Manjunath Kudlur wrote:
>> Is there a way to define member functions in the
>> wrapper class that are valid only for certain kinds of expressions? I
>> experimented a little with boost::enable_if, but that didn't seem to
>> work. Any thoughts?
>
> Look at how the proto calculator works. You just need to compute () ariy
> using a transform adn then juse a static assert in the expression
> evaluation

It's not actually quite that simple in this case. Manjunath has defined
his function call overloads as follows:

   result_type operator()(
      typename
          boost::result_of<call_param_type<0>(const Expr &)>::type x,
      typename
          boost::result_of<call_param_type<1>(const Expr &)>::type y)

This function is *not* a template, so the types mentioned in its
signature are evaluated eagerly. The call_param_type transform extracts
the Nth child from Expr. If Expr doesn't have enough child nodes, it
violates the transform's preconditions. Compiler errors are sure to result.

One solution would be to rewrite the overloads as:

   template<typename A0, typename A1>
   result_type operator()(A0 const &a0, A1 const &a0) const

and then within the function add compile-time assertions that (a) the
number of arguments is currect, and (b) that each argument type is
implicitly convertible to the expected types.

The other option would be to move the function call overloads into a
CRTP base that is partially specialized on the number of arguments, like:

   template<class Expr, long Arity = Expr::proto_arity_c>
   struct program_expr_base;

   template<class Expr>
   struct program_expr_base<Expr, 2>
   {
     void operator()(
       typename boost::result_of<
         call_param_type<0>(Expr const &)
>::type x
     ) const
     { ... }
   };

   // more specializations. See docs for BOOST_PROTO_LOCAL_ITERATE
   // and friends

Then your program_expr inherits from program_expr_base. At this point, I
would also give up on making program_expr a POD and just use
proto::extends. Finally, there'll be an ambiguity because both
program_expr_base and boost::extends will define operator(). To resolve
that, you'll need "using program_expr_base<Expr>::operator();" in
program_expr.

HTH,

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