Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] defining function call operators on expressions
From: Manjunath Kudlur (keveman_at_[hidden])
Date: 2010-03-01 22:31:31


On Sun, Feb 28, 2010 at 8:18 PM, Eric Niebler <eric_at_[hidden]> wrote:
> 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.

Thanks, it seems obvious now :). I am including my code too, so that
there is one more example for people to look at. I began wondering
about a related problem when writing this code. Because of the way
program_generator is defined below, any expression of the form
Program_(a0, a1... an) gets wrapped in program_expr. Suppose I want to
restrict the number of parameters to the function call operator to the
number of arguments to Program_(). In other words, I want to make
Program_(a0, a1)(10, 20, 30), Program_(a0, a1)(10) etc. illegal. I can
invent one expression wrapper for every possible Program_(..) and in
that wrapper class, define the function call operator with the correct
number of arguments, i.e., wrap Program_(a0) in program1_expr, wrap
Program_(a0, a1) in program2_expr etc., and define these classes. That
would work of course. 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?

Manjunath

#include <boost/proto/proto.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/utility.hpp>

#include <iostream>
#include <sstream>
#include <string>

namespace proto=boost::proto;
namespace mpl=boost::mpl;

unsigned int ids;

template<typename VT>
struct Var {
  unsigned int id;
  Var() {
    id = ++ids;
  }
};

typedef proto::terminal<Var<int> >::type int32_;
typedef proto::terminal<Var<float> >::type float_;

struct program_ {};

template<class E> struct program_expr;

struct call_grammar
  : proto::or_<
proto::function<
proto::terminal<program_>,
proto::vararg<proto::terminal<Var<proto::_> > > >
> {};

struct program_generator
  : proto::or_<
proto::when<call_grammar, proto::pod_generator<program_expr>(proto::_expr) >,
proto::otherwise<proto::_expr>
> {};

struct program_domain
  : proto::domain<program_generator>
{};

struct _var_type
  : proto::callable {

  template<typename Sig>
  struct result;

  template<typename This, typename T>
  struct result<This(const Var<T> &)> {
    typedef T type;
  };
};

struct var_type
  : proto::or_<
proto::when<proto::terminal<Var<proto::_> >,
_var_type(proto::_value)>
> {};

template<int N>
struct call_param_type
  : proto::or_<
proto::when<
proto::function<
proto::terminal<program_>,
proto::vararg<proto::terminal<Var<proto::_> > > >,
var_type(proto::_child_c<N+1>)>
> {};

template <typename Expr>
struct program_expr {
  BOOST_PROTO_BASIC_EXTENDS(Expr, program_expr<Expr>, program_domain);
  BOOST_PROTO_EXTENDS_SUBSCRIPT();

  typedef void result_type;

  result_type operator()(typename
                         boost::result_of<call_param_type<0>(const
Expr &)>::type x) const {
    std::cout << "program with one arg\n";
  }

  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) const {
    std::cout << "program with two args\n";
  }
};

template<typename A0>
typename proto::result_of::make_expr<proto::tag::function
, program_domain
, program_
, A0 const &>::type const
Program_(A0 const &a0)
{
  return proto::make_expr<proto::tag::function, program_domain>(
                                                                program_(),
                                                                boost::ref(a0));
}

template<typename A0, typename A1>
typename proto::result_of::make_expr<proto::tag::function
, program_domain
, program_
, A0 const &
, A1 const &>::type const
Program_(A0 const &a0, A1 const &a1)
{
  return proto::make_expr<proto::tag::function, program_domain>(
                                                                program_(),
                                                                boost::ref(a0),
                                                                boost::ref(a1));
}

int main()
{
  int32_ a,b,c;

  //Program_(a)(10);
  Program_(a, b)(10, 20);
  Program_(a, b)(10);
}


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