Boost logo

Boost :

From: Maurizio Vitale (mav_at_[hidden])
Date: 2007-05-14 22:55:39

I'm not sure whether what I'm trying is possible, but I'm asking anyhow, that's cheap.

I have a context like the following, which overloads operator() for a bunch of terminals
and a predefined mask(left,right) and mask(what, left, right):

    template<typename Expr, typename Target, typename Source>
    struct meta_context : proto::callable_context<const meta_context<Expr,Target,Source> > {

      typedef meta_context<Expr, Target, Source> self;

      typedef unsigned int result_type;

      meta_context (const Target& target, const Source& source) : m_target (target), m_source (source) {}

    #define RESULT_FOR(NAME, EXPR) result_type operator () (proto::tag::terminal, NAME##_tag NAME) const { return EXPR; }

      RESULT_FOR (source, proto::arg(m_source).m_data)
      RESULT_FOR (source_left, proto::arg(m_source).left ())
      RESULT_FOR (source_right, proto::arg(m_source).right ())

      RESULT_FOR (target, proto::arg(m_target).m_data)
      RESULT_FOR (target_left, proto::arg(m_target).left ())
      RESULT_FOR (target_right, proto::arg(m_target).right ())

      template<typename What, typename Left, typename Right>
      result_type operator () (mask_tag, const What& what, const Left& left, const Right& right) const {
        std::size_t what_value = proto::eval (what, *this);
        std::size_t left_value = proto::eval (left, *this);
        std::size_t right_value = proto::eval (right, *this);

        if (left_value == sizeof (unsigned long long)*8)
          return what_value & (~0ULL << right_value);
          return what_value & (~(~1ull << (left_value-1) | ~(~0ull << right_value)));

      template<typename Left, typename Right>
      result_type operator () (mask_tag, const Left& left, const Right& right) const {
        std::size_t left_value = proto::eval (left, *this);
        std::size_t right_value = proto::eval (right, *this);

        if (left_value == sizeof (unsigned long long)*8)
            return ~0ULL << right_value;
            return ~(~1ull << (left_value-1) | ~(~0ull << right_value));

    #undef RESULT_FOR

      const Target& m_target;
      const Source& m_source;

This is find and does its job, delegating most of the work to inherithed defaults.
Now I'd like to shortcut the run-time evaluation when a value can be determined solely from the type.
Let's assume I have a transform that returns either an mpl::int_<> giving the compile time value
or the special type run_time when no compile time result can be computed.

I know (haven't tried, so it's just a semi-educated guess) that I could just overload everything,
check whether none of the arguments returns run_time, rebuild the original expression type
(because I think once I'm in one of the operator() overloads the expression is decomposed in
tag and arguments, with the complete one available nowhere), call the transform on
the newly created expression and return the compile time value.
If any of the arguments evaluate to run_time, do the run-time processing.

But this overloading everything is not what I'd like. What I'd like is to leave the few overloads
that do something special in the context and in addition overload eval like this:

    template<typename Expr1>
    struct eval
      typedef typename self::result_type result_type;
      result_type operator()(Expr1 const &expr, self &ctx) {
        ... do compile time evaluation ...
        ... if known, return value, otherwise:
        return proto::default_eval<Expr1, self>()(expr, ctx);

Except that this doesn't quite do it, default_eval knows nothing about the semantics of my terminals and
But I cannot simply call proto::eval either.

Is there a way to do this in proto already, so that some additional behaviour can be spliced in before
the normal (but not the default) behaviour?



Boost list run by bdawes at, gregod at, cpdaniel at, john at