#include #include /* **** */ /* tags */ namespace tag { struct Add; struct Mul; struct Minus; } /* ********** */ /* expression */ template class Expr { std::tuple _operands; public: Expr(Operands... operands): _operands{operands...} {} template class Evaluator> auto eval() const { return eval(std::make_index_sequence{}); } private: template class Evaluator, std::size_t... Is> auto eval(std::index_sequence) const { return Evaluator::eval(std::get(_operands).template eval()...); } }; template class Value { T _value; public: Value(T value): _value(value) {} template class> auto eval() const { return _value; } }; /* *********** */ /* type traits */ namespace impl { template struct IsExpr: std::false_type {}; template struct IsExpr>: std::true_type {}; template struct IsExpr>: std::true_type {}; } template constexpr bool IsExpr = impl::IsExpr::value; template< typename LHS, typename RHS, std::enable_if_t && IsExpr>* = nullptr > auto operator+(LHS lhs, RHS rhs) { return Expr{lhs, rhs}; } template< typename LHS, typename RHS, std::enable_if_t && IsExpr>* = nullptr > auto operator*(LHS lhs, RHS rhs) { return Expr{lhs, rhs}; } template< typename RHS, std::enable_if_t>* = nullptr > auto operator-(RHS rhs) { return Expr{rhs}; } /* ********** */ /* evaluators */ template struct EvaluatorElem; template<> struct EvaluatorElem { template static auto eval(T lhs, T rhs) { return lhs + rhs; } }; template<> struct EvaluatorElem { template static auto eval(T lhs, T rhs) { return lhs * rhs; } }; template<> struct EvaluatorElem { template static auto eval(T rhs) { return -rhs; } }; /* *** */ template struct EvaluatorBool; template<> struct EvaluatorBool { static auto eval(bool lhs, bool rhs) { return lhs or rhs; } }; template<> struct EvaluatorBool { static auto eval(bool lhs, bool rhs) { return lhs and rhs; } }; template<> struct EvaluatorBool { static auto eval(bool rhs) { return not rhs; } }; /* *** */ template class Evaluator, typename Expr> auto eval(Expr expr) { return expr.template eval(); } int main() { int volatile v[]{1, 1, 1}; int result; Value v0{v[0]}, v1{v[1]}, v2{v[2]}; auto expr = v0 * -(v1 + v2); result = eval(expr); std::printf("evaluator elem: %d\n", result); result = eval(expr); std::printf("evaluator bool: %d\n", result); }