diff --git a/docs/reference/core/concepts.rst b/docs/reference/core/concepts.rst index 7b7d62b6..fc06e807 100644 --- a/docs/reference/core/concepts.rst +++ b/docs/reference/core/concepts.rst @@ -59,20 +59,20 @@ Concepts .. concept:: template QuantityLike - A concept matching all quantity-like types. Satisfied by all types for which a correct specialization - of :class:`quantity_traits` type trait is provided. + A concept matching all quantity-like types other than specialization of :class:`quantity`. Satisfied by + all types for which a correct specialization of :class:`quantity_like_traits` type trait is provided. .. concept:: template WrappedQuantity A concept matching types that wrap quantity objects. Satisfied by all wrapper types that - satisfy :expr:`QuantityLike` recursively + satisfy :expr:`Quantity || QuantityLike` recursively (i.e. ``std::optional>``). .. concept:: template QuantityValue A concept matching types that can be used as a `Quantity` representation type. Satisfied - by types that match :expr:`(!QuantityLike) && (!WrappedQuantity) && std::regular` and - satisfy one of the following: + by types that match :expr:`(!Quantity) && (!QuantityLike) && (!WrappedQuantity) && std::regular` + and satisfy one of the following: - if :expr:`common_type_with` is ``true``, then :expr:`std::common_type_t` must at least provide binary multiplication and division operators, diff --git a/docs/reference/core/customization_points.rst b/docs/reference/core/customization_points.rst index eeb3813b..cb80f132 100644 --- a/docs/reference/core/customization_points.rst +++ b/docs/reference/core/customization_points.rst @@ -6,5 +6,5 @@ Customization Points .. doxygenstruct:: units::quantity_values :members: -.. doxygenstruct:: units::quantity_traits +.. doxygenstruct:: units::quantity_like_traits :members: diff --git a/src/include/units/bits/basic_concepts.h b/src/include/units/bits/basic_concepts.h index da8a889e..4f679ba7 100644 --- a/src/include/units/bits/basic_concepts.h +++ b/src/include/units/bits/basic_concepts.h @@ -216,7 +216,7 @@ inline constexpr bool is_quantity_point = false; /** * @brief A concept matching all quantities in the library. * - * Satisfied by all specializations of :class:`quantity`. + * Satisfied by all specializations of @c quantity. */ template concept Quantity = detail::is_quantity; @@ -224,23 +224,23 @@ concept Quantity = detail::is_quantity; /** * @brief A concept matching all quantity points in the library. * - * Satisfied by all specializations of :class:`quantity_point`. + * Satisfied by all specializations of @c quantity_point. */ template concept QuantityPoint = detail::is_quantity_point; /** - * @brief A concept matching all quantity-like types + * @brief A concept matching all quantity-like types (other than specialization of @c quantity) * - * Satisfied by all types for which a correct specialization of `quantity_traits` + * Satisfied by all types for which a correct specialization of `quantity_like_traits` * type trait is provided. */ template concept QuantityLike = requires(T q) { - typename quantity_traits::dimension; - typename quantity_traits::unit; - typename quantity_traits::rep; - { quantity_traits::count(q) } -> std::convertible_to::rep>; + typename quantity_like_traits::dimension; + typename quantity_like_traits::unit; + typename quantity_like_traits::rep; + { quantity_like_traits::count(q) } -> std::convertible_to::rep>; }; // QuantityValue @@ -279,7 +279,7 @@ inline constexpr bool is_wrapped_quantity = false; template requires requires { typename T::value_type; } -inline constexpr bool is_wrapped_quantity = QuantityLike || is_wrapped_quantity; +inline constexpr bool is_wrapped_quantity = Quantity || QuantityLike || is_wrapped_quantity; } // namespace detail @@ -300,6 +300,7 @@ concept wrapped_quantity_ = // exposition only */ template concept QuantityValue = + (!Quantity) && (!QuantityLike) && (!wrapped_quantity_) && std::regular && diff --git a/src/include/units/chrono.h b/src/include/units/chrono.h index 81e7a295..0130ea51 100644 --- a/src/include/units/chrono.h +++ b/src/include/units/chrono.h @@ -29,7 +29,7 @@ namespace units { template -struct quantity_traits> { +struct quantity_like_traits> { using dimension = physical::si::dim_time; using unit = downcast_unit; using rep = Rep; diff --git a/src/include/units/customization_points.h b/src/include/units/customization_points.h index fd4d8117..c74f0a2b 100644 --- a/src/include/units/customization_points.h +++ b/src/include/units/customization_points.h @@ -71,6 +71,6 @@ struct quantity_values { * @tparam T the type to provide support for */ template -struct quantity_traits; +struct quantity_like_traits; } // namespace units diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index d167e12c..7efdc723 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -36,8 +36,8 @@ namespace units { template concept floating_point_ = // exposition only - (QuantityLike && treat_as_floating_point::rep>) || - (!QuantityLike && treat_as_floating_point); + (Quantity && treat_as_floating_point) || + (!Quantity && treat_as_floating_point); template concept safe_convertible_to_ = // exposition only @@ -49,15 +49,15 @@ concept safe_convertible_to_ = // exposition only // QFrom ratio is an exact multiple of QTo template concept harmonic_ = // exposition only - QuantityLike && + Quantity && Quantity && requires(QFrom from, QTo to) { requires is_integral(detail::quantity_ratio(from) / detail::quantity_ratio(to)); }; template concept safe_castable_to_ = // exposition only - QuantityLike && - QuantityOf::dimension> && - scalable_with_::rep, typename QTo::rep> && + Quantity && + QuantityOf && + scalable_with_ && (floating_point_ || (!floating_point_ && harmonic_)); template @@ -81,6 +81,9 @@ template Q2> requires quantity_value_for_ using common_quantity_for = common_quantity>; +template +using quantity_like_type = quantity::dimension, typename quantity_like_traits::unit, typename quantity_like_traits::rep>; + /** * @brief A quantity * @@ -133,8 +136,12 @@ public: template Value> explicit(!(equivalent>)) constexpr quantity(const Value& v) : value_(static_cast(v)) {} + template + requires std::same_as> + explicit constexpr quantity(const Q& q) : value_(q.count()) {} + template Q> - explicit(!Quantity) constexpr quantity(const Q& q) : value_(quantity_cast(q).count()) {} + constexpr quantity(const Q& q) : value_(quantity_cast(q).count()) {} quantity& operator=(const quantity&) = default; quantity& operator=(quantity&&) = default; @@ -328,10 +335,10 @@ template explicit(false) quantity(V) -> quantity; template -explicit(!Quantity) quantity(Q) -> quantity::dimension, typename quantity_traits::unit, typename quantity_traits::rep>; +explicit quantity(Q) -> quantity_like_type; // non-member binary operators -template Q2> +template Q2> requires quantity_value_for_, typename Q1::rep, typename Q2::rep> [[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs) { @@ -404,14 +411,6 @@ template Q2> } // type traits -template -struct quantity_traits> { - using dimension = D; - using unit = U; - using rep = Rep; - static constexpr rep count(const quantity& q) { return q.count(); } -}; - namespace detail { template diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h index e41ca65d..2d9bacc6 100644 --- a/src/include/units/quantity_cast.h +++ b/src/include/units/quantity_cast.h @@ -44,17 +44,14 @@ class quantity_point; namespace detail { -template -constexpr auto quantity_ratio(const Q&) +template +constexpr auto quantity_ratio(const quantity&) { - using traits = quantity_traits; - using dim = TYPENAME traits::dimension; - using unit = TYPENAME traits::unit; - if constexpr(BaseDimension) { - return unit::ratio; + if constexpr(BaseDimension) { + return U::ratio; } else { - return dim::base_units_ratio * unit::ratio / dim::coherent_unit::ratio; + return D::base_units_ratio * U::ratio / D::coherent_unit::ratio; } } @@ -105,34 +102,29 @@ struct cast_traits { * * @tparam To a target quantity type to cast to */ -template - requires QuantityOf::dimension> && - scalable_with_::rep, typename To::rep> -[[nodiscard]] constexpr auto quantity_cast(const From& q) +template Rep> + requires QuantityOf +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - using traits = quantity_traits; - using from_dim = TYPENAME traits::dimension; - using from_unit = TYPENAME traits::unit; - using from_rep = TYPENAME traits::rep; using ret_unit = downcast_unit; using ret = quantity; - using cast_traits = detail::cast_traits; - using ratio_type = TYPENAME cast_traits::ratio_type; - using rep_type = TYPENAME cast_traits::rep_type; - constexpr auto c_ratio = detail::cast_ratio(quantity(), To()); + using traits = detail::cast_traits; + using ratio_type = TYPENAME traits::ratio_type; + using rep_type = TYPENAME traits::rep_type; + constexpr auto c_ratio = detail::cast_ratio(quantity(), To()); if constexpr (treat_as_floating_point) { - return ret(static_cast(static_cast(traits::count(q)) * + return ret(static_cast(static_cast(q.count()) * (static_cast(c_ratio.num) * detail::fpow10(c_ratio.exp) / static_cast(c_ratio.den)))); } else { if constexpr (c_ratio.exp > 0) { - return ret(static_cast(static_cast(traits::count(q)) * + return ret(static_cast(static_cast(q.count()) * (static_cast(c_ratio.num) * static_cast(detail::ipow10(c_ratio.exp))) / static_cast(c_ratio.den))); } else { - return ret(static_cast(static_cast(traits::count(q)) * + return ret(static_cast(static_cast(q.count()) * static_cast(c_ratio.num) / (static_cast(c_ratio.den) * static_cast(detail::ipow10(-c_ratio.exp))))); } @@ -151,11 +143,11 @@ template * * @tparam ToD a dimension type to use for a target quantity */ -template - requires equivalent::dimension> -[[nodiscard]] constexpr auto quantity_cast(const From& q) +template + requires equivalent +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - return quantity_cast, typename quantity_traits::rep>>(q); + return quantity_cast, Rep>>(q); } /** @@ -170,11 +162,11 @@ template * * @tparam ToU a unit type to use for a target quantity */ -template - requires UnitOf::dimension> -[[nodiscard]] constexpr auto quantity_cast(const From& q) +template + requires UnitOf +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - return quantity_cast::dimension, ToU, typename quantity_traits::rep>>(q); + return quantity_cast>(q); } /** @@ -193,11 +185,11 @@ template * @tparam ToD a dimension type to use for a target quantity * @tparam ToU a unit type to use for a target quantity */ -template - requires equivalent::dimension> && UnitOf -[[nodiscard]] constexpr auto quantity_cast(const From& q) +template + requires equivalent && UnitOf +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - return quantity_cast::rep>>(q); + return quantity_cast>(q); } /** @@ -212,11 +204,10 @@ template * * @tparam ToRep a representation type to use for a target quantity */ -template - requires scalable_with_::rep, ToRep> -[[nodiscard]] constexpr auto quantity_cast(const From& q) +template Rep> +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - return quantity_cast::dimension, typename quantity_traits::unit, ToRep>>(q); + return quantity_cast>(q); } /** diff --git a/test/unit_test/static/chrono_test.cpp b/test/unit_test/static/chrono_test.cpp index 6be21279..e712482f 100644 --- a/test/unit_test/static/chrono_test.cpp +++ b/test/unit_test/static/chrono_test.cpp @@ -37,14 +37,11 @@ static_assert(std::constructible_from, std::c static_assert(!std::convertible_to>); static_assert(std::constructible_from, std::chrono::seconds>); static_assert(!std::convertible_to>); -static_assert(std::constructible_from, std::chrono::hours>); +static_assert(!std::constructible_from, std::chrono::hours>); static_assert(!std::convertible_to>); static_assert(!std::constructible_from, std::chrono::seconds>); static_assert(!std::convertible_to>); -// quantity_cast -static_assert(quantity_cast>(7200s).count() == 2); - // CTAD static_assert(std::is_same_v>); static_assert(std::is_same_v>); diff --git a/test/unit_test/static/concepts_test.cpp b/test/unit_test/static/concepts_test.cpp index fcdf1518..0ad14f3d 100644 --- a/test/unit_test/static/concepts_test.cpp +++ b/test/unit_test/static/concepts_test.cpp @@ -118,7 +118,7 @@ static_assert(!QuantityPoint); static_assert(QuantityLike); static_assert(QuantityLike); -static_assert(QuantityLike>); +static_assert(!QuantityLike>); static_assert(!QuantityLike); // WrappedQuantity