From d83cbc049fd1d75f6960f0bee3c10a229fb60766 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 25 Oct 2024 22:53:03 +0200 Subject: [PATCH] feat: `MagnitudeSpecExpr` and `PowerVBase` removed and some functions renamed to limit possible ambiguity in overload resolution --- .../include/mp-units/framework/magnitude.h | 55 ++++++++++++------- .../mp-units/framework/magnitude_concepts.h | 33 +---------- 2 files changed, 35 insertions(+), 53 deletions(-) diff --git a/src/core/include/mp-units/framework/magnitude.h b/src/core/include/mp-units/framework/magnitude.h index e2dea0ca..5873da1e 100644 --- a/src/core/include/mp-units/framework/magnitude.h +++ b/src/core/include/mp-units/framework/magnitude.h @@ -82,8 +82,21 @@ concept MagArg = std::integral || MagConstant; } +/** + * @brief Any type which can be used as a basis vector in a power_v. + * + * We have two categories. + * + * The first is just an integral type (either `int` or `std::intmax_t`). This is for prime number bases. + * These can always be used directly as NTTPs. + * + * The second category is a _custom tag type_, which inherits from `mag_constant` and has a static member variable + * `value` of type `long double` that holds its value. We choose `long double` to get the greatest degree of precision; + * users who need a different type can convert from this at compile time. This category is for any irrational base + * we admit into our representation (on which, more details below). + */ // TODO Unify with `power` if UTPs (P1985) are accepted by the Committee -template +template requires(detail::valid_ratio && !detail::ratio_one) struct power_v { static constexpr auto base = V; @@ -92,7 +105,7 @@ struct power_v { namespace detail { -template +template [[nodiscard]] consteval auto get_base(Element element) { if constexpr (is_specialization_of_v) @@ -101,7 +114,7 @@ template return element; } -template +template [[nodiscard]] consteval auto get_base_value(Element element) { if constexpr (is_specialization_of_v) @@ -112,7 +125,7 @@ template return element; } -template +template [[nodiscard]] MP_UNITS_CONSTEVAL ratio get_exponent(Element) { if constexpr (is_specialization_of_v) @@ -121,7 +134,7 @@ template return ratio{1}; } -template +template [[nodiscard]] consteval auto power_v_or_T() { if constexpr (R.den == 1) { @@ -134,8 +147,8 @@ template } } -template -[[nodiscard]] consteval auto inverse(M) +template +[[nodiscard]] consteval auto mag_inverse(M) { return power_v_or_T(); } @@ -148,7 +161,7 @@ using widen_t = conditional, T>; template -[[nodiscard]] consteval widen_t compute_base_power(MagnitudeSpecExpr auto el) +[[nodiscard]] consteval widen_t compute_base_power(auto el) { // This utility can only handle integer powers. To compute rational powers at compile time, we'll // need to write a custom function. @@ -161,7 +174,7 @@ template if constexpr (std::is_integral_v) { std::abort(); // Cannot represent reciprocal as integer } else { - return T{1} / compute_base_power(inverse(el)); + return T{1} / compute_base_power(mag_inverse(el)); } } @@ -180,17 +193,17 @@ template } } -[[nodiscard]] consteval bool is_rational(MagnitudeSpecExpr auto element) +[[nodiscard]] consteval bool is_rational_impl(auto element) { return std::is_integral_v && get_exponent(element).den == 1; } -[[nodiscard]] consteval bool is_integral(MagnitudeSpecExpr auto element) +[[nodiscard]] consteval bool is_integral_impl(auto element) { - return is_rational(element) && get_exponent(element).num > 0; + return is_rational_impl(element) && get_exponent(element).num > 0; } -[[nodiscard]] consteval bool is_positive_integral_power(MagnitudeSpecExpr auto element) +[[nodiscard]] consteval bool is_positive_integral_power_impl(auto element) { auto exp = get_exponent(element); return exp.den == 1 && exp.num > 0; @@ -198,7 +211,7 @@ template //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude product implementation. -[[nodiscard]] consteval bool less(MagnitudeSpecExpr auto lhs, MagnitudeSpecExpr auto rhs) +[[nodiscard]] consteval bool mag_less(auto lhs, auto rhs) { // clang-arm64 raises "error: implicit conversion from 'long' to 'long double' may lose precision" so we need an // explicit cast @@ -232,14 +245,14 @@ struct magnitude_base> { template [[nodiscard]] friend consteval Magnitude auto _multiply_impl(magnitude, magnitude) { - if constexpr (less(H, H2)) { + if constexpr (mag_less(H, H2)) { if constexpr (sizeof...(T) == 0) { // Shortcut for the "pure prepend" case, which makes it easier to implement some of the other cases. return magnitude{}; } else { return magnitude{} * (magnitude{} * magnitude{}); } - } else if constexpr (less(H2, H)) { + } else if constexpr (mag_less(H2, H)) { return magnitude

