Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] declaring result type for callable contexts
From: Maurizio Vitale (mav_at_[hidden])
Date: 2009-06-05 16:47:54


>>>>> "Eric" == Eric Niebler <eric_at_[hidden]> writes:

    Eric> Maurizio Vitale wrote:
>> Eric, It seems like result types must be defined inside a struct
>> eval, but examples in the documentation show the form commented
>> out below.
>>
>> Is this a recent change?
>>
>> Also, in absence of a result_type declaration inside struct eval
>> {...} the type defaults to int. Would it be possible to make it
>> void or some_ugly_looking_type_that_tell_me_i_is_all_wrong? int
>> might happen to be what the user wants, until he decide to change
>> it and hides the problem.
>>
>> template<typename Expr> struct my_context :
>> proto::callable_context<const my_context<Expr> > { struct eval
>> {typedef double result_type;};
>>
>> // doesn't work (anymore?) //typedef double result_type; };

    Eric> There have been no recent changes in this area, though I have
    Eric> been reorganizing some code. The Context concept (ugh, not
    Eric> defined in the reference section, sorry) requires a nested
    Eric> eval struct template with a nested result_type typedef. Users
    Eric> can define a context that satisfies that requirement by
    Eric> inheriting from callable_context, which defines the nested
    Eric> eval<> struct for you, and is implemented in terms of member
    Eric> function overloads within the derived context type. That turns
    Eric> out to be a lot easier in most situations.

Ok, while reducing the code to something small enough for posting I
think I've got what was wrong. Let's see if it makes sense to you:

[if my prose is too long and makes little sense, you can find my code
 attached to this message]

      - my context inherits from callable_context and defines a
      result_type. But it doesn't define (yet) any overload for the
      arithmetic operations.

      - I then have a data structure that I use for terminals.
      This also has no arithmetic operators defined. BUT it
      has conversion operators to some basic types (was int, it is now
      double to see where the type was coming from)

      What I think happens is that the default_context is asked to
      evaluate expression, knows jack about my data type but happily see
      a conversion operator to a builtin type, use it and then does
      arithmetic over it using the builtin arithmetic operator.

      So proto reports the right type for the evaluation of the
      expression, it is just that it is not what I declared with
      result_type. Maybe it would be good to add an assertion for this
      case, as forgetting even one overload under the appropriate
      circumstances (e.g. conversion operator to a builtin type) can
      cause a not immediately diagnosable problem.

In the small example I cannot reproduce one aspect of what I was seeing,
namely that putting result_type inside a struct eval made proto return
what I was expecting (it would have been wrong, but I had enough
conversion operators/constructor to make it work on the surface).
My guess is that in that case proto believes in my eval and doesn't use
the callable_context one which in turns would use my context and then
falling back on default context.

Anyhow, if the above makes sense sorry for the noise.


#include <boost/proto/proto.hpp>

template<typename> struct XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX;
#define X(TYPE) \
  typedef TYPE type##__LINE__; \
  typedef typename XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<type##__LINE__>::XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX debug_ ## __LINE__

  namespace mpl = boost::mpl;
  namespace proto = boost::proto;
  using proto::_;

  struct systemc_grammar : proto::or_ <
    proto::terminal<struct data>,
    proto::unary_expr<_, systemc_grammar>,
    proto::binary_expr<_, systemc_grammar, systemc_grammar>
> {};

  template <typename Expr>
  struct systemc_expression : proto::extends<Expr, systemc_expression<Expr>, struct systemc_domain> {
    typedef proto::extends<Expr, systemc_expression<Expr>, struct systemc_domain> base_type;
    
    systemc_expression (Expr const& expr_ = Expr()) : base_type (expr_) {}

    operator int () const { return systemc_eval (*this); }
  };

  struct systemc_domain : proto::domain<proto::generator<systemc_expression>, struct systemc_grammar> {};
      
  template<typename Expr>
  struct systemc_context : proto::callable_context<const systemc_context<Expr> > {
    typedef data result_type;
  };

  template<typename Expr>
  typename boost::remove_reference<typename proto::result_of::eval< Expr, systemc_context<Expr> >::type>::type
  systemc_eval (const Expr& expr) {
    typedef typename boost::remove_reference<typename proto::result_of::eval< Expr, systemc_context<Expr> >::type>::type t;
    typedef typename proto::result_of::eval< Expr, systemc_context<Expr> >::type tt;
    
    return proto::eval (expr, systemc_context<Expr> ());
  }

  struct data {
    data () : m_data () {}
    operator double () const { return m_data; }
    double m_data;
  };

  template<typename E>
  void coerce (data& target, const E& source) {
    BOOST_AUTO (source_data, systemc_eval (source));
    X (BOOST_TYPEOF (source_data));
    target = source_data & 0xf;
  }

  struct number : systemc_expression<proto::terminal<data>::type> {
    typedef systemc_expression<proto::terminal<data>::type> base_type;

    number () : base_type (base_type::proto_base_expr::make (data ())) {}

    template<typename E>
    number& operator=(const E& e) {
      coerce (proto::value (*this), e);
      return *this;
    }
  };

int main (int, char**) {
  number a,b,c;
  a = b*c;
}


      
    Eric> In short, if you're using callable_context, don't define
    Eric> nested eval<> structs. If you have some code that recently
    Eric> stopped working, you should post it so I can see that the
    Eric> problem is.

    Eric> -- Eric Niebler BoostPro Computing http://www.boostpro.com

-- 
Maurizio Vitale
Polymath Solutions

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