Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] defining function call operators on expressions
From: Manjunath Kudlur (keveman_at_[hidden])
Date: 2010-03-02 15:47:48


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

Here is the code as per the above suggestion, preserved for posterity :

#include <boost/proto/proto.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/utility.hpp>
#include <boost/type_traits/is_same.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 _var_arity
  : proto::or_<
  proto::when<proto::terminal<Var<proto::_> >, proto::make<mpl::int_<1> > >
> {};

struct _prog_arity
  : proto::or_<
proto::when<
proto::function<proto::terminal<program_>,
proto::vararg<proto::terminal<Var<proto::_> > > >,
proto::fold<proto::functional::pop_front(proto::_expr),
proto::make<mpl::int_<0> >,
proto::make<mpl::plus<proto::_state, _var_arity> > > >
> {};

template<typename Expr>
struct prog_arity
  : boost::result_of<_prog_arity(Expr)>
{};

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;

  template<typename A0>
  result_type operator()(A0 a0) const {
    BOOST_MPL_ASSERT_RELATION(1, ==, prog_arity<Expr>::type::value);
    BOOST_MPL_ASSERT((boost::is_same<A0, typename
boost::result_of<call_param_type<0>(const Expr &)>::type>));
    std::cout << "program with one arg\n";
  }

  template<typename A0, typename A1>
  result_type operator()(A0 a0, A1 a1) const {
    BOOST_MPL_ASSERT_RELATION(2, ==, prog_arity<Expr>::type::value);
    BOOST_MPL_ASSERT((boost::is_same<A0, typename
boost::result_of<call_param_type<0>(const Expr &)>::type>));
    BOOST_MPL_ASSERT((boost::is_same<A1, typename
boost::result_of<call_param_type<1>(const Expr &)>::type>));
    std::cout << "program with two args\n";
  }

  template<typename A0, typename A1, typename A2>
  result_type operator()(A0 a0, A1 a1, A2 a2) const {
    BOOST_MPL_ASSERT_RELATION(3, ==, prog_arity<Expr>::type::value);
    BOOST_MPL_ASSERT((boost::is_same<A0, typename
boost::result_of<call_param_type<0>(const Expr &)>::type>));
    BOOST_MPL_ASSERT((boost::is_same<A1, typename
boost::result_of<call_param_type<1>(const Expr &)>::type>));
    BOOST_MPL_ASSERT((boost::is_same<A2, typename
boost::result_of<call_param_type<2>(const Expr &)>::type>));
    std::cout << "program with three 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));
}

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

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

  int p1 = 10, p2 = 20, p3 = 30;

  Program_(a)(p1);
  Program_(a,b)(10, p2);
  Program_(a,b,c)(10, 20, p3);

}


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