Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] const-ness of references
From: Manjunath Kudlur (keveman_at_[hidden])
Date: 2010-03-05 00:38:32


> Well, your domain's generator is a little unusual in that not all the
> expressions it generates are, in fact, within your domain. That's not a
> stated post-condition of the Generator parameter, but it probably should be.
> In short, make_expr is assuming that the generator is returning a new
> object, and so it is storing it by value.

In my case, I am treating the domain mechanism as a means to add a new
property to my expression. I want that property to hold only for the
expression of the form Program_(...), and that's why I have the
generator the way it is. To be honest, I assumed that you provide the
domain mechanism just for this purpose (i.e., add new properties to
expressions).

> I could hack Proto to make this case work, but doing so makes me
> uncomfortable. I don't think I want to support generators that don't return
> expressions in the right domain.

Well, I did get my case working by creating a new generator,
by_ref_generator, and taking the terminals passed to the Program_
function as references (NOT const refs). Here is the code :

#include <boost/proto/proto.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <iostream>
#include <sstream>
#include <string>

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

template<typename VT>
struct Var {
  VT value;
  void assign(const VT v) {
    value = v;
  }
};

struct program_ {};

struct _assign
  : proto::callable {

  typedef void result_type;

  template<typename VT>
  result_type operator()(Var<VT> &var) const {
    var.assign(20);
  }

  template<typename VT>
  result_type operator()(Var<VT> &var, const VT val) const {
    var.assign(val);
  }
};

struct by_ref_generator
{
  BOOST_PROTO_CALLABLE()

  template<typename Sig>
  struct result;

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

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

  template<typename Expr>
  typename result<by_ref_generator(Expr &)>::type operator ()(Expr &e) const
  {
    return e;
  }
};

struct assign
  : proto::or_<
proto::when<proto::terminal<Var<proto::_> >,
_assign(proto::_value)>,
proto::when<proto::assign<proto::terminal<Var<proto::_> >,
            proto::literal<proto::_> >,
_assign(proto::_value(proto::_left), proto::_value(proto::_right))>,
proto::when<proto::function<proto::terminal<Var<proto::_> >,
proto::literal<proto::_> >,
_assign(proto::_value(proto::_left), proto::_value(proto::_right))>
> {};

template<class E> struct program_expr;

struct program_generator
  : proto::or_<
proto::when<proto::function<proto::terminal<program_>,
            proto::terminal<Var<proto::_> > >,
proto::pod_generator<program_expr>(proto::_expr)>,
proto::when<proto::terminal<Var<proto::_> >,
by_ref_generator(proto::_expr)>,
proto::otherwise<proto::_expr>
> {};

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

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

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()(int a) {
    std::cout << "program with one arg\n";
    (proto::value(proto::child_c<1>(*this))).assign(a);
  }
};

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

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

  assign()(a=20);
  assign()(a(35));

  Program_(a)(40);
  std::cout << proto::value(a).value << std::endl;
  Program_(a)(50);
  std::cout << proto::value(a).value << std::endl;

}


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