Skip to content

Instantly share code, notes, and snippets.

@fritschy
Created August 31, 2011 13:59
Show Gist options
  • Save fritschy/1183596 to your computer and use it in GitHub Desktop.
Save fritschy/1183596 to your computer and use it in GitHub Desktop.
Expression template example, "binds" an expression to a variable.
#include <iostream>
#define SHOW_EXPRESSION() std::cout << __PRETTY_FUNCTION__ << std::endl
namespace expr
{
template<typename E> float Eval(E const &e) { return e.eval(); }
float Eval(float e) { return e; }
struct val
{
float v;
template <typename E> val(E const &e) : v(Eval(e)) {}
float eval() const { return v; }
};
std::ostream &operator<<(std::ostream &os, val const &v) { return os << v.v; }
struct Mul { static float op(float a, float b) { return a * b; } };
struct Div { static float op(float a, float b) { return a / b; } };
struct Plus { static float op(float a, float b) { return a + b; } };
struct Minus { static float op(float a, float b) { return a - b; } };
struct Neg { static float op(float a) { return -a; } };
inline char Symbol(Mul) { return '*'; }
inline char Symbol(Div) { return '/'; }
inline char Symbol(Plus) { return '+'; }
inline char Symbol(Minus) { return '-'; }
inline char Symbol(Neg) { return '-'; }
struct BaseExpr // solely needed to bind temporary Exprs to const refs...
{
virtual float eval() const = 0;
virtual void show(std::ostream &) const = 0;
};
template<typename Op, typename Ea>
struct UnaryExpr : public BaseExpr
{
Ea const a;
UnaryExpr(Ea const &A) : a(A) {}
virtual float eval() const { SHOW_EXPRESSION(); return Op::op(Eval(a)); }
virtual void show(std::ostream &os) const { os << Symbol(Op()) << a; }
};
template<typename Op, typename Ea, typename Eb>
struct BinaryExpr : public BaseExpr
{
Ea const a;
Eb const b;
BinaryExpr(Ea const &A, Eb const &B) : a(A), b(B) {}
virtual float eval() const { SHOW_EXPRESSION(); return Op::op(Eval(a), Eval(b)); }
virtual void show(std::ostream &os) const { os << '(' << a << ' ' << Symbol(Op()) << ' ' << b << ')'; }
};
template<typename Ea, typename Eb> BinaryExpr<Plus, Ea, Eb> operator+(Ea const &a, Eb const &b) { return BinaryExpr<Plus, Ea, Eb>(a, b); }
template<typename Ea, typename Eb> BinaryExpr<Minus, Ea, Eb> operator-(Ea const &a, Eb const &b) { return BinaryExpr<Minus, Ea, Eb>(a, b); }
template<typename Ea, typename Eb> BinaryExpr<Mul, Ea, Eb> operator*(Ea const &a, Eb const &b) { return BinaryExpr<Mul, Ea, Eb>(a, b); }
template<typename Ea, typename Eb> BinaryExpr<Div, Ea, Eb> operator/(Ea const &a, Eb const &b) { return BinaryExpr<Div, Ea, Eb>(a, b); }
template<typename E> UnaryExpr<Neg, E> operator-(E const &e) { return UnaryExpr<Neg, E>(e); }
std::ostream &operator<<(std::ostream &os, BaseExpr const &e) { e.show(os); return os; }
}
int main()
{
expr::val v(1.f);
expr::val w(v*2.3f);
expr::BaseExpr const &e = w+v+w*5.1f+v/w*v*w;
// (((2.3 + 1) + (2.3 * 5.1)) + (((1 / 2.3) * 1) * 2.3)) = 16.03
std::cout << e << " = " << expr::Eval(e) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment