
On Sun, Feb 28, 2010 at 8:18 PM, Eric Niebler <eric@boostpro.com> 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); }