Boost logo

Boost :

From: Maurizio Vitale (mav_at_[hidden])
Date: 2007-05-15 17:02:14


Waiting for Eric, the following works, although it is way more verbose than if a single eval overload could
be spliced in, before other operator() overloads. The trick is to only specialize eval, rather than mixing
eval and operator ()s.

I also think this solution is much heavier on the compiler.

The assembly code I get is very nice, and for now I don't seem to need
compile-time simplifications: what I've seen in assembler is
optimal. Still it gives a warm feeling to know that there're place
where optimizations can be placed as needed.

--------------------------------------------------------------------------------------------------------

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) {}

  template<typename T> struct aux : mpl::if_<boost::is_same<T,run_time>, mpl::false_, T> {};

  template<typename Expr_, typename Enable=void>
  struct eval : proto::default_eval<Expr_, self> {
    typedef unsigned int result_type;

    result_type operator () (const Expr_& expr, self ctx) {
      typedef typename meta_transform<Target, Source>::template apply<Expr_,mpl::void_, mpl::void_>::type result;

      if (boost::is_same<result, run_time>::value)
        return proto::default_eval<Expr_,self>::operator () (expr, ctx);
      else
        return aux<result>::type::value;
    }
  };

#define RESULT_FOR(NAME, EXPR) \
  template<typename Expr_> \
  struct eval<Expr_, typename boost::enable_if<proto::matches<Expr_, proto::terminal<NAME##_tag> > >::type> { \
    typedef unsigned int result_type; \
    result_type operator () (const Expr_& expr, self ctx) { \
      return EXPR; \
    } \
  };
  RESULT_FOR (source, proto::arg(ctx.m_source).m_data)
  RESULT_FOR (source_left, proto::arg(ctx.m_source).left ())
  RESULT_FOR (source_right, proto::arg(ctx.m_source).right ())

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

  template<typename Expr_>
  struct eval<Expr_, typename boost::enable_if<proto::matches<Expr_, proto::binary_expr<mask_tag, proto::_, proto::_> > >::type> {
    typedef unsigned int result_type;
    result_type operator () (const Expr_& expr, self ctx) {
      typedef typename meta_transform<Target, Source>::template apply<Expr_,mpl::void_, mpl::void_>::type result;
      if (boost::is_same<result, run_time>::value) {
        std::size_t left_value = proto::eval(proto::arg_c<0>(expr), ctx);
        std::size_t right_value = proto::eval(proto::arg_c<1>(expr), ctx);

        return ... run-time value ...
      } else
        return aux<result>::type::value;
    }
  };

  template<typename Expr_>
  struct eval<Expr_, typename boost::enable_if<proto::matches<Expr_, proto::nary_expr<mask_tag, proto::_, proto::_, proto::_> > >::type> {
    typedef unsigned int result_type;
    result_type operator () (const Expr_& expr, self ctx) {
      typedef typename meta_transform<Target, Source>::template apply<Expr_,mpl::void_, mpl::void_>::type result;
      if (boost::is_same<result, run_time>::value) {
        std::size_t what_value = proto::eval(proto::arg_c<0>(expr), ctx);
        std::size_t left_value = proto::eval(proto::arg_c<1>(expr), ctx);
        std::size_t right_value = proto::eval(proto::arg_c<2>(expr), ctx);

        return ... run-time value ...
      } else
        return aux<result>::type::value;
    }
  };

  #undef RESULT_FOR

  const Target& m_target;
  const Source& m_source;
};


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk