Solution: Expression Templates
Explore how to implement expression templates in C++ to efficiently handle operations such as vector subtraction and division. Understand the use of classes like MyVectorSub and MyVectorDiv, and function templates that enable lazy evaluation, improving performance in resource management and arithmetic operations.
We'll cover the following...
We'll cover the following...
Solution
C++
// vectorArithmeticExpressionTemplates.cpp#include <cassert>#include <iostream>#include <vector>template<typename T, typename Cont= std::vector<T> >class MyVector{Cont cont;public:// MyVector with initial sizeexplicit MyVector(const std::size_t n) : cont(n){}// MyVector with initial size and valueMyVector(const std::size_t n, const double initialValue) : cont(n, initialValue){}// Constructor for underlying containerexplicit MyVector(const Cont& other) : cont(other){}// assignment operator for MyVector of different typetemplate<typename T2, typename R2>MyVector& operator=(const MyVector<T2, R2>& other){assert(size() == other.size());for (std::size_t i = 0; i < cont.size(); ++i) cont[i] = other[i];return *this;}// size of underlying containerstd::size_t size() const{return cont.size();}// index operatorsT operator[](const std::size_t i) const{return cont[i];}T& operator[](const std::size_t i){return cont[i];}// returns the underlying dataconst Cont& data() const{return cont;}Cont& data(){return cont;}};// MyVector + MyVectortemplate<typename T, typename Op1 , typename Op2>class MyVectorAdd{const Op1& op1;const Op2& op2;public:MyVectorAdd(const Op1& a, const Op2& b): op1(a), op2(b){}T operator[](const std::size_t i) const{return op1[i] + op2[i];}std::size_t size() const{return op1.size();}};// MyVector - MyVectortemplate<typename T, typename Op1, typename Op2>class MyVectorSub {const Op1& op1;const Op2& op2;public:MyVectorSub(const Op1& a, const Op2& b) : op1(a), op2(b) {}T operator[](const std::size_t i) const {return op1[i] - op2[i];}std::size_t size() const {return op1.size();}};// elementwise MyVector * MyVectortemplate< typename T, typename Op1 , typename Op2 >class MyVectorMul {const Op1& op1;const Op2& op2;public:MyVectorMul(const Op1& a, const Op2& b ): op1(a), op2(b){}T operator[](const std::size_t i) const{return op1[i] * op2[i];}std::size_t size() const{return op1.size();}};// elementwise MyVector / MyVectortemplate< typename T, typename Op1, typename Op2 >class MyVectorDiv {const Op1& op1;const Op2& op2;public:MyVectorDiv(const Op1& a, const Op2& b) : op1(a), op2(b) {}T operator[](const std::size_t i) const {return op1[i] / op2[i];}std::size_t size() const {return op1.size();}};// function template for the + operatortemplate<typename T, typename R1, typename R2>MyVector<T, MyVectorAdd<T, R1, R2> >operator+ (const MyVector<T, R1>& a, const MyVector<T, R2>& b){return MyVector<T, MyVectorAdd<T, R1, R2> >(MyVectorAdd<T, R1, R2 >(a.data(), b.data()));}// function template for the - operatortemplate<typename T, typename R1, typename R2>MyVector<T, MyVectorSub<T, R1, R2> >operator- (const MyVector<T, R1>& a, const MyVector<T, R2>& b) {return MyVector<T, MyVectorSub<T, R1, R2> >(MyVectorSub<T, R1, R2 >(a.data(), b.data()));}// function template for the * operatortemplate<typename T, typename R1, typename R2>MyVector<T, MyVectorMul< T, R1, R2> >operator* (const MyVector<T, R1>& a, const MyVector<T, R2>& b){return MyVector<T, MyVectorMul<T, R1, R2> >(MyVectorMul<T, R1, R2 >(a.data(), b.data()));}// function template for the / operatortemplate<typename T, typename R1, typename R2>MyVector<T, MyVectorDiv< T, R1, R2> >operator/ (const MyVector<T, R1>& a, const MyVector<T, R2>& b) {return MyVector<T, MyVectorDiv<T, R1, R2> >(MyVectorDiv<T, R1, R2 >(a.data(), b.data()));}// function template for << operatortemplate<typename T>std::ostream& operator<<(std::ostream& os, const MyVector<T>& cont){std::cout << '\n';for (int i=0; i<cont.size(); ++i) {os << cont[i] << ' ';}os << '\n';return os;}int main(){MyVector<double> x(10,5.4);MyVector<double> y(10,10.3);MyVector<double> result(10);result = x + x + y * y - x + x + y / y;std::cout << result << '\n';}
Explanation
The solution to our challenge is highlighted in the code above. Let’s discuss it line by line:
-
Lines 72–87: We defined the
MyVectorSubclass, which ...