Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if numeric type A can be cast to numeric type B

Given two numeric types From and To. Does the following code actually determine whether or not any value of type From can be represented as a value of type To without losing information? If yes, 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.
};
like image 408
Alexander Tobias Bockstaller Avatar asked Sep 24 '12 14:09

Alexander Tobias Bockstaller


1 Answers

The compiler has this feature built-in now: narrowing conversions are not allowed when using list-initialisation.

You can write a traditional expression tester trait based off of To { std::declval<From>() } and possibly add additional checks with 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 neither GCC nor clang get it right.

like image 106
R. Martinho Fernandes Avatar answered Oct 18 '22 00:10

R. Martinho Fernandes