From b4bb7227b90976e69128ab2bad8a879ce6c737b9 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 27 Sep 2023 17:06:08 +0200 Subject: [PATCH] feat: `UnitCompatibleWith` added and applied to `in(U)` and `force_in(U)` functions --- .../framework_basics/basic_concepts.md | 12 +++++++++++- src/core/include/mp-units/bits/unit_concepts.h | 18 ++++++++++++++++++ src/core/include/mp-units/quantity.h | 8 ++++---- src/core/include/mp-units/quantity_point.h | 4 ++-- src/core/include/mp-units/quantity_spec.h | 1 + 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/docs/users_guide/framework_basics/basic_concepts.md b/docs/users_guide/framework_basics/basic_concepts.md index adc98a27..478ae14f 100644 --- a/docs/users_guide/framework_basics/basic_concepts.md +++ b/docs/users_guide/framework_basics/basic_concepts.md @@ -263,13 +263,23 @@ concept with an associated quantity type implicitly convertible to `V`. [nested quantity kind within the dimensionless quantities tree](dimensionless_quantities.md/#nested-quantity-kinds). +### `UnitCompatibleWith` { #UnitCompatibleWith } + +`UnitCompatibleWith` concept is satisfied for all units `T` when: + +- `V1` is a [`Unit`](#Unit), +- `V2` is a [`QuantitySpec`](#QuantitySpec), +- `T` and `V1` are defined in terms of the same reference unit, +- if `T` is an [`AssociatedUnit`](#AssociatedUnit) it should satisfy [`UnitOf`](#UnitOf). + + ## `Reference` { #Reference } `Reference` concept is satisfied by all [quantity reference](../../appendix/glossary.md#reference) types. Such types provide all the meta-information required to create a [`Quantity`](#Quantity). A `Reference` can either be: -- An [AssociatedUnit](#AssociatedUnit). +- An [`AssociatedUnit`](#AssociatedUnit). - The instantiation of a `reference` class template with a [`QuantitySpec`](#QuantitySpec) passed as the first template argument and a [`Unit`](#Unit) passed as the second one. diff --git a/src/core/include/mp-units/bits/unit_concepts.h b/src/core/include/mp-units/bits/unit_concepts.h index 51b806d2..f4e616c8 100644 --- a/src/core/include/mp-units/bits/unit_concepts.h +++ b/src/core/include/mp-units/bits/unit_concepts.h @@ -193,4 +193,22 @@ concept UnitOf = // the below is to make `dimensionless[radian]` invalid (get_kind(QS) == get_kind(get_quantity_spec(U{})) || !detail::NestedQuantityKindSpecOf); +namespace detail { + +[[nodiscard]] consteval bool have_same_canonical_reference_unit(Unit auto u1, Unit auto u2); + +} + +/** + * @brief A concept matching all units compatible with the provided unit and quantity spec + * + * Satisfied by all units that have the same canonical reference as `U2` and in case they + * have associated quantity specification it should satisfy `UnitOf`. + */ +template +concept UnitCompatibleWith = + Unit && Unit> && QuantitySpec> && + (!AssociatedUnit || UnitOf)&&detail::have_same_canonical_reference_unit(U{}, U2); + + } // namespace mp_units diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index e1e989cd..498a9a32 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -142,14 +142,14 @@ public: quantity& operator=(quantity&&) = default; // conversions - template + template U> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr quantity in(U) const { return quantity{*this}; } - template + template U> requires requires(quantity q) { value_cast(q); } [[nodiscard]] constexpr quantity force_in(U) const { @@ -175,14 +175,14 @@ public: requires(U{} == unit) constexpr const rep&& numerical_value_ref_in(U) const&& noexcept = delete; - template + template U> requires requires(quantity q) { q.in(U{}); } [[nodiscard]] constexpr rep numerical_value_in(U) const noexcept { return (*this).in(U{}).numerical_value_; } - template + template U> requires requires(quantity q) { q.force_in(U{}); } [[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept { diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 3a8dd8bd..74a51d92 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -168,14 +168,14 @@ public: return *this - PO2{}; } - template + template U> requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr quantity_point in(U) const { return make_quantity_point(quantity_ref_from(PO).in(U{})); } - template + template U> requires requires(quantity_type q) { value_cast(q); } [[nodiscard]] constexpr quantity_point force_in(U) const { diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index fde4d157..b94e476c 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -40,6 +40,7 @@ namespace detail { template + requires(!AssociatedUnit) || UnitOf [[nodiscard]] consteval Reference auto make_reference(QS qs, U u) { if constexpr (detail::QuantityKindSpec)