
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; };