Francis Cugler
Francis Cugler

Reputation: 7905

C++ casting template parameter to its unsigned version

I'm working on a class template that takes a single parameter T of any type. For now I'm interested in integral types; later on when I expand this class to use floating point types I will then specialize this class.

Within this class I have a member variable that will store the max number of bit representations that can be stored in this type. For example:

Fundamental Types & Sizes: Range of values

I can get the max value easier by using the unsigned version of that type so in my template class (pseudo code here):

template<class T>
binaryRep {
    T t_; // store the value
    std::size_t size_ = sizeof( T ); // size in bytes
    std::size_t maxVal = T( -1 ); // This is where I need T to be it's unsigned version.    
};

If someone is to use this template class as such:

void someFunc() {
    binaryRep<unsigned char> binUC; // This works fine

    binaryRep<char> binSC; // Not giving the needed results.
}

Is there a way within the class's constructor to cast T to unsigned T?

In my constructor I was trying to do something like this:

binaryRep( const T& t ) : t_( static_cast<unsigned T>( t ) ) {
}

However this doesn't compile and didn't think it would either... but something of this nature is what I'm needing here.

[Note:] - The maxValue member in this class represents the total number of viable binary bit combinations this type can store. For example: both char & unsigned char of a standard 8 bit byte has a max number of 256 binary bit combinations.

If you need more information than this please let me know.

Upvotes: 3

Views: 916

Answers (2)

Ahmed Elbadawy
Ahmed Elbadawy

Reputation: 71

As far as I know, there is no STL in C++ to give you an unsigned datatype of the signed version.

However, it isn't hard to write your own to get the unsigned type of the corresponding signed data type.

here is a sample of code I created for you.

template<typename T>
struct remove_signed { };

template<>
struct remove_signed<char> { typedef unsigned char Type; };

template<>
struct remove_signed<signed char> { typedef unsigned char Type; };

template<>
struct remove_signed<signed short int> { typedef unsigned short int Type; };

template<>
struct remove_signed<signed int> { typedef unsigned int Type; };

template<>
struct remove_signed<signed long int> { typedef unsigned long int Type; };

template<>
struct remove_signed<signed long long> { typedef unsigned long long Type; };


template<typename T>
using remove_signed_t = typename remove_signed<T>::Type;


int main(int argc, char** argv)
{
   
    signed int x;
    remove_signed<decltype(x)>::Type y; //y is unsigned int

    signed char k;
    remove_signed<decltype(k)>::Type l; //l is unsigned char

    //or
    remove_signed_t<decltype(k)> g; //g is unsigned char
    
    return 0;
}

Good luck.

Edit: As @HolyBlackCat has mentioned, there is std::make_unsigned which can give you unsigned datatype of the signed type And it is exactly implemented as the code above, so if you want to know how std::make_unsigned works, you can check the code.

Upvotes: 3

haaawk
haaawk

Reputation: 330

Setting maxVal to size_ == sizeof(long long) ? (uLL) -1 : (1uLL << size_) - 1 should do the trick.

Upvotes: 0

Related Questions