// CS 509 - Advanced Programming II
// Spring 2004
//
// The definitions for expression templates with value-passing evaluation.

#ifndef _ettl_h_defined_
#define _ettl_h_defined_

// The type of the value returned by evaluate().

   typedef double result_type;


class literal {

  public:

    // Create an expression that always evaluates to the given value. 

       literal(result_type v) : value(v) { }


    // Evaluate this expression. 

       result_type evaluate(result_type) const {
	 return value;
	 }

  private:

    result_type value;

  };


class variable {

  public:

  // Evaluate this expression.

     result_type evaluate(result_type v) const {
       return v;
       }
  };


// The default type-representation mapping.

   template <class ValueType>
   struct representation {
     typedef ValueType type;
     };


// Type-representation mapping specializations for pod types.

   template <>
   struct representation<int> {
     typedef literal type;
     };

   template <>
   struct representation<float> {
     typedef literal type;
     };

   template <>
   struct representation<double> {
     typedef literal type;
     };


template < class Operand, class UnaryOp >
class unary_expression {

  public:

  // Create an expression that evaluates to the result of applying the given
  // unary operation to the result of evaluating the given expression.

     unary_expression(
       Operand e, UnaryOp op = UnaryOp())
       : expr(e), oprtr(op) { }


    // Return the result of evaluating this expression.

       result_type evaluate(result_type v) const {
         return oprtr(expr.evaluate(v));
         }

  private:

    typename representation<Operand>::type expr;
    UnaryOp oprtr;
  };


template < class LeftOperand, class RightOperand, class BinaryOp >
class binary_expression {

  public:

    // Create an expression that evaluates to the result of applying the given
    // binary operation to the result of evaluating the given expressions.

       binary_expression(
         LeftOperand l, RightOperand r, BinaryOp op = BinaryOp())
         : left(l), right(r), oprtr(op) { }

    // Return the result of evaluating this expression.

       result_type evaluate(result_type v) const {
         return oprtr(left.evaluate(v), right.evaluate(v));
         }

  private:

    typename representation<LeftOperand>::type left;
    typename representation<RightOperand>::type right;
    BinaryOp oprtr;
  };


#define def_binexp(_op1, _op2) \
  template <class LExpr, class RExpr> \
  static binary_expression <LExpr, RExpr, std::_op2<result_type> > \
  operator _op1 (LExpr l, RExpr r) { \
  return binary_expression<LExpr, RExpr, std::_op2<result_type> >(l, r); }


#endif

// $Log: ettl.h,v $
// Revision 1.1  2004/05/06 19:43:14  rclayton
// Initial revision
//


syntax highlighted by Code2HTML, v. 0.9