It's a question from C++ Primer Chapter 16.2.3 (question 16.41):
Write a version of sum with a return type that is guaranteed to be large enough to hold the result of the addition.
I'm sure there might be some rather obscure STL function that can get this job done, but in the context of the chapter it introduces Standard Type Transformation Templates such as remove_reference<T>
and make_signed<T>
which I'm sure it intends for me to use to accomplish this, in conjunction with trailing return types. The best I can do is:
template <typename It> auto sum(It first, It second) -> typename make_unsigned<It>::type {
return first+second;
}
This almost answers the question but not quite, it doesn't account for that fact that I could pass two unsigned int
s which add to go outside the range of values that an unsigned int
can hold (and so loops back down to zero). As far as I can tell the transformation templates can't help with that issue, is it somehow possible to deduce the return type as the next largest integral type up from the integral type deduced from the passed arguments?
Your easy option is to use an arbitrary precision math package.
Your slightly harder option is to write an arbitrary precision arithmetic add.
I have some code that uses a package, but I can't find it at the moment. Will update when I find it. Easy to use.
Update: found it
package called gmpxx.h. (I think boost also has a suitable class or 2)
With uint64_t, factorial 93 (or maybe 94?) causes wrap around.
With mpz_class,
I decided to add a way to pick the next largest integral type based on the size of the type. It checks if the type is signed, and if so, makes it unsigned. Otherwise, it checks the unsigned types beginning with
unsigned char
to find the smallest type that is larger than the current one. It fails astatic_assert
if there is no larger type. It works like this:The full code is below. It's not the prettiest thing in the world, but I thought it was an interesting experiment.
Since you want to do this at compile time, there is no way of knowing the value of the arguments the function will be invoked with. So you should protect agains overflowing at compile time, and the most obvious thing that comes to my mind is using a promotion trait class:
Live on Coliru
Expanding upon @vsoftco's answer, this would be a more portable way to define the
promote
classes, also taking into account the case where both arguments are negative: