Determine if a numeric type A can be entered in a numeric type B

For two numeric types From and To . Does the following code determine if a value of type From can really be represented as a value of type To without loss of information? If so, is there a shorter or more readable way of determining?

 template <class From, class To> struct can_cast { static const bool value = (std::numeric_limits<From>::is_integer || // either From is an integer type OR std::is_floating_point<To>::value) && // ...they're both floating point types AND (std::numeric_limits<From>::is_signed == false || // either From is unsigned OR std::numeric_limits<To>::is_signed == true) && // ...they're both signed AND (std::numeric_limits<From>::digits < std::numeric_limits<To>::digits || // To has more bits for digits than From OR std::numeric_limits<From>::digits == std::numeric_limits<To>::digits && // To and From have same number of bits, but std::numeric_limits<From>::is_signed == std::numeric_limits<To>::is_signed); // they're either both signed or both unsigned. }; 
+6
source share
1 answer

The compiler now has a built-in function: narrowing conversions is not allowed when using list initialization.

You can write a traditional expression tester feature based on To { std::declval<From>() } and possibly add additional checks using std::is_integral and std::is_floating_point .

 template <typename T> struct sfinae_true : std::true_type {}; struct can_cast_tester { template <typename From, typename To> sfinae_true<decltype(To { std::declval<From>() })> static test(int); template <typename...> std::false_type static test(...); }; template <typename From, typename To> struct can_cast // terrible name : decltype(can_cast_tester::test<From, To>(0)) {}; 

Theoretically, this should work, but currently it seems that neither GCC nor clang get it right.

+2
source

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


All Articles