{} * (magnitude{} * magnitude{}); } else { if constexpr (is_same_v) { @@ -412,7 +425,7 @@ constexpr Out magnitude_symbol_impl(Out out, const unit_symbol_formatting& fmt) * Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, raise to * rational powers, and compare for equality. */ -template +template struct magnitude : detail::magnitude_base> { template [[nodiscard]] friend consteval Magnitude auto operator*(magnitude m1, M m2) @@ -435,18 +448,18 @@ struct magnitude : detail::magnitude_base> { private: // all below functions should in fact be in a `detail` namespace but are placed here to benefit from the ADL - [[nodiscard]] friend consteval bool _is_integral(const magnitude&) { return (detail::is_integral(Ms) && ...); } - [[nodiscard]] friend consteval bool _is_rational(const magnitude&) { return (detail::is_rational(Ms) && ...); } + [[nodiscard]] friend consteval bool _is_integral(const magnitude&) { return (detail::is_integral_impl(Ms) && ...); } + [[nodiscard]] friend consteval bool _is_rational(const magnitude&) { return (detail::is_rational_impl(Ms) && ...); } [[nodiscard]] friend consteval bool _is_positive_integral_power(const magnitude&) { - return (detail::is_positive_integral_power(Ms) && ...); + return (detail::is_positive_integral_power_impl(Ms) && ...); } /** * @brief The value of a Magnitude in a desired type T. */ template - requires((detail::is_integral(Ms) && ...)) || treat_as_floating_point + requires((detail::is_integral_impl(Ms) && ...)) || treat_as_floating_point [[nodiscard]] friend consteval T _get_value(const magnitude&) { // Force the expression to be evaluated in a constexpr context, to catch, e.g., overflow. diff --git a/src/core/include/mp-units/framework/magnitude_concepts.h b/src/core/include/mp-units/framework/magnitude_concepts.h index c5861f21..586c25e4 100644 --- a/src/core/include/mp-units/framework/magnitude_concepts.h +++ b/src/core/include/mp-units/framework/magnitude_concepts.h @@ -49,38 +49,7 @@ struct mag_constant; MP_UNITS_EXPORT template concept MagConstant = detail::TagType && is_derived_from_specialization_of_v; -namespace detail { - -/** - * @brief Any type which can be used as a basis vector in a PowerV. - * - * We have two categories. - * - * The first is just an integral type (either `int` or `std::intmax_t`). This is for prime number bases. - * These can always be used directly as NTTPs. - * - * The second category is a _custom tag type_, which inherits from `mag_constant` and has a static member variable - * `value` of type `long double` that holds its value. We choose `long double` to get the greatest degree of precision; - * users who need a different type can convert from this at compile time. This category is for any irrational base - * we admit into our representation (on which, more details below). - */ -template -concept PowerVBase = one_of || MagConstant; - -} // namespace detail - -template - requires(detail::valid_ratio && !detail::ratio_one) -struct power_v; - -namespace detail { - -template -concept MagnitudeSpecExpr = PowerVBase || is_specialization_of_v; - -} - -template +template struct magnitude; /**