#include #include #include #include /* **** */ /* tags */ namespace tag { struct Argument; struct Add; struct Mul; struct Minus; struct Less; } /* ********** */ /* 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}; } template< typename LHS, typename RHS, std::enable_if_t && IsExpr>* = nullptr > auto operator<(LHS lhs, RHS rhs) { return Expr{lhs, 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; } }; template<> struct EvaluatorElem { template static auto eval(T lhs, T rhs) { return lhs < 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, bool Impl = false> struct Evaluable { using Evaluator = EvaluatorTemplate>; Expression expr; static constexpr std::size_t arity = MaxArgument + 1; template= arity)>* = nullptr> auto operator()(Arguments... arguments) { static_assert(Impl || sizeof...(Arguments) <= arity, "too many arguments"); using IndexSequence = std::make_index_sequence{}>; return eval(IndexSequence{}, arguments...); } template* = nullptr> auto operator()(Arguments...) { static_assert(sizeof...(Arguments) >= arity, "too few arguments"); } private: 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, true>{expr}(arguments...); } }; template class Evaluator, typename Expr> auto bind(Expr expr) { return Evaluable{expr}; } /* ******** */ /* examples */ void directCall() { using namespace arg; int volatile v0 = 3, v1 = 5, v2 = 7, v3 = 9; int result; auto expr = _1 * -(_2 + _0) + _3 * _0; auto fElem = bind(expr); result = fElem(v0, v1, v2, v3); std::printf("result: %d\n", result); } void lambda() { using namespace arg; std::vector v{5, 7, 3, 1, 6, 9, 4, 2}; std::vector w(v.size()); std::sort(std::begin(v), std::end(v), bind(_1 < _0)); std::transform(std::begin(v), std::begin(w), std::begin(w), bind(_0 * _0)); for(auto i: v) std::printf("%d ", i); std::puts(""); for(auto i: w) std::printf("%d ", i); std::puts(""); } int main() { directCall(); lambda(); }