C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden C++ for Scientists - Technische Universität Dresden
194 CHAPTER 6. INHERITANCE Our compilers are so sophisticated, they certainly handle de Morgan’s law perfectly. Negating the equality operator is something we can do on every type that has an equality operator. We could copy-and-past this code snippet and just replace the type of the argument. Alternatively, we can write a class like this: template struct unequality { bool operator!=(const T& that) const { return !(static cast(∗this) == that); } }; and derive from it: class point : public unequality { ... }; This mutual dependency: • One class is derived from the other and • The latter takes the derived class’ type as template argument is somewhat confusing at the first view. Essential for this to work is that the code of a template class member is only generated when the class is instantiated and the function is actually called. At the time the template class ‘unequality is parsed, the compiler checks only the correctness of the syntax. When we write int main (int argc, char∗ argv[]) { point p1(3, 4), p2(3, 5); std::cout ≪ ”p1 != p2 is ” ≪ (p1 != p2 ? ”true” : ”false”) ≪ ’\n’; } return 0 ; fter the definition of unequality and point both types are completely known to the compiler. What happens when we call p1 != p2? 1. The compiler searches for operator!= in class point → without success. 2. The compiler looks for operator!= in the base class unequality → with success. 3. The this pointer of unequality refers a component of point’s this pointer. 4. Both types are completely known and we can statically down-cast the this pointer to point. 5. Since we know that the this pointer of unequality is an up-casted this pointer to point 3 we are save to down-cast it to its original type. 6. The equality operator for point is called. Its implementation is already known at this point because the code of unequality’s operator!= is not generated before the instantiation of point. 3 Unless the first argument is really of type unequality. There are also ways to impede this, e.g. http: //en.wikipedia.org/wiki/Barton-Nackman_trick but we used this unary operator notation for the sake of simplicity.
6.5. BARTON-NACKMAN TRICK 195 Likewise every class U with an equality operator can be derived from unequality. A collection of such CRTP templates for operator defaults is provided by Boost.Operators from Jeremy Siek and David Abrahams. Alternatively to the above implementation where the this pointer is dereferred and casted as reference, one can cast the pointer first and derefer it afterwards: template struct unequality { bool operator!=(const T& that) const { return !(∗static cast(this) == that); } }; There is no difference, this is just a question of taste. 6.5.2 A Reusable Access Operator ⇒ matrix crtp example.cpp We still owe the reader the reusable implementation of the matrix bracket operator promised in Section 3.7.4. Back then we did not know enough language features. First of all we had no templates which are indispensable for a proxy. We will show you why. Say we have a matrix class as in § 3.7.4 and we just want to call the binary operator() from the unary operator[] via a proxy: class matrix; // Forward declaration class simple bracket proxy { public: simple bracket proxy(matrix& A, int r) : A(A), r(r) {} double& operator[](int c){ return A(r, c); } private: matrix& A; int r; }; class matrix { // ... double& operator()(int r, int c) { ... } }; simple bracket proxy operator[](int r) { return simple bracket proxy(∗this, r); } This does not compile because operator[] from simple bracket proxy calls operator() from matrix but this is not defined yet. The forward declaration of matrix is not sufficient because we need the complete definition of matrix not only the assertion that the type exist. Vice versa if we define matrix first, we would miss the constructor of simple bracket proxy in the operator[] implementation.
- 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 154 and 155: 154 CHAPTER 5. META-PROGRAMMING Dis
- 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 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
- Page 204 and 205: 204 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 206 and 207: 206 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 208 and 209: 208 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 210 and 211: 210 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 212 and 213: 212 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 214 and 215: 214 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 216 and 217: 216 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 218 and 219: 218 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 220 and 221: 220 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 222 and 223: 222 CHAPTER 7. EFFECTIVE PROGRAMMIN
- Page 225 and 226: Finite World of Computers Chapter 8
- Page 227 and 228: 8.2. MORE NUMBERS AND BASIC STRUCTU
- Page 229 and 230: 8.2. MORE NUMBERS AND BASIC STRUCTU
- Page 231 and 232: 8.4. THE OTHER WAY AROUND 231 As ca
- Page 233 and 234: How to Handle Physics on the Comput
- Page 235 and 236: Programming tools Chapter 10 In thi
- Page 237 and 238: 10.2. DEBUGGING 237 T& glas::contin
- Page 239 and 240: 10.3. VALGRIND 239 Stepi and Nexti
- Page 241 and 242: 10.5. UNIX AND LINUX 241 • top: l
- Page 243 and 244: C ++ Libraries for Scientific Compu
6.5. BARTON-NACKMAN TRICK 195<br />
Likewise every class U with an equality operator can be derived from unequality. A collection<br />
of such CRTP templates <strong>for</strong> operator defaults is provided by Boost.Operators from Jeremy<br />
Siek and David Abrahams.<br />
Alternatively to the above implementation where the this pointer is dereferred and casted as<br />
reference, one can cast the pointer first and derefer it afterwards:<br />
template <br />
struct unequality<br />
{<br />
bool operator!=(const T& that) const { return !(∗static cast(this) == that); }<br />
};<br />
There is no difference, this is just a question of taste.<br />
6.5.2 A Reusable Access Operator<br />
⇒ matrix crtp example.cpp<br />
We still owe the reader the reusable implementation of the matrix bracket operator promised<br />
in Section 3.7.4. Back then we did not know enough language features.<br />
First of all we had no templates which are indispensable <strong>for</strong> a proxy. We will show you why.<br />
Say we have a matrix class as in § 3.7.4 and we just want to call the binary operator() from the<br />
unary operator[] via a proxy:<br />
class matrix; // Forward declaration<br />
class simple bracket proxy<br />
{<br />
public:<br />
simple bracket proxy(matrix& A, int r) : A(A), r(r) {}<br />
double& operator[](int c){ return A(r, c); }<br />
private:<br />
matrix& A;<br />
int r;<br />
};<br />
class matrix<br />
{<br />
// ...<br />
double& operator()(int r, int c) { ... }<br />
};<br />
simple bracket proxy operator[](int r)<br />
{<br />
return simple bracket proxy(∗this, r);<br />
}<br />
This does not compile because operator[] from simple bracket proxy calls operator() from matrix but<br />
this is not defined yet. The <strong>for</strong>ward declaration of matrix is not sufficient because we need the<br />
complete definition of matrix not only the assertion that the type exist. Vice versa if we define<br />
matrix first, we would miss the constructor of simple bracket proxy in the operator[] implementation.