Std :: make_signed which accepts floating point types

I have a template class that can only be created for scalar types (integers, floats, etc.), and I want the typedef member to always be a signed type variant. I.e:

unsigned int signed int
signed long longsigned long long (already signed)
unsigned char signed char
floatfloat
long doublelong double
etc...

Unfortunately, std::make_signed only works for integer types, not floating point types. What is the easiest way to do this? I am looking for something like a form using SignedT = ...; to be part of my template template with the template parameter T, which is already guaranteed to be scalar.

+4
source share
4 answers

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 here is how to check 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 living example .

+8
source

After my initial unsuccessful attempt to use std::conditional I decided to use SFINAE instead. I use std::enable_if to conditionally enable specialization for floating point types:

 template<typename T, typename Enable = void> struct my_make_signed { typedef typename std::make_signed<T>::type type; }; template<typename T> struct my_make_signed<T, typename std::enable_if<std::is_floating_point<T>::value>::type> { typedef T type; }; 
+3
source

@jrok initially had code that could work, he just needed to do a little tweaking. This is the working code:

 template<typename T> struct YourClass { using SignedT = typename std::conditional < std::is_floating_point<T>::value, //if floating point type std::common_type<T>, //use it as-is std::make_signed<T> //otherwise make sure it is signed >::type::type; //notice the double ::type }; 

Demo: http://ideone.com/Vw7o82

The above structure can also be modified by itself as a class of type attributes if this function is to be used several times. However, @Andy Prowl's answer does this with an alias pattern, which is better.

+2
source
 namespace mine { template<typename T, bool b> struct make_signed__ { typedef T type; }; template<typename T> struct make_signed__<T,false> { typedef typename std::make_signed<T>::type type; }; template<typename T> struct make_signed { typedef typename make_signed__<T, std::is_floating_point<T>::value>::type type; }; } int main () { std::cout << std::is_same<mine::make_signed<unsigned int>::type, int>::value; std::cout << std::is_same<mine::make_signed<long double>::type, long double>::value; } 
0
source

Source: https://habr.com/ru/post/1479162/


All Articles