432,109 Members | 932 Online
Need help? Post your question and get tips & solutions from a community of 432,109 IT Pros & Developers. It's quick & easy.

# Expect ArithmeticType to have limits?

 P: n/a Let's say we want to write a function which calculates the force which earth's gravity exerts on an object of particular mass at sea level. We could start off with: unsigned CalcForce(unsigned const mass) { return mass * 9.81; /* Let's ignore the rounding-down */ } Of course though, C++ has many built-in arithmetic types; we could as easily have written it as: double CalcForce(double const mass) { return mass * 9.81; } or: long unsigned CalcForce(long unsigned const mass) { return mass * 9.81; } So this might lead us to write a template function which can deal with any arithmetic type. We might start off with: template T CalcForce(T const mass) { return mass * 9.81; } The problem with this, however, is that it is TOO generic -- it could be passed anything from a pointer to an std::string! In an attempt to restrict the possibilities, maybe we could try: #define COMPASS /* Compile-time assertion */ #include template T CalcForce(T const mass) { COMPASS(std::numeric_limits::is_specialized); return mass * 9.81; } Do you think this is a wise way to write a generic function which deals with numbers? Lastly, let's say that we want this function to work with user-defined arithmetic types also, such as a BigNum library. Should any such classes be expected to have a specialisation of "numeric_limits"? -- Frederick Gotham Sep 23 '06 #1
4 Replies

 P: n/a Frederick Gotham wrote: So this might lead us to write a template function which can deal with any arithmetic type. We might start off with: template T CalcForce(T const mass) { return mass * 9.81; } The problem with this, however, is that it is TOO generic -- it could be passed anything from a pointer to an std::string! In an attempt to restrict the possibilities, maybe we could try: You can't pass anything. If you specialize it for anything that has not an adequate operator * it will not compile. The problem is that the error message can be difficult to understand, but there are ways to work around that. There is paper about this in Stroustrup's web, for example. template T CalcForce(T const mass) { COMPASS(std::numeric_limits::is_specialized); return mass * 9.81; } Do you think this is a wise way to write a generic function which deals with numbers? Lastly, let's say that we want this function to work with user-defined arithmetic types also, such as a BigNum library. Should any such classes be expected to have a specialisation of "numeric_limits"? If you write code like this you are effectively expecting it. I see one problem with this approach. One programmer may want to use your function with a third part BigNum class that does not have that specialization. No problem, they say, I can write it on my own. Later, a new version of the BigNum class is released, and now it has the specialization of numeric_limits. The program must be adapted, or must use conditional code to be able to compile with any BigNum version. IMO is more practical to check only for what you need: the availability of an adequate operator *, in this case. -- Salu2 Sep 23 '06 #2

 P: n/a Frederick Gotham wrote: > The problem with this, however, is that it is TOO generic -- it could be passed anything from a pointer to an std::string! In an attempt to restrict the possibilities, maybe we could try: #define COMPASS /* Compile-time assertion */ #include template T CalcForce(T const mass) { COMPASS(std::numeric_limits::is_specialized); return mass * 9.81; } Decide which numeric types you're using in your program and write functions that take those types. Supporting two or three types doesn't require templates. Further, getting good results from numeric computations means writing type-specific code -- it varies depending on the details of the type. You can't, in general, write it generically. -- -- Pete Author of "The Standard C++ Library Extensions: a Tutorial and Reference." For more information about this book, see www.petebecker.com/tr1book. Sep 23 '06 #3

 P: n/a Pete Becker posted: Decide which numeric types you're using in your program and write functions that take those types. The point is to write portable code which can be used for all sorts of different integer types, including the linkes of: __int256 a,b = 34,c; a = CalcForce(b); Supporting two or three types doesn't require templates. The point is to support *all* arithmetic types, including user-defined ones. Further, getting good results from numeric computations means writing type-specific code -- it varies depending on the details of the type. You can't, in general, write it generically. I write arithmetic generic code all the time -- all you need is a robust understanding of integer promotion and conversion. -- Frederick Gotham Sep 23 '06 #4

 P: n/a Frederick Gotham wrote: Pete Becker posted: >Decide which numeric types you're using in your program and writefunctions that take those types. The point is to write portable code which can be used for all sorts of different integer types, including the linkes of: __int256 a,b = 34,c; a = CalcForce(b); Why? > >Supporting two or three types doesn't require templates. The point is to support *all* arithmetic types, including user-defined ones. Again, why? > >Further, getting good results from numeric computations means writingtype-specific code -- it varies depending on the details of the type.You can't, in general, write it generically. I write arithmetic generic code all the time -- all you need is a robust understanding of integer promotion and conversion. But your example function only makes sense for floating-point types. Even if you want to throw in int or long, why in the world do you need to calculate forces for char, unsigned char, and signed char? -- -- Pete Author of "The Standard C++ Library Extensions: a Tutorial and Reference." For more information about this book, see www.petebecker.com/tr1book. Sep 23 '06 #5

### This discussion thread is closed

Replies have been disabled for this discussion.