Search code examples
c++templatesc++11type-traits

std::make_signed that accepts floating point types


I have a templated class that can only be instantiated for scalar types (integers, floats, etc.) and I want a member typedef to always be the signed variant of the type. That is:

unsigned int -> signed int
signed long long -> signed long long (already signed)
unsigned char -> signed char
float -> float
long double -> long double
etc...

Unfortunately, std::make_signed only works for integral types, not the floating point types. What is the simplest way to do this? I'm looking for something of the form using SignedT = ...;, to be part of my templated class with template parameter T already guaranteed to be scalar.


Solution

  • A simple template alias will do:

    #include <type_traits>
    
    template<typename T>
    struct identity { using type = T; };
    
    template<typename T>
    using try_make_signed =
        typename std::conditional<
            std::is_integral<T>::value,
            std::make_signed<T>,
            identity<T>
            >::type;
    

    And this is how you could test it:

    int main()
    {
        static_assert(::is_same<
            try_make_signed<unsigned int>::type, int
            >::value, "!");
    
        static_assert(std::is_same<
            try_make_signed<double>::type, double
            >::value, "!");
    }
    

    Here is a live example.