diff --git a/src/core/include/mp-units/bits/quantity_point_concepts.h b/src/core/include/mp-units/bits/quantity_point_concepts.h index a27af90b..5de5c944 100644 --- a/src/core/include/mp-units/bits/quantity_point_concepts.h +++ b/src/core/include/mp-units/bits/quantity_point_concepts.h @@ -60,22 +60,44 @@ inline constexpr bool is_derived_from_specialization_of_absolute_point_origin = template concept QuantityPoint = detail::is_quantity_point; +template +struct relative_point_origin; + +namespace detail { + +template +inline constexpr bool is_specialization_of_relative_point_origin = false; + +template +inline constexpr bool is_specialization_of_relative_point_origin> = true; + +template +void to_base_specialization_of_relative_point_origin(const volatile relative_point_origin*); + +template +inline constexpr bool is_derived_from_specialization_of_relative_point_origin = + requires(T* t) { to_base_specialization_of_relative_point_origin(t); }; + +} // namespace detail + /** * @brief A concept matching all quantity point origins in the library * * Satisfied by either quantity points or by all types derived from `absolute_point_origin` class template. */ template -concept PointOrigin = QuantityPoint || detail::is_derived_from_specialization_of_absolute_point_origin; +concept PointOrigin = detail::is_derived_from_specialization_of_absolute_point_origin || + (detail::is_derived_from_specialization_of_relative_point_origin && + !detail::is_specialization_of_relative_point_origin); /** * @brief A concept matching all quantity point origins for a specified quantity type in the library * * Satisfied by all quantity point origins that are defined using a provided quantity specification. */ -template +template concept PointOriginFor = - PointOrigin && QuantitySpec> && implicitly_convertible(Q, T::quantity_spec); + PointOrigin && QuantitySpec> && implicitly_convertible(QS, T::quantity_spec); template auto PO, RepresentationOf Rep> @@ -108,7 +130,8 @@ concept QuantityPointOf = QuantityPoint && (ReferenceOf, V> || (PointOrigin> && - (std::same_as, std::remove_const_t> || + (std::same_as, std::remove_const_t> || + std::same_as, std::remove_const_t> || (detail::is_specialization_of_absolute_point_origin> && detail::is_specialization_of_absolute_point_origin> && implicitly_convertible(QP::absolute_point_origin.quantity_spec, V.quantity_spec) && diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 5a4044cf..848f7779 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -34,12 +34,18 @@ struct absolute_point_origin { static constexpr QuantitySpec auto quantity_spec = Q; }; +template +struct relative_point_origin { + static constexpr QuantityPoint auto parent_origin = QP; + static constexpr QuantitySpec auto quantity_spec = QP.quantity_spec; +}; + namespace detail { [[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PointOrigin auto po) { - if constexpr (requires { po.absolute_point_origin; }) - return po.absolute_point_origin; + if constexpr (requires { po.parent_origin.absolute_point_origin; }) + return po.parent_origin.absolute_point_origin; else return po; } @@ -145,7 +151,7 @@ public: std::remove_const_t>) return relative(); else - return point_origin.absolute() + relative(); + return point_origin.parent_origin.absolute() + relative(); } template diff --git a/test/unit_test/static/concepts_test.cpp b/test/unit_test/static/concepts_test.cpp index 76cb5e80..fc73faa0 100644 --- a/test/unit_test/static/concepts_test.cpp +++ b/test/unit_test/static/concepts_test.cpp @@ -360,15 +360,20 @@ static_assert(!QuantityLike); // QuantityPoint inline constexpr struct my_origin : absolute_point_origin { } my_origin; +inline constexpr struct my_relative_origin : + relative_point_origin{42 * si::metre}> { +} my_relative_origin; static_assert(QuantityPoint>); static_assert(QuantityPoint>); static_assert(QuantityPoint{}, int>>); static_assert(QuantityPoint{}, int>>); static_assert(QuantityPoint>); +static_assert(QuantityPoint>); static_assert(!QuantityPoint>); static_assert(!QuantityPoint>); static_assert(!QuantityPoint); +static_assert(!QuantityPoint); static_assert(!QuantityPoint); static_assert(!QuantityPoint>); static_assert(!QuantityPoint); @@ -390,28 +395,41 @@ static_assert( QuantityPointOf{}, int>, isq::radius>); static_assert(QuantityPointOf, isq::length>); static_assert(QuantityPointOf, isq::radius>); +static_assert(QuantityPointOf, isq::length>); +static_assert(QuantityPointOf, isq::radius>); static_assert(QuantityPointOf, absolute_point_origin{}>); static_assert(QuantityPointOf, absolute_point_origin{}>); -static_assert(QuantityPointOf, my_origin>); +static_assert(!QuantityPointOf, my_origin>); +static_assert(!QuantityPointOf, my_relative_origin>); static_assert(QuantityPointOf, absolute_point_origin{}>); static_assert(!QuantityPointOf, absolute_point_origin{}>); static_assert(!QuantityPointOf, my_origin>); +static_assert(!QuantityPointOf, my_relative_origin>); static_assert(QuantityPointOf, absolute_point_origin{}>); static_assert(QuantityPointOf, absolute_point_origin{}>); -static_assert(QuantityPointOf, my_origin>); +static_assert(!QuantityPointOf, my_origin>); +static_assert(!QuantityPointOf, my_relative_origin>); static_assert(QuantityPointOf, my_origin>); -static_assert(QuantityPointOf, absolute_point_origin{}>); +static_assert(QuantityPointOf, my_relative_origin>); +static_assert( + QuantityPointOf, absolute_point_origin{}>); +static_assert( + !QuantityPointOf, absolute_point_origin{}>); static_assert( !QuantityPointOf, absolute_point_origin{}>); +static_assert( + !QuantityPointOf, absolute_point_origin{}>); // PointOrigin static_assert(PointOrigin>); static_assert(PointOrigin); -static_assert(PointOrigin>); -static_assert(PointOrigin>); -static_assert(PointOrigin{}, int>>); -static_assert(PointOrigin{}, int>>); -static_assert(PointOrigin>); +static_assert(PointOrigin); +static_assert(!PointOrigin{42 * si::metre}>>); +static_assert(!PointOrigin>); +static_assert(!PointOrigin>); +static_assert(!PointOrigin{}, int>>); +static_assert(!PointOrigin{}, int>>); +static_assert(!PointOrigin>); static_assert(!PointOrigin>); static_assert(!PointOrigin); static_assert(!PointOrigin>); @@ -426,42 +444,48 @@ static_assert(!PointOriginFor, isq::time>); static_assert(PointOriginFor); static_assert(PointOriginFor); static_assert(!PointOriginFor); -static_assert(PointOriginFor, isq::length>); -static_assert(PointOriginFor, isq::radius>); +static_assert(PointOriginFor); +static_assert(PointOriginFor); +static_assert(!PointOriginFor); +static_assert(!PointOriginFor, isq::length>); +static_assert(!PointOriginFor, isq::radius>); static_assert(!PointOriginFor, isq::time>); -static_assert(PointOriginFor, isq::length>); -static_assert(PointOriginFor, isq::radius>); +static_assert(!PointOriginFor, isq::length>); +static_assert(!PointOriginFor, isq::radius>); static_assert(!PointOriginFor, isq::time>); static_assert(!PointOriginFor, isq::length>); -static_assert(PointOriginFor, isq::radius>); +static_assert(!PointOriginFor, isq::radius>); static_assert(!PointOriginFor, isq::time>); static_assert( - PointOriginFor{}, int>, isq::length>); + !PointOriginFor{}, int>, isq::length>); static_assert( - PointOriginFor{}, int>, isq::radius>); + !PointOriginFor{}, int>, isq::radius>); static_assert( !PointOriginFor{}, int>, isq::time>); static_assert( !PointOriginFor{}, int>, isq::length>); static_assert( - PointOriginFor{}, int>, isq::radius>); + !PointOriginFor{}, int>, isq::radius>); static_assert( !PointOriginFor{}, int>, isq::time>); -static_assert(PointOriginFor>{}, int>, - isq::length>); -static_assert(PointOriginFor>{}, int>, - isq::radius>); +static_assert(!PointOriginFor< + quantity_point>{}, int>, isq::length>); +static_assert(!PointOriginFor< + quantity_point>{}, int>, isq::radius>); static_assert(!PointOriginFor< quantity_point>{}, int>, isq::time>); static_assert(!PointOriginFor< quantity_point>{}, int>, isq::length>); -static_assert(PointOriginFor>{}, int>, - isq::radius>); +static_assert(!PointOriginFor< + quantity_point>{}, int>, isq::radius>); static_assert( !PointOriginFor{}, int>, isq::time>); static_assert(!PointOriginFor, isq::length>); -static_assert(PointOriginFor, isq::radius>); +static_assert(!PointOriginFor, isq::radius>); static_assert(!PointOriginFor, isq::time>); +static_assert(!PointOriginFor, isq::length>); +static_assert(!PointOriginFor, isq::radius>); +static_assert(!PointOriginFor, isq::time>); static_assert(!PointOriginFor, isq::length>); static_assert(!PointOriginFor); static_assert(!PointOriginFor, isq::length>); diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 401e39cb..b656ec81 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -39,8 +39,13 @@ using sys_seconds = std::chrono::time_point { } mean_sea_level; -inline constexpr quantity_point ground_level{42 * isq::height[m]}; -inline constexpr quantity_point everest_base_camp{5364 * m}; +inline constexpr struct ground_level : + relative_point_origin{42 * isq::height[m]}> { +} ground_level; + +inline constexpr struct everest_base_camp : + relative_point_origin{5364 * m}> { +} everest_base_camp; QUANTITY_SPEC(special_height, isq::height); QUANTITY_SPEC(activity, 1 / isq::time);