From a962182e13339f7183b7ff6134cc6285dcf9670b Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 22 Dec 2023 16:35:06 +0100 Subject: [PATCH] feat: implicit point origins compatibility between different quantity specs added --- src/core/include/mp-units/quantity_point.h | 68 +++- test/unit_test/static/quantity_point_test.cpp | 367 +++++++++++++++++- 2 files changed, 410 insertions(+), 25 deletions(-) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 44ef0443..4f8c1bcc 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -63,27 +63,45 @@ struct relative_point_origin { static constexpr PointOrigin auto absolute_point_origin = QP.absolute_point_origin; }; -template -[[nodiscard]] consteval bool operator==(PO1 po1, PO2 po2) -{ - if constexpr (detail::AbsolutePointOrigin && detail::AbsolutePointOrigin) - return is_same_v; - else if constexpr (detail::RelativePointOrigin && detail::RelativePointOrigin) - return PO1::quantity_point == PO2::quantity_point; - else if constexpr (detail::RelativePointOrigin) - return detail::same_absolute_point_origins(po1, po2) && - detail::is_eq_zero(PO1::quantity_point.quantity_from(PO1::quantity_point.absolute_point_origin)); - else if constexpr (detail::RelativePointOrigin) - return detail::same_absolute_point_origins(po1, po2) && - detail::is_eq_zero(PO2::quantity_point.quantity_from(PO2::quantity_point.absolute_point_origin)); -} - template struct implicit_zeroth_point_origin_ : absolute_point_origin, QS> {}; template inline constexpr implicit_zeroth_point_origin_ implicit_zeroth_point_origin; +namespace detail { + +template +inline constexpr bool is_specialization_of_implicit_zeroth_point_origin = false; + +template +inline constexpr bool is_specialization_of_implicit_zeroth_point_origin> = true; + +template +[[nodiscard]] consteval bool is_implicit_zeroth_point_origin(PO) +{ + return is_specialization_of_implicit_zeroth_point_origin; +} + +} // namespace detail + +template +[[nodiscard]] consteval bool operator==(PO1 po1, PO2 po2) +{ + if constexpr (detail::AbsolutePointOrigin && detail::AbsolutePointOrigin) + return is_same_v || + (detail::is_implicit_zeroth_point_origin(po1) && detail::is_implicit_zeroth_point_origin(po2) && + interconvertible(po1.quantity_spec, po2.quantity_spec)); + else if constexpr (detail::RelativePointOrigin && detail::RelativePointOrigin) + return PO1::quantity_point == PO2::quantity_point; + else if constexpr (detail::RelativePointOrigin) + return detail::same_absolute_point_origins(po1, po2) && + detail::is_eq_zero(PO1::quantity_point.quantity_from_zero()); + else if constexpr (detail::RelativePointOrigin) + return detail::same_absolute_point_origins(po1, po2) && + detail::is_eq_zero(PO2::quantity_point.quantity_from_zero()); +} + template [[nodiscard]] consteval PointOriginFor auto zeroth_point_origin(R) { @@ -151,7 +169,7 @@ public: template requires QuantityOf, get_quantity_spec(R)> && std::constructible_from && - (point_origin == zeroth_point_origin(R)) && (point_origin == zeroth_point_origin(Q::reference)) + (point_origin == zeroth_point_origin(R)) && (implicitly_convertible(Q::quantity_spec, quantity_spec)) constexpr explicit quantity_point(Q&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward(q)) { } @@ -241,11 +259,13 @@ public: return *this - PO2{}; } - // returns always a value relative to the unit's zero - // available only if point is defined in terms of a unit's zero point origin [[nodiscard]] constexpr Quantity auto quantity_from_zero() const - requires(detail::same_absolute_point_origins(absolute_point_origin, zeroth_point_origin(R))) { + if constexpr (requires { unit.point_origin; }) { + // original quantity point unit can be lost in the below operation + const auto q = quantity_from(unit.point_origin); + if constexpr (requires { q.in(unit); }) + // restore the unit if possible (non-truncating) // original quantity point unit can be lost in the below operation const auto q = quantity_from(zeroth_point_origin(R)); if constexpr (requires { q.in(unit); }) @@ -378,7 +398,10 @@ template const quantity& q) requires requires { qp.quantity_ref_from(PO1) + q; } { - return quantity_point{qp.quantity_ref_from(PO1) + q, PO1}; + if constexpr (detail::is_implicit_zeroth_point_origin(PO1)) + return quantity_point{qp.quantity_ref_from(PO1) + q}; + else + return quantity_point{qp.quantity_ref_from(PO1) + q, PO1}; } template @@ -412,7 +435,10 @@ template const quantity& q) requires requires { qp.quantity_ref_from(PO1) - q; } { - return quantity_point{qp.quantity_ref_from(PO1) - q, PO1}; + if constexpr (detail::is_implicit_zeroth_point_origin(PO1)) + return quantity_point{qp.quantity_ref_from(PO1) - q}; + else + return quantity_point{qp.quantity_ref_from(PO1) - q, PO1}; } template diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 48b379a5..082ff3f2 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -33,9 +34,13 @@ namespace { using namespace mp_units; using namespace mp_units::si::unit_symbols; +using namespace mp_units::usc::unit_symbols; using namespace std::chrono_literals; using sys_seconds = std::chrono::time_point; +inline constexpr struct zeroth_length : absolute_point_origin { +} zeroth_length; + inline constexpr struct mean_sea_level : absolute_point_origin { } mean_sea_level; @@ -88,6 +93,7 @@ static_assert(my_ground_level == ground_level); static_assert(same_ground_level1 == ground_level); static_assert(same_ground_level2 == my_ground_level); +static_assert(mean_sea_level != zeroth_length); static_assert(mean_sea_level != other_absolute_level); static_assert(my_mean_sea_level != other_absolute_level); static_assert(ground_level != other_ground_level); @@ -123,6 +129,17 @@ static_assert(zeroth_point_origin(si::kelvin / si::second) == static_assert(zeroth_point_origin(si::degree_Celsius / si::second) == implicit_zeroth_point_origin>); +static_assert(implicit_zeroth_point_origin == implicit_zeroth_point_origin); +static_assert(implicit_zeroth_point_origin == + implicit_zeroth_point_origin); +static_assert(implicit_zeroth_point_origin> == implicit_zeroth_point_origin); +static_assert(implicit_zeroth_point_origin> == + implicit_zeroth_point_origin); + +static_assert(implicit_zeroth_point_origin != implicit_zeroth_point_origin); +static_assert(implicit_zeroth_point_origin != implicit_zeroth_point_origin); +static_assert(implicit_zeroth_point_origin != implicit_zeroth_point_origin); + ///////////////////// // class invariants ///////////////////// @@ -142,6 +159,8 @@ concept invalid_types = requires { requires !requires { typename QP; }; requires !requires { typename QP; }; requires !requires { typename QP; }; + requires !requires { typename QP, int>; }; + requires !requires { typename QP, int>; }; // quantity used as Rep requires !requires { typename QP>; }; // quantity point used as Rep @@ -167,6 +186,9 @@ concept valid_types = requires { typename QP; typename QP; typename QP; + typename QP, int>; + typename QP>, int>; + typename QP, int>; }; static_assert(valid_types); @@ -201,6 +223,22 @@ static_assert(std::three_way_comparable::reference == si::metre); +static_assert(quantity_point::quantity_spec == kind_of); +static_assert(quantity_point::dimension == isq::dim_length); +static_assert(quantity_point::unit == si::metre); +static_assert(is_of_type::point_origin, implicit_zeroth_point_origin_>>); +static_assert( + is_of_type::absolute_point_origin, implicit_zeroth_point_origin_>>); + +static_assert(quantity_point::reference == isq::height[m]); +static_assert(quantity_point::quantity_spec == isq::height); +static_assert(quantity_point::dimension == isq::dim_length); +static_assert(quantity_point::unit == si::metre); +static_assert(is_of_type::point_origin, implicit_zeroth_point_origin_>); +static_assert( + is_of_type::absolute_point_origin, implicit_zeroth_point_origin_>); + static_assert(quantity_point::reference == si::metre); static_assert(quantity_point::quantity_spec == kind_of); static_assert(quantity_point::dimension == isq::dim_length); @@ -348,6 +386,80 @@ static_assert(!std::convertible_to, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +// different dimensions +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +// convertible but different quantity_specs +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +// quantity_specs with common_quantity_spec +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +// non-convertible quantity_specs +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +// quantity-like +static_assert(!std::constructible_from, std::chrono::seconds>); +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::seconds>); +static_assert(!std::convertible_to>); + + +// ---------------------- +// explicit point origins +// ---------------------- + static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); @@ -366,6 +478,13 @@ static_assert(!std::convertible_to, quantity_point, quantity>); static_assert(!std::convertible_to, quantity_point>); +// quantity_specs with common_quantity_spec +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity>); +static_assert(!std::convertible_to, quantity_point>); + // different dimensions static_assert(!std::constructible_from, quantity>); static_assert(!std::convertible_to, quantity_point>); @@ -404,7 +523,60 @@ static_assert( // construction from a quantity point /////////////////////////////////////// -// same origins +// implicit origin +static_assert(std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); +static_assert(std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); +static_assert(std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); + +static_assert( + std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); + +static_assert(std::constructible_from, quantity_point>); +static_assert(std::convertible_to, quantity_point>); + +// convertible but different quantity_specs +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +// quantity_specs with common_quantity_spec +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +// non-convertible quantity_specs +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +// mixed origins +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); +static_assert(!std::constructible_from, quantity_point>); +static_assert(!std::convertible_to, quantity_point>); + +// same explicit origins static_assert( std::constructible_from, quantity_point>); static_assert( @@ -501,6 +673,22 @@ static_assert( static_assert( std::convertible_to, quantity_point>); +static_assert(std::constructible_from, + quantity_point>); +static_assert( + std::convertible_to, quantity_point>); + +// quantity_specs with common_quantity_spec +static_assert(!std::constructible_from, + quantity_point>); +static_assert( + !std::convertible_to, quantity_point>); + +static_assert(!std::constructible_from, + quantity_point>); +static_assert( + !std::convertible_to, quantity_point>); + // different dimensions static_assert( !std::constructible_from, quantity_point>); @@ -605,6 +793,11 @@ static_assert( // obtaining a relative quantity ////////////////////////////////// +static_assert(quantity_point{42 * m}.quantity_from_zero() == 42 * m); +static_assert(quantity_point{isq::height(42 * m)}.quantity_from_zero() == 42 * m); +static_assert(quantity_point{20 * deg_C}.quantity_from_zero() == 20 * deg_C); +static_assert(quantity_point{20. * deg_C}.in(deg_F).quantity_from_zero() == 68 * deg_F); + static_assert((mean_sea_level + 42 * m).quantity_from(mean_sea_level) == 42 * m); static_assert((mean_sea_level + isq::height(42 * m)).quantity_from(mean_sea_level) == 42 * m); @@ -669,17 +862,43 @@ static_assert(invalid_unit_conversion); // CTAD ///////// +static_assert(std::is_same_v); +static_assert(std::is_same_v, + implicit_zeroth_point_origin_>>); +static_assert(std::is_same_v, + implicit_zeroth_point_origin_>>); +static_assert(quantity_point{123 * m}.unit == si::metre); +static_assert(quantity_point{123 * m}.quantity_spec == kind_of); + +static_assert(std::is_same_v); +static_assert(std::is_same_v, + implicit_zeroth_point_origin_>); +static_assert(std::is_same_v, + implicit_zeroth_point_origin_>); +static_assert(quantity_point{isq::height(123 * m)}.unit == si::metre); +static_assert(quantity_point{isq::height(123 * m)}.quantity_spec == isq::height); + +static_assert(std::is_same_v); +static_assert(std::is_same_v, + struct si::zeroth_degree_Celsius>); +static_assert(std::is_same_v, + struct si::zeroth_kelvin>); +static_assert(quantity_point{20 * deg_C}.unit == si::degree_Celsius); +static_assert(quantity_point{20 * deg_C}.quantity_spec == kind_of); + using namespace std::chrono_literals; static_assert(std::is_same_v); static_assert(std::is_same_v, chrono_point_origin_>); +static_assert(std::is_same_v, + chrono_point_origin_>); static_assert(quantity_point{sys_seconds{24h}}.unit == si::second); static_assert(quantity_point{sys_seconds{24h}}.quantity_spec == kind_of); -// //////////// -// // getters -// //////////// +//////////// +// getters +//////////// constexpr quantity_point mean_sea_level_qp = mean_sea_level + 1 * m; constexpr quantity_point my_mean_sea_level_qp = my_mean_sea_level + 1 * m; @@ -808,12 +1027,39 @@ concept invalid_binary_operations = requires { requires !requires { isq::length(1 * m) + QP(1 * m); }; requires !requires { QP(1 * m) + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + QP(1 * m); }; + requires !requires { QP, int>(1 * m) + isq::length(1 * m); }; + requires !requires { isq::length(1 * m) + QP, int>(1 * m); }; + requires !requires { + QP, int>(1 * m) + isq::length(1 * m); + }; + requires !requires { + isq::length(1 * m) + QP, int>(1 * m); + }; requires !requires { Origin + isq::length(1 * m); }; requires !requires { isq::length(1 * m) + Origin; }; // can't subtract more generic quantity (violates point_origin quantity_spec) requires !requires { QP(1 * m) - isq::length(1 * m); }; requires !requires { QP(1 * m) - isq::length(1 * m); }; + requires !requires { QP, int>(1 * m) - isq::length(1 * m); }; + requires !requires { + QP, int>(1 * m) - isq::length(1 * m); + }; + requires !requires { + QP, int>(10 * isq::height[m] / + (2 * isq::time[s])) + + 5 * isq::speed[m / s]; + }; + requires !requires { + 5 * isq::speed[m / s] + + QP, int>( + 10 * isq::height[m] / (2 * isq::time[s])); + }; + requires !requires { + QP, int>(10 * isq::height[m] / + (2 * isq::time[s])) - + 5 * isq::speed[m / s]; + }; requires !requires { Origin - isq::length(1 * m); }; // quantity point can't be subtracted from a quantity @@ -835,6 +1081,28 @@ concept invalid_binary_operations = requires { }; requires !requires { mean_sea_level - QP(1 * m); }; requires !requires { QP(1 * m) - other_absolute_level; }; + requires !requires { QP(1 * m) - quantity_point{1 * m}; }; + requires !requires { quantity_point{1 * m} - QP(1 * m); }; + requires !requires { + QP, int>(1 * m) - quantity_point{isq::height(1 * m)}; + }; + requires !requires { + quantity_point{isq::height(1 * m)} - QP, int>(1 * m); + }; + requires !requires { + QP, int>(1 * m) - quantity_point{isq::length(1 * m)}; + }; + requires !requires { + quantity_point{isq::length(1 * m)} - QP, int>(1 * m); + }; + requires !requires { + quantity_point{10 * isq::height[m] / (2 * isq::time[s])} - + QP, int>(5 * isq::speed[m / s]); + }; + requires !requires { + QP, int>(5 * isq::speed[m / s]) - + quantity_point{10 * isq::height[m] / (2 * isq::time[s])}; + }; // cant'subtract two unrelated points requires !requires { Origin - OtherOrigin; }; @@ -1260,6 +1528,51 @@ static_assert( is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + (10 * isq::height[m] / (2 * isq::time[s])), quantity_point<(isq::height / isq::time)[m / s], zero_m_per_s, int>>); +static_assert((quantity_point{5 * isq::speed[m / s]} + 10 * isq::length[m] / (2 * isq::time[s])).quantity_from_zero() == + 10 * isq::speed[m / s]); +static_assert((10 * isq::length[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]}).quantity_from_zero() == + 10 * isq::speed[m / s]); +static_assert((quantity_point{5 * isq::speed[m / s]} - 10 * isq::length[m] / (2 * isq::time[s])).quantity_from_zero() == + 0 * isq::speed[m / s]); + +static_assert((quantity_point{10 * isq::length[m] / (2 * isq::time[s])} + 5 * isq::speed[m / s]).quantity_from_zero() == + 10 * isq::speed[m / s]); +static_assert((5 * isq::speed[m / s] + quantity_point{10 * isq::length[m] / (2 * isq::time[s])}).quantity_from_zero() == + 10 * isq::speed[m / s]); +static_assert((quantity_point{10 * isq::length[m] / (2 * isq::time[s])} - 5 * isq::speed[m / s]).quantity_from_zero() == + 0 * isq::speed[m / s]); + +static_assert((quantity_point{5 * isq::speed[m / s]} + 10 * isq::height[m] / (2 * isq::time[s])).quantity_from_zero() == + 10 * isq::speed[m / s]); +static_assert((10 * isq::height[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]}).quantity_from_zero() == + 10 * isq::speed[m / s]); +static_assert((quantity_point{5 * isq::speed[m / s]} - 10 * isq::height[m] / (2 * isq::time[s])).quantity_from_zero() == + 0 * isq::speed[m / s]); + +static_assert(is_of_type, int>>); +static_assert(is_of_type<10 * isq::height[m] / (2 * isq::time[s]) + quantity_point{5 * isq::speed[m / s]}, + quantity_point, int>>); +static_assert(is_of_type, int>>); +static_assert(is_of_type<5 * isq::speed[m / s] + quantity_point{10 * isq::length[m] / (2 * isq::time[s])}, + quantity_point, int>>); +static_assert(is_of_type, int>>); +static_assert(is_of_type, int>>); +static_assert( + is_of_type>); +static_assert( + is_of_type>); + +static_assert( + is_of_type< + quantity_point{10 * isq::height[m] / (2 * isq::time[s])} + (10 * isq::height[m] / (2 * isq::time[s])), + quantity_point<(isq::height / isq::time)[m / s], implicit_zeroth_point_origin, int>>); + inline constexpr struct zero_Hz : absolute_point_origin> { } zero_Hz; @@ -1297,6 +1610,40 @@ static_assert(is_of_type<(zero_Hz + 10 / (2 * isq::period_duration[s])) - (zero_ static_assert(is_of_type<(zero_Hz + 5 * isq::frequency[Hz]) - (zero_Hz + 10 / (2 * isq::period_duration[s])), quantity>); +static_assert((quantity_point{10 / (2 * isq::period_duration[s])} + 5 * isq::frequency[Hz]).quantity_from_zero() == + 10 * isq::frequency[Hz]); +static_assert((10 / (2 * isq::period_duration[s]) + quantity_point{zero_Hz + 5 * isq::frequency[Hz]}) + .quantity_from_zero() == 10 * isq::frequency[Hz]); +static_assert((quantity_point{5 * isq::frequency[Hz]} + 10 / (2 * isq::period_duration[s])).quantity_from_zero() == + 10 * isq::frequency[Hz]); +static_assert((5 * isq::frequency[Hz] + quantity_point{10 / (2 * isq::period_duration[s])}).quantity_from_zero() == + 10 * isq::frequency[Hz]); +static_assert((quantity_point{10 / (2 * isq::period_duration[s])} - 5 * isq::frequency[Hz]).quantity_from_zero() == + 0 * isq::frequency[Hz]); +static_assert((quantity_point{5 * isq::frequency[Hz]} - 10 / (2 * isq::period_duration[s])).quantity_from_zero() == + 0 * isq::frequency[Hz]); +static_assert(quantity_point{10 / (2 * isq::period_duration[s])} - quantity_point{5 * isq::frequency[Hz]} == + 0 * isq::frequency[Hz]); +static_assert(quantity_point{5 * isq::frequency[Hz]} - quantity_point{10 / (2 * isq::period_duration[s])} == + 0 * isq::frequency[Hz]); + +static_assert(is_of_type, int>>); +static_assert(is_of_type<10 / (2 * isq::period_duration[s]) + quantity_point{5 * isq::frequency[Hz]}, + quantity_point, int>>); +static_assert(is_of_type, int>>); +static_assert(is_of_type<5 * isq::frequency[Hz] + quantity_point{10 / (2 * isq::period_duration[s])}, + quantity_point, int>>); +static_assert(is_of_type, int>>); +static_assert(is_of_type, int>>); +static_assert(is_of_type>); +static_assert(is_of_type>); + // Different named dimensions template consteval bool invalid_addition(Ts... ts) @@ -1323,4 +1670,16 @@ static_assert(invalid_addition(5 * isq::activity[Bq], zero_Hz + 10 / (2 * isq::t static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), zero_Hz + 5 * isq::frequency[Hz])); static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); +static_assert(invalid_addition(quantity_point{5 * isq::activity[Bq]}, 5 * isq::frequency[Hz])); +static_assert(invalid_addition(5 * isq::activity[Bq], quantity_point{5 * isq::frequency[Hz]})); +static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, 5 * isq::frequency[Hz])); +static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, quantity_point{5 * isq::frequency[Hz]})); + +static_assert(invalid_addition(quantity_point{5 * isq::activity[Bq]}, 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz])); +static_assert(invalid_addition(5 * isq::activity[Bq], quantity_point{10 / (2 * isq::time[s])}, 5 * isq::frequency[Hz])); +static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), quantity_point{5 * isq::frequency[Hz]})); +static_assert(invalid_subtraction(quantity_point{5 * isq::activity[Bq]}, 10 / (2 * isq::time[s]), + 5 * isq::frequency[Hz])); + + } // namespace