18 template<
typename T_From,
typename T_To>
19 constexpr bool integralIntegralLossless
20 = std::is_integral_v<T_From> && std::is_integral_v<T_To>
21 && ((std::is_signed_v<T_From> == std::is_signed_v<T_To>
22 && std::numeric_limits<T_From>::digits <= std::numeric_limits<T_To>::digits)
23 || (std::is_unsigned_v<T_From> && std::is_signed_v<T_To>
24 && std::numeric_limits<T_From>::digits < std::numeric_limits<T_To>::digits));
27 template<
typename T_From,
typename T_To>
28 constexpr bool floatFloatLossless
29 = std::is_floating_point_v<T_From> && std::is_floating_point_v<T_To>
30 && std::numeric_limits<T_From>::radix == std::numeric_limits<T_To>::radix
31 && std::numeric_limits<T_From>::digits <= std::numeric_limits<T_To>::digits
32 && std::numeric_limits<T_From>::max_exponent <= std::numeric_limits<T_To>::max_exponent
33 && std::numeric_limits<T_From>::min_exponent >= std::numeric_limits<T_To>::min_exponent;
37 template<
typename T_From,
typename T_To>
38 constexpr bool integralFloatLossless = std::is_integral_v<T_From> && std::is_floating_point_v<T_To>
39 && (std::numeric_limits<T_From>::digits + std::is_signed_v<T_From>)
40 <= std::numeric_limits<T_To>::digits;
52 template<
typename T_From,
typename T_To>
54 = std::convertible_to<T_From, T_To>
55 && (detail::integralIntegralLossless<T_From, T_To> || detail::floatFloatLossless<T_From, T_To>
56 || detail::integralFloatLossless<T_From, T_To>);
58 template<
typename T_From,
typename T_To>
59 concept Convertible =
requires { std::is_convertible_v<T_From, T_To>; };
Concept to check if a type can be lossless converted to another type.