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?
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:
#include <iostream>
#include <limits>
template<typename T>
struct promote;
template<> // and so on for all types that you want to promote
struct promote<unsigned int> // type to be promoted from
{
using type = unsigned long int; // type to be promoted to
};
// helper a la C++14
template<typename T>
using promote_t = typename promote<T>::type;
template <typename It>
auto my_sum(It first, It second) -> promote_t<It>
{
return static_cast<promote_t<It>>(first) + second; // promotion
}
int main()
{
unsigned int a = std::numeric_limits<unsigned int>::max();
unsigned int b = std::numeric_limits<unsigned int>::max();
auto c = my_sum(a, b); // type is promoted to unsigned long int
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
std::cout << "a + b = " << c << std::endl;
}
Live on Coliru
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With