From 85d6e35d79d668a2e65d695429d39a092a3ae4d2 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Sat, 9 Apr 2022 17:42:59 +0000 Subject: [PATCH] Loosen requirements on Rep for Magnitude This is necessary to be able to use Magnitudes in Units with a Rep that is not `std::is_arithmetic`. --- src/core/include/units/magnitude.h | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index 545b7d99..e3f16666 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -137,13 +137,14 @@ constexpr auto inverse(BasePower auto bp) // `widen_t` gives the widest arithmetic type in the same category, for intermediate computations. template - requires std::is_arithmetic_v -using widen_t = std::conditional_t, long double, - std::conditional_t, std::intmax_t, std::uintmax_t>>; +using widen_t = + std::conditional_t, + std::conditional_t, long double, + std::conditional_t, std::intmax_t, std::uintmax_t>>, + T>; // Raise an arbitrary arithmetic type to a positive integer power at compile time. template - requires std::is_arithmetic_v constexpr T int_power(T base, std::integral auto exp) { // As this function should only be called at compile time, the exceptions herein function as @@ -166,7 +167,7 @@ constexpr T int_power(T base, std::integral auto exp) // template parameter, rather than a function parameter. if (exp == 0) { - return 1; + return T{1}; } if (exp % 2 == 1) { @@ -178,7 +179,6 @@ constexpr T int_power(T base, std::integral auto exp) template - requires std::is_arithmetic_v constexpr widen_t compute_base_power(BasePower auto bp) { // This utility can only handle integer powers. To compute rational powers at compile time, we'll @@ -197,11 +197,11 @@ constexpr widen_t compute_base_power(BasePower auto bp) if constexpr (std::is_integral_v) { throw std::invalid_argument{"Cannot represent reciprocal as integer"}; } else { - return 1 / compute_base_power(inverse(bp)); + return T{1} / compute_base_power(inverse(bp)); } } - auto power = bp.power.num * int_power(10, bp.power.exp); + auto power = numerator(bp.power); return int_power(static_cast>(bp.get_base()), power); } @@ -210,8 +210,8 @@ constexpr widen_t compute_base_power(BasePower auto bp) // The input is the desired result, but in a (wider) intermediate type. The point of this function // is to cast to the desired type, but avoid overflow in doing so. template - requires std::is_arithmetic_v && std::is_arithmetic_v && - (std::is_integral_v == std::is_integral_v) +// TODO(chogg): Migrate this to use `treat_as_floating_point`. + requires(!std::is_integral_v || std::is_integral_v) constexpr To checked_static_cast(From x) { // This function should only ever be called at compile time. The purpose of these exceptions is @@ -220,10 +220,6 @@ constexpr To checked_static_cast(From x) if (!std::in_range(x)) { throw std::invalid_argument{"Cannot represent magnitude in this type"}; } - } else { - if (x < std::numeric_limits::min() || x > std::numeric_limits::max()) { - throw std::invalid_argument{"Cannot represent magnitude in this type"}; - } } return static_cast(x); @@ -388,7 +384,8 @@ concept Magnitude = detail::is_magnitude; * @brief The value of a Magnitude in a desired type T. */ template - requires std::is_floating_point_v || (std::is_integral_v && is_integral(magnitude{})) +// TODO(chogg): Migrate this to use `treat_as_floating_point`. + requires(!std::is_integral_v || is_integral(magnitude{})) constexpr T get_value(const magnitude&) { // Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow.