On 16.05.2012 06:23, Seungbeom Kim wrote:
> Hi all,
>
> The subject explains itself. Let's say you have a pair of objects, a and b,
> of an unsigned integer type U, and you want to calculate their difference
> in a signed integer type.
>
> Obviously you cannot simply write "a - b", because that will yield an
> unsigned integer value in modulo arithmetic. So you want to write
>
> S d = static_cast<S>(a) - static_cast<S>(b);
>
> for a signed integer type S.
>
> The problem is, how do you determine S? Of course, S should be large enough
> to represent all the values of U. To be safe, you could just use S=intmax_t
> for every U, but that might be an overkill; if U=uint16_t, then S=uint32_t
> is enough, and you don't want to use more expensive arithmetic in uint64_t
> or uint128_t. So, something like S=int_least[N+1]_t where N=numeric_limits
> <U>::digits() would be desirable (+1 because of the sign bit).
>
> Is there a way to automatically determine S from U?
>
I think this should work, although I recommend primarily to avoid using
unsigned types for numbers, and secondly, if one must, use `ptrdiff_t`
for differences (after all, that's what you get for a pointer difference):
<code>
#include <iostream>
#include <typeinfo>
using namespace std;
struct CompleteVoid {};
template< class Type > struct Next;
template<> struct Next<char> { typedef unsigned char T; };
template<> struct Next<signed char> { typedef unsigned char T; };
template<> struct Next<unsigned char> { typedef short T; };
template<> struct Next<short> { typedef unsigned short T; };
template<> struct Next<unsigned short> { typedef int T; };
template<> struct Next<int> { typedef unsigned T; };
template<> struct Next<unsigned> { typedef long T; };
template<> struct Next<long> { typedef unsigned long T; };
template<> struct Next<unsigned long> { typedef long long T; };
template<> struct Next<long long> { typedef unsigned long long T; };
template<> struct Next<unsigned long long> { typedef CompleteVoid T; };
template< bool condition, class A, class B >
struct Choose;
template< class A, class B >
struct Choose< true, A, B > { typedef A T; };
template< class A, class B >
struct Choose< false, A, B > { typedef B T; };
template< class Type >
struct NextLarger
{
private:
typedef typename Next<Type>::T NextUp;
public:
typedef typename Choose<
(sizeof(NextUp) > sizeof(Type)),
NextUp,
typename NextLarger<NextUp>::T
>::T T;
};
template<>
struct NextLarger<CompleteVoid>
{
public:
typedef void T;
};
int main()
{
wcout
<< "The signed type above & covering 'unsigned' is '"
<< typeid( NextLarger<unsigned>::T ).name()
<< "'."
<< endl;
}
</code>
For g++ there is g++-specific function that produces readable type
names, I don't recall its name but you can easily find it.
Cheers & hth.,
- Alf
--