|
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