diff --git a/src/core/include/mp-units/bits/quantity_spec_concepts.h b/src/core/include/mp-units/bits/quantity_spec_concepts.h index d685c923c..9ee2b6905 100644 --- a/src/core/include/mp-units/bits/quantity_spec_concepts.h +++ b/src/core/include/mp-units/bits/quantity_spec_concepts.h @@ -130,7 +130,7 @@ concept QuantitySpec = detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec || detail::QuantityKindSpec; template -[[nodiscard]] consteval QuantitySpec auto get_kind(Q q); +[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q); namespace detail { @@ -138,7 +138,7 @@ template concept NestedQuantityKindSpecOf = QuantitySpec> && QuantitySpec> && get_kind(From) != get_kind(To) && - std::derived_from, std::remove_cvref_t>; + std::derived_from, std::remove_cvref_t>; } diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index ae958d045..d0524a774 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -444,11 +444,15 @@ namespace detail { template concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec; +template +[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q); + } // namespace detail #ifdef __cpp_explicit_this_parameter template - requires(detail::QuantitySpecWithNoSpecifiers>) && (get_kind(Q) == Q) + requires(detail::QuantitySpecWithNoSpecifiers>) && + (detail::detail::get_kind_tree_root(Q) == Q) struct kind_of_ : std::remove_const_t { static constexpr auto _quantity_spec_ = Q; }; @@ -456,10 +460,11 @@ struct kind_of_ : std::remove_const_t { #if MP_UNITS_COMP_CLANG template - requires detail::QuantitySpecWithNoSpecifiers> && (get_kind(Q) == Q) + requires detail::QuantitySpecWithNoSpecifiers> && + (detail::get_kind_tree_root(Q) == Q) #else template - requires(get_kind(Q) == Q) + requires(detail::get_kind_tree_root(Q) == Q) #endif struct kind_of_ : quantity_spec, Q> { static constexpr auto _quantity_spec_ = Q; @@ -467,7 +472,7 @@ struct kind_of_ : quantity_spec, Q> { #endif template - requires(get_kind(Q) == Q) + requires(detail::get_kind_tree_root(Q) == Q) inline constexpr kind_of_ kind_of; namespace detail { @@ -484,6 +489,15 @@ template return q; } +template +[[nodiscard]] consteval auto remove_kind(Q q) +{ + if constexpr (detail::QuantityKindSpec) + return Q::_quantity_spec_; + else + return q; +} + } // namespace detail // Operators @@ -493,7 +507,7 @@ template { return detail::clone_kind_of( detail::expr_multiply( - remove_kind(lhs), remove_kind(rhs))); + detail::remove_kind(lhs), detail::remove_kind(rhs))); } template @@ -501,7 +515,7 @@ template { return detail::clone_kind_of( detail::expr_divide( - remove_kind(lhs), remove_kind(rhs))); + detail::remove_kind(lhs), detail::remove_kind(rhs))); } template @@ -538,13 +552,13 @@ template else if constexpr (detail::IntermediateDerivedQuantitySpec) return detail::clone_kind_of( detail::expr_pow( - remove_kind(q))); + detail::remove_kind(q))); else if constexpr (Den == 1) return detail::clone_kind_of( - derived_quantity_spec, Num>>{}); + derived_quantity_spec, Num>>{}); else return detail::clone_kind_of( - derived_quantity_spec, Num, Den>>{}); + derived_quantity_spec, Num, Den>>{}); } @@ -1315,8 +1329,8 @@ template else if constexpr (From{} == To{}) return yes; else if constexpr (QuantityKindSpec || QuantityKindSpec) { - constexpr auto from_kind = get_kind(From{}); - constexpr auto to_kind = get_kind(To{}); + constexpr auto from_kind = get_kind_tree_root(From{}); + constexpr auto to_kind = get_kind_tree_root(To{}); constexpr auto exploded_kind_result = [](specs_convertible_result res) { using enum specs_convertible_result; return res == no ? no : yes; @@ -1327,11 +1341,11 @@ template return convertible_impl(from_kind, to_kind); else if constexpr (get_complexity(from_kind) > get_complexity(to_kind)) return exploded_kind_result( - convertible_impl(get_kind(explode(from_kind).quantity), to_kind)); + convertible_impl(get_kind_tree_root(explode(from_kind).quantity), to_kind)); else return exploded_kind_result( - convertible_impl(from_kind, get_kind(explode(to_kind).quantity))); - } else if constexpr (NestedQuantityKindSpecOf && get_kind(To{}) == To{}) + convertible_impl(from_kind, get_kind_tree_root(explode(to_kind).quantity))); + } else if constexpr (NestedQuantityKindSpecOf && get_kind_tree_root(To{}) == To{}) return yes; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { if constexpr (have_common_base(From{}, To{})) { @@ -1401,8 +1415,8 @@ template namespace detail { template - requires requires(Q q) { get_kind(q); } -using to_kind = std::remove_const_t; + requires requires(Q q) { get_kind_tree_root(q); } +using to_kind = std::remove_const_t; #ifdef __cpp_explicit_this_parameter template @@ -1415,19 +1429,8 @@ template return contains(); } -} // namespace detail - -template -[[nodiscard]] consteval auto remove_kind(Q q) -{ - if constexpr (detail::QuantityKindSpec) - return Q::_quantity_spec_; - else - return q; -} - template -[[nodiscard]] consteval QuantitySpec auto get_kind(Q q) +[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q) { auto defined_as_kind = [](QQ qq) { if constexpr (requires { detail::defined_as_kind(qq); }) @@ -1441,7 +1444,7 @@ template } else if constexpr (defined_as_kind(Q{})) { return q; } else if constexpr (requires { Q::_parent_; }) { - return get_kind(Q::_parent_); + return get_kind_tree_root(Q::_parent_); } else if constexpr (detail::IntermediateDerivedQuantitySpec) { return detail::expr_map(q); @@ -1451,20 +1454,29 @@ template } } +} // namespace detail + +template +[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q) +{ + return kind_of; +} + [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; } template [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2) - requires(implicitly_convertible(get_kind(q1), get_kind(q2)) || implicitly_convertible(get_kind(q2), get_kind(q1))) + requires(implicitly_convertible(get_kind_tree_root(q1), get_kind_tree_root(q2)) || + implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1))) { - using QQ1 = std::remove_const_t; - using QQ2 = std::remove_const_t; + using QQ1 = std::remove_const_t; + using QQ2 = std::remove_const_t; if constexpr (is_same_v) return q1; else if constexpr (detail::NestedQuantityKindSpecOf) - return remove_kind(q1); + return detail::remove_kind(q1); else if constexpr (detail::NestedQuantityKindSpecOf) - return remove_kind(q2); + return detail::remove_kind(q2); else if constexpr ((detail::QuantityKindSpec && !detail::QuantityKindSpec) || (detail::IntermediateDerivedQuantitySpec && detail::NamedQuantitySpec && implicitly_convertible(Q1{}, Q2{}))) @@ -1479,10 +1491,10 @@ template return q2; else if constexpr (implicitly_convertible(Q2{}, Q1{})) return q1; - else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{}))) - return get_kind(q2); + else if constexpr (implicitly_convertible(get_kind_tree_root(Q1{}), get_kind_tree_root(Q2{}))) + return get_kind_tree_root(q2); else - return get_kind(q1); + return get_kind_tree_root(q1); } [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2,