C++ Expression Templates | Lazy Evaluation Techniques

C++ Expression Templates | Lazy Evaluation Techniques

이 글의 핵심

A practical guide to expression templates: from motivation to vector/matrix examples, pitfalls, and library references.

The problem

// Simple vector
class Vector {
    vector<double> data;
public:
    Vector(size_t n) : data(n) {}
    
    Vector operator+(const Vector& other) const {
        Vector result(data.size());
        for (size_t i = 0; i < data.size(); i++) {
            result.data[i] = data[i] + other.data[i];
        }
        return result;  // temporary
    }
};

// Issue: three temporaries
Vector a, b, c, d;
Vector result = a + b + c + d;
// temp1 = a + b
// temp2 = temp1 + c
// temp3 = temp2 + d
// result = temp3

Expression-template approach

// Expression template
template<typename E>
class VecExpression {
public:
    double operator const {
        return static_cast<const E&>(*this)[i];
    }
    
    size_t size() const {
        return static_cast<const E&>(*this).size();
    }
};

// Concrete vector
class Vector : public VecExpression<Vector> {
    vector<double> data;
    
public:
    Vector(size_t n) : data(n) {}
    
    double operator const { return data[i]; }
    double& operator { return data[i]; }
    size_t size() const { return data.size(); }
    
    // Construct from an expression
    template<typename E>
    Vector(const VecExpression<E>& expr) : data(expr.size()) {
        for (size_t i = 0; i < expr.size(); i++) {
            data[i] = expr[i];  // lazy evaluation happens here
        }
    }
};

// Addition expression
template<typename E1, typename E2>
class VecAdd : public VecExpression<VecAdd<E1, E2>> {
    const E1& u;
    const E2& v;
    
public:
    VecAdd(const E1& u, const E2& v) : u(u), v(v) {}
    
    double operator const {
        return u[i] + v[i];
    }
    
    size_t size() const { return u.size(); }
};

// Operator+
template<typename E1, typename E2>
VecAdd<E1, E2> operator+(const VecExpression<E1>& u, const VecExpression<E2>& v) {
    return VecAdd<E1, E2>(static_cast<const E1&>(u), static_cast<const E2&>(v));
}

int main() {
    Vector a(3), b(3), c(3);
    
    // No temporaries for intermediate vectors
    Vector result = a + b + c;  // evaluated in one pass into result
}

Practical examples

Example 1: Vector ops

Includes VecScale, operator* with a scalar, and a dot helper—same as the Korean article.

Example 2: Matrix ops

MatExpression, Matrix, MatAdd, operator+—same structure as the Korean article.

Example 3: Lazy list map

ListExpression, List, ListMap, map helper—same as the Korean article.

Performance comparison

Benchmark sketch comparing naive chained + vs expression-template assignment—measure on your hardware; results vary.

Common pitfalls

Dangling references

Storing auto expr = a + b can dangle if operands are temporaries—evaluate into a concrete Vector promptly.

Long template errors

Add static_assert constraints where helpful.

Compile-time explosion

Break expressions into named temporaries when builds get too heavy.

Libraries

Eigen and Blaze apply expression templates (or similar) internally—see their documentation.

FAQ

Q1: When? Numeric kernels, matrix/vector code, internal DSLs.
Q2: Speedups? Often from removing temporaries—measure.
Q3: Downsides? Complexity, build time, diagnostics.
Q4: Implement yourself? Prefer mature libraries unless you have a narrow, controlled use case.
Q5: Debugging? Small tests, static_assert, disable aggressive optimizations while investigating.
Q6: Resources? C++ Templates: The Complete Guide, Eigen sources, Modern C++ Design.


  • Expression templates (deep dive)
  • Type traits
  • Tag dispatching

Practical tips

Debugging

  • Fix warnings first; minimize reproducers.

Performance

  • Profile before optimizing; define metrics.

Code review

  • Align with team conventions.

Checklist

Before coding

  • Best tool for the job?
  • Maintainable by the team?
  • Meets performance goals?

While coding

  • Warnings cleared?
  • Edge cases covered?
  • Errors handled?

At review

  • Clear intent?
  • Enough tests?
  • Documented?

Keywords

C++, expression template, metaprogramming, optimization, templates.

See also

  • Expression templates (deep dive)
  • SFINAE & Concepts
  • Tag dispatching
  • Type traits
  • Alignment & padding