diff --git a/src/core/include/mp-units/bits/dimension_concepts.h b/src/core/include/mp-units/bits/dimension_concepts.h index cd8b2b9d..5a5991e4 100644 --- a/src/core/include/mp-units/bits/dimension_concepts.h +++ b/src/core/include/mp-units/bits/dimension_concepts.h @@ -101,4 +101,12 @@ concept DerivedDimension = is_derived_from_specialization_of concept Dimension = detail::BaseDimension || detail::DerivedDimension; +/** + * @brief A concept checking if the argument is of the same dimension. + * + * Satisfied when both argument satisfy a `Dimension` concept and when they compare equal. + */ +template +concept DimensionOf = Dimension && Dimension> && (T{} == D); + } // namespace mp_units 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 27838524..b7eca451 100644 --- a/src/core/include/mp-units/bits/quantity_spec_concepts.h +++ b/src/core/include/mp-units/bits/quantity_spec_concepts.h @@ -157,11 +157,23 @@ template namespace detail { template -concept DerivedFromQuantityKindSpecOf = +concept NestedQuantityKindSpecOf = QuantitySpec> && QuantitySpec> && get_kind(From) != get_kind(To) && std::derived_from, std::remove_cvref_t>; } +template +concept QuantitySpecOf = + QuantitySpec && QuantitySpec> && implicitly_convertible(T{}, QS) && + // the below is to make the following work + // static_assert(ReferenceOf); + // static_assert(!ReferenceOf); + // static_assert(!ReferenceOf + // static_assert(ReferenceOf); + // static_assert(!ReferenceOf); + !detail::NestedQuantityKindSpecOf && + (detail::QuantityKindSpec || !detail::NestedQuantityKindSpecOf); + } // namespace mp_units diff --git a/src/core/include/mp-units/bits/reference_concepts.h b/src/core/include/mp-units/bits/reference_concepts.h index c51d2d59..e0e3d6a4 100644 --- a/src/core/include/mp-units/bits/reference_concepts.h +++ b/src/core/include/mp-units/bits/reference_concepts.h @@ -72,11 +72,7 @@ template */ template concept ReferenceOf = - Reference && - ((Dimension> && get_quantity_spec(T{}).dimension == V) || - (QuantitySpec> && implicitly_convertible(get_quantity_spec(T{}), V) && - !detail::DerivedFromQuantityKindSpecOf && - (detail::QuantityKindSpec> || - !detail::DerivedFromQuantityKindSpecOf))); + Reference && (DimensionOf, V> || + QuantitySpecOf, V>); } // namespace mp_units diff --git a/src/core/include/mp-units/bits/unit_concepts.h b/src/core/include/mp-units/bits/unit_concepts.h index a669f5bc..ba727a20 100644 --- a/src/core/include/mp-units/bits/unit_concepts.h +++ b/src/core/include/mp-units/bits/unit_concepts.h @@ -185,10 +185,10 @@ concept AssociatedUnit = Unit && detail::has_associated_quantity(U{}); * the provided quantity_spec type. */ template -concept UnitOf = AssociatedUnit && QuantitySpec> && - implicitly_convertible(get_quantity_spec(U{}), QS) && - // the below is to make `dimensionless[radian]` invalid - (get_kind(QS) == get_kind(get_quantity_spec(U{})) || - !detail::DerivedFromQuantityKindSpecOf); +concept UnitOf = + AssociatedUnit && QuantitySpec> && + implicitly_convertible(get_quantity_spec(U{}), QS) && + // the below is to make `dimensionless[radian]` invalid + (get_kind(QS) == get_kind(get_quantity_spec(U{})) || !detail::NestedQuantityKindSpecOf); } // namespace mp_units diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index e66d2505..632ff81c 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -1354,7 +1354,7 @@ template else return exploded_kind_result( convertible_impl(from_kind, get_kind(explode(to_kind).quantity))); - } else if constexpr (DerivedFromQuantityKindSpecOf && get_kind(to) == to) + } else if constexpr (NestedQuantityKindSpecOf && get_kind(to) == to) return yes; else if constexpr (NamedQuantitySpec && NamedQuantitySpec) { if constexpr (have_common_base(from, to)) { @@ -1481,9 +1481,9 @@ template using QQ2 = std::remove_const_t; if constexpr (is_same_v) return q1; - else if constexpr (detail::DerivedFromQuantityKindSpecOf) + else if constexpr (detail::NestedQuantityKindSpecOf) return remove_kind(q1); - else if constexpr (detail::DerivedFromQuantityKindSpecOf) + else if constexpr (detail::NestedQuantityKindSpecOf) return remove_kind(q2); else if constexpr ((detail::QuantityKindSpec && !detail::QuantityKindSpec) || (detail::IntermediateDerivedQuantitySpec && detail::NamedQuantitySpec && diff --git a/test/unit_test/static/quantity_spec_test.cpp b/test/unit_test/static/quantity_spec_test.cpp index 96024fb2..c113f63b 100644 --- a/test/unit_test/static/quantity_spec_test.cpp +++ b/test/unit_test/static/quantity_spec_test.cpp @@ -792,6 +792,7 @@ static_assert((velocity / acceleration).character == quantity_character::scalar) // common_quantity_spec static_assert(common_quantity_spec(length, length) == length); +static_assert(common_quantity_spec(kind_of, kind_of) == kind_of); static_assert(common_quantity_spec(kind_of, length) == length); static_assert(common_quantity_spec(length, kind_of) == length); static_assert(common_quantity_spec(width, kind_of) == width);