mp/examples/et/4_separate.cpp

151 lines
2.9 KiB
C++
Raw Normal View History

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