|
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