C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden C++ for Scientists - Technische Universität Dresden
136 CHAPTER 5. META-PROGRAMMING double d1= 3., d2= 4.; std::cout ≪ ”min magnitude(d1, d2) = ” ≪ min magnitude(d1, d2) ≪ ’\n’; If we call this function with two complex values: std::complex c1(3.), c2(4.); std::cout ≪ ”min magnitude(c1, c2) = ” ≪ min magnitude(c1, c2) ≪ ’\n’; we will see the error message no match for ≫operator< ≪in ≫ax < a≪ The problem is that abs returns in this case double values which provides the comparison operator but we store them as complex values in the temporaries. The careful reader might think we do we store them at all, if we compared the magnitudes directly we might safe memory and we could compare them as they are. This absolutely true and this is how we would implement the function normally. However, there are situations where one need a temporary, e.g., when computing the value with the minimal magnitude in a vector. For the sake of simplicity we just look at two values. With the new standard we can also handle the issue easily with auto types like: template T inline min magnitude(const T& x, const T& y) { using std::abs; auto ax= abs(x), ay= abs(y); return ax < ay ? x : y; } To make a long story short, sometimes we need to know explicitly the result type of an expression or a type information in general. Just think of a member variable of a template class: we must know the type of the member in the definition of the class. This leads us to ‘type traits’. Type traits meta-functions that provide an information about a type. In the example here we search for a given type an appropriate type for its magnitude. We can provide such type information by template specialization: template struct Magnitude {}; template struct Magnitude { typedef int type; }; template struct Magnitude { typedef float type; }; template
5.2. PROVIDING TYPE INFORMATION 137 struct Magnitude { typedef double type; }; template struct Magnitude { typedef float type; }; template struct Magnitude { typedef double type; }; Admittedly, this is rather cumbersome. We can abbreviate the first definitions by postulating “if we do not know better, we assume that T’s Magnitude type is T itself.” template struct Magnitude { typedef T type; }; This is true for all intrinsic types and we handle them all correctly with one definition. A slight disadvantage of this definition is that it incorrectly applies to all types whose type trait is not specialized. A set of classes where we know that the above definition is not correct, are all instantiations of the template class complex. So we define specializations like: template struct Magnitude { typedef double type; }; Instead of defining them individually for complex, complex, . . . we use a templated form to treat them all template struct Magnitude { typedef T type; }; Now that the type traits are defined we can refactor our function to use it: template T inline min magnitude(const T& x, const T& y) { using std::abs; typename Magnitude::type ax= abs(x), ay= abs(y); return ax < ay ? x : y; }
- Page 86 and 87: 86 CHAPTER 3. CLASSES of the decrem
- Page 88 and 89: 88 CHAPTER 3. CLASSES There are two
- Page 90 and 91: 90 CHAPTER 4. GENERIC PROGRAMMING }
- Page 92 and 93: 92 CHAPTER 4. GENERIC PROGRAMMING c
- Page 94 and 95: 94 CHAPTER 4. GENERIC PROGRAMMING A
- Page 96 and 97: 96 CHAPTER 4. GENERIC PROGRAMMING v
- Page 98 and 99: 98 CHAPTER 4. GENERIC PROGRAMMING c
- Page 100 and 101: 100 CHAPTER 4. GENERIC PROGRAMMING
- Page 102 and 103: 102 CHAPTER 4. GENERIC PROGRAMMING
- 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 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 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
136 CHAPTER 5. META-PROGRAMMING<br />
double d1= 3., d2= 4.;<br />
std::cout ≪ ”min magnitude(d1, d2) = ” ≪ min magnitude(d1, d2) ≪ ’\n’;<br />
If we call this function with two complex values:<br />
std::complex c1(3.), c2(4.);<br />
std::cout ≪ ”min magnitude(c1, c2) = ” ≪ min magnitude(c1, c2) ≪ ’\n’;<br />
we will see the error message<br />
no match <strong>for</strong> ≫operator< ≪in ≫ax < a≪<br />
The problem is that abs returns in this case double values which provides the comparison operator<br />
but we store them as complex values in the temporaries.<br />
The careful reader might think we do we store them at all, if we compared the magnitudes<br />
directly we might safe memory and we could compare them as they are. This absolutely true<br />
and this is how we would implement the function normally. However, there are situations where<br />
one need a temporary, e.g., when computing the value with the minimal magnitude in a vector.<br />
For the sake of simplicity we just look at two values. With the new standard we can also handle<br />
the issue easily with auto types like:<br />
template <br />
T inline min magnitude(const T& x, const T& y)<br />
{<br />
using std::abs;<br />
auto ax= abs(x), ay= abs(y);<br />
return ax < ay ? x : y;<br />
}<br />
To make a long story short, sometimes we need to know explicitly the result type of an expression<br />
or a type in<strong>for</strong>mation in general. Just think of a member variable of a template class: we must<br />
know the type of the member in the definition of the class.<br />
This leads us to ‘type traits’. Type traits meta-functions that provide an in<strong>for</strong>mation about a<br />
type.<br />
In the example here we search <strong>for</strong> a given type an appropriate type <strong>for</strong> its magnitude. We can<br />
provide such type in<strong>for</strong>mation by template specialization:<br />
template <br />
struct Magnitude {};<br />
template <br />
struct Magnitude<br />
{<br />
typedef int type;<br />
};<br />
template <br />
struct Magnitude<br />
{<br />
typedef float type;<br />
};<br />
template