C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden C++ for Scientists - Technische Universität Dresden
154 CHAPTER 5. META-PROGRAMMING Discussion 5.1 The drawback is that if the entries are accessed multiple times the sum is recomputed. On the other hand, most expressions are only used once and this is not a problem. An example where vector entries are accessed several times is A ∗ (x+y). Here, it is preferable to compute a true vector first instead of computing the matrix vector product on the expression template. 12 To evaluate w= x + y we also need an assignment operator for vector sum: template class vector sum; // forward declaration template class vector { // ... vector& operator=(const vector sum& that) { check size(size(that)); for (int i= 0; i < my size; ++i) data[i]= that[i]; return ∗this; } }; The assignment runs a loop over w and that. As that is an object of type vector sum the expression that[i] computes x[i] + y[i]. In contrast to the implementationn in Section 5.3.1 we have now • Only one loop; • No temporary vector; • No additional memory allocation and deallocation; and • No addional data reads and writes. In fact, the same operations are performed as in the loop for (int i= 0; i < size(w); ++i) w[i] = x[i] + y[i]; The cost to create a vector sum object is negligible. The object will be kept on the stack and does not require memory allocation. Even that little effort for creating the object will be optimized away by most compilers with static code analysis. What happens when we like to add three vectors? The naïve implementation from § 5.3.1 returns a vector and this vector can be added to another vector. Our approach returns a vector sum and we have no addition for vector sum and vector. Thus we would need another ET class and an according operation: template class vector sum3 { void check index(int i) const { assert(i >= 0 && i < size(v1)); } public: vector sum3(const vector& v1, const vector& v2, const vector& v3) : v1(v1), v2(v2), v3(v3) { assert(size(v1) == size(v2)); assert(size(v1) == size(v3)); 12 TODO: Shall we provide a solution for this as well? This something that is over-due in MTL4 anyway.
5.3. EXPRESSION TEMPLATES 155 } friend int size(const vector sum3& x) { return size(x.v1); } T operator[](int i) const { check index(i); return v1[i] + v2[i] + v3[i]; } private: const vector& v1, v2, v3; }; template vector sum3 inline operator+(const vector sum& x, const vector& y) { return vector sum3(x.v1, x.v2, y); } Furthermore, vector sum must declare our new plus operator as friend to access its private members and vector needs an assignment for vector sum3. This becomes increasingly annoying. Also, what happens if we perform the second addition first w= x + (y + z)? Then we need another plus operator. What if some of the vectors are multiplied by a scalar, e.g., w= x + dot(x, y) ∗ y + 4.3 ∗ z, and this scalar product is also implemented by an ET? Our implementation effort runs into combinatorial explosion and we need a more flexible solution that we introduce in the next section. 5.3.3 Generic Expression Templates So far we started from a specific class (vector) and generalized the implementation gradually. Although this can help us to understand the mechanism, we like to go now to the general version that takes arbitrary vector types: template vector sum inline operator+(const V1& x, const V2& y) { return vector sum(x, y); } We now need an expression class with arbitrary arguments: template class vector sum { typedef vector sum self; void check index(int i) const { assert(i >= 0 && i < size(v1)); } public: vector sum(const V1& v1, const V2& v2) : v1(v1), v2(v2) { assert(size(v1) == size(v2)); } ???? operator[](int i) const { check index(i); return v1[i] + v2[i]; } friend int size(const self& x) { return size(x.v1); } private: const V1& v1;
- Page 104 and 105: 104 CHAPTER 4. GENERIC PROGRAMMING
- Page 106 and 107: 106 CHAPTER 4. GENERIC PROGRAMMING
- Page 108 and 109: 108 CHAPTER 4. GENERIC PROGRAMMING
- Page 110 and 111: 110 CHAPTER 4. GENERIC PROGRAMMING
- Page 112 and 113: 112 CHAPTER 4. GENERIC PROGRAMMING
- Page 114 and 115: 114 CHAPTER 4. GENERIC PROGRAMMING
- Page 116 and 117: 116 CHAPTER 4. GENERIC PROGRAMMING
- Page 118 and 119: 118 CHAPTER 4. GENERIC PROGRAMMING
- Page 120 and 121: 120 CHAPTER 4. GENERIC PROGRAMMING
- Page 122 and 123: 122 CHAPTER 4. GENERIC PROGRAMMING
- Page 124 and 125: 124 CHAPTER 4. GENERIC PROGRAMMING
- Page 126 and 127: 126 CHAPTER 4. GENERIC PROGRAMMING
- Page 128 and 129: 128 CHAPTER 4. GENERIC PROGRAMMING
- Page 130 and 131: 130 CHAPTER 4. GENERIC PROGRAMMING
- Page 132 and 133: 132 CHAPTER 4. GENERIC PROGRAMMING
- Page 134 and 135: 134 CHAPTER 5. META-PROGRAMMING exp
- Page 136 and 137: 136 CHAPTER 5. META-PROGRAMMING dou
- Page 138 and 139: 138 CHAPTER 5. META-PROGRAMMING We
- Page 140 and 141: 140 CHAPTER 5. META-PROGRAMMING Fir
- Page 142 and 143: 142 CHAPTER 5. META-PROGRAMMING hig
- Page 144 and 145: 144 CHAPTER 5. META-PROGRAMMING The
- Page 146 and 147: 146 CHAPTER 5. META-PROGRAMMING tra
- Page 148 and 149: 148 CHAPTER 5. META-PROGRAMMING tem
- Page 150 and 151: 150 CHAPTER 5. META-PROGRAMMING 5.3
- Page 152 and 153: 152 CHAPTER 5. META-PROGRAMMING •
- Page 156 and 157: 156 CHAPTER 5. META-PROGRAMMING };
- Page 158 and 159: 158 CHAPTER 5. META-PROGRAMMING A s
- Page 160 and 161: 160 CHAPTER 5. META-PROGRAMMING ass
- Page 162 and 163: 162 CHAPTER 5. META-PROGRAMMING num
- Page 164 and 165: 164 CHAPTER 5. META-PROGRAMMING Usi
- Page 166 and 167: 166 CHAPTER 5. META-PROGRAMMING } v
- Page 168 and 169: 168 CHAPTER 5. META-PROGRAMMING The
- Page 170 and 171: 170 CHAPTER 5. META-PROGRAMMING onl
- Page 172 and 173: 172 CHAPTER 5. META-PROGRAMMING for
- Page 174 and 175: 174 CHAPTER 5. META-PROGRAMMING } u
- Page 176 and 177: 176 CHAPTER 5. META-PROGRAMMING } r
- Page 178 and 179: 178 CHAPTER 5. META-PROGRAMMING };
- Page 180 and 181: 180 CHAPTER 5. META-PROGRAMMING } t
- Page 182 and 183: 182 CHAPTER 5. META-PROGRAMMING };
- Page 184 and 185: 184 CHAPTER 5. META-PROGRAMMING Com
- Page 186 and 187: 186 CHAPTER 5. META-PROGRAMMING tem
- Page 188 and 189: 188 CHAPTER 6. INHERITANCE { } std:
- Page 190 and 191: 190 CHAPTER 6. INHERITANCE 6.4.1 Ca
- Page 192 and 193: 192 CHAPTER 6. INHERITANCE dbp= sta
- Page 194 and 195: 194 CHAPTER 6. INHERITANCE Our comp
- Page 196 and 197: 196 CHAPTER 6. INHERITANCE Another
- Page 198 and 199: 198 CHAPTER 6. INHERITANCE
- Page 200 and 201: 200 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 202 and 203: 202 CHAPTER 7. EFFECTIVE PROGRAMMIN
5.3. EXPRESSION TEMPLATES 155<br />
}<br />
friend int size(const vector sum3& x) { return size(x.v1); }<br />
T operator[](int i) const { check index(i); return v1[i] + v2[i] + v3[i]; }<br />
private:<br />
const vector& v1, v2, v3;<br />
};<br />
template <br />
vector sum3 inline operator+(const vector sum& x, const vector& y)<br />
{<br />
return vector sum3(x.v1, x.v2, y);<br />
}<br />
Furthermore, vector sum must declare our new plus operator as friend to access its private<br />
members and vector needs an assignment <strong>for</strong> vector sum3. This becomes increasingly annoying.<br />
Also, what happens if we per<strong>for</strong>m the second addition first w= x + (y + z)? Then we<br />
need another plus operator. What if some of the vectors are multiplied by a scalar, e.g.,<br />
w= x + dot(x, y) ∗ y + 4.3 ∗ z, and this scalar product is also implemented by an ET? Our implementation<br />
ef<strong>for</strong>t runs into combinatorial explosion and we need a more flexible solution that<br />
we introduce in the next section.<br />
5.3.3 Generic Expression Templates<br />
So far we started from a specific class (vector) and generalized the implementation gradually.<br />
Although this can help us to understand the mechanism, we like to go now to the general version<br />
that takes arbitrary vector types:<br />
template <br />
vector sum inline operator+(const V1& x, const V2& y)<br />
{<br />
return vector sum(x, y);<br />
}<br />
We now need an expression class with arbitrary arguments:<br />
template <br />
class vector sum<br />
{<br />
typedef vector sum self;<br />
void check index(int i) const { assert(i >= 0 && i < size(v1)); }<br />
public:<br />
vector sum(const V1& v1, const V2& v2) : v1(v1), v2(v2)<br />
{<br />
assert(size(v1) == size(v2));<br />
}<br />
???? operator[](int i) const { check index(i); return v1[i] + v2[i]; }<br />
friend int size(const self& x) { return size(x.v1); }<br />
private:<br />
const V1& v1;