#include #include /* **** */ /* tags */ namespace tag { struct Argument; struct Add; struct Mul; struct Minus; } /* ********** */ /* expression */ template struct Expr { std::tuple operands; Expr(Operands... operands): operands{operands...} {} }; template struct Argument {}; namespace arg { Argument<0> _0; Argument<1> _1; Argument<2> _2; Argument<3> _3; // ... } /* *********** */ /* 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 value) { return value; } }; 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; } }; /* *** */ namespace impl { template struct GetExprOp; template struct GetExprOp> { using type = Op; }; } template using GetExprOp = typename impl::GetExprOp::type; namespace impl { template struct MaxArgument; template struct MaxArgument: std::integral_constant::value> {}; template struct MaxArgument, Arguments...> { static constexpr std::size_t M = MaxArgument::value; static constexpr std::size_t value = I>M? I:M; }; template struct MaxArgument, Arguments...> { static constexpr std::size_t M0 = MaxArgument::value; static constexpr std::size_t M1 = MaxArgument::value; static constexpr std::size_t value = M0>M1? M0:M1; }; template<> struct MaxArgument<>: std::integral_constant {}; } template constexpr std::size_t MaxArgument = impl::MaxArgument::value; template class EvaluatorTemplate, typename BoundArgs = std::tuple<>, bool Impl = false> struct Evaluable { using Evaluator = EvaluatorTemplate>; Expression expr; BoundArgs boundArgs; static constexpr std::size_t arity = MaxArgument + 1 - std::tuple_size{}; template= arity>* = nullptr> auto operator()(Arguments... arguments) { static_assert(Impl || sizeof...(Arguments) <= arity, "too many arguments"); using IndexSequence = std::make_index_sequence{}>; return evalBound(IndexSequence{}, arguments...); } template* = nullptr> auto operator()(Arguments... arguments) { auto newBoundArgs = std::tuple_cat(boundArgs, std::make_tuple(arguments...)); return Evaluable{expr, newBoundArgs}; } private: template auto evalBound(std::index_sequence, Arguments... arguments) { using IndexSequence = std::make_index_sequence{}>; return eval(IndexSequence{}, std::get(boundArgs)..., arguments...); } template auto eval(std::index_sequence, Arguments... arguments) { using IndexSequence = std::index_sequence; return Evaluator::eval(std::get(resolveOperands(IndexSequence{}, expr.operands, arguments...))...); } template auto resolveOperands(std::index_sequence, T tuple, Arguments... arguments) { return std::make_tuple(resolveOperand(std::get(tuple), arguments...)...); } template auto resolveOperand(Argument, Arguments... arguments) { return std::get(std::make_tuple(arguments...)); } template auto resolveOperand(Expr expr, Arguments... arguments) { return Evaluable, EvaluatorTemplate, std::tuple<>, true>{expr, {}}(arguments...); } }; template class Evaluator, typename Expr> auto bind(Expr expr) { return Evaluable{expr, {}}; } int main() { int volatile v0 = 3, v1 = 5, v2 = 7, v3 = 9; int result; using namespace arg; auto expr = _1 * -(_2 + _0) + _3 * _0; auto fElem = bind(expr); auto fCurry = fElem(v0); result = fCurry(v1)(v2)(v3); std::printf("result: %d\n", result); }