C++ for Scientists - Technische Universität Dresden

C++ for Scientists - Technische Universität Dresden C++ for Scientists - Technische Universität Dresden

math.tu.dresden.de
from math.tu.dresden.de More from this publisher
03.12.2012 Views

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; }

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!