diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index f67a79bd7f..a649898293 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -411,6 +411,115 @@ class quantity { lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_; return std::forward(lhs); } + + // binary operators on quantities + template + requires detail::CommonlyInvocableQuantities, quantity, quantity> + [[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) + { + using ret = detail::common_quantity_for, quantity, quantity>; + const ret ret_lhs(lhs); + const ret ret_rhs(rhs); + return ::mp_units::quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit), + ret::reference}; + } + + template + requires detail::CommonlyInvocableQuantities, quantity, quantity> + [[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) + { + using ret = detail::common_quantity_for, quantity, quantity>; + const ret ret_lhs(lhs); + const ret ret_rhs(rhs); + return ::mp_units::quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit), + ret::reference}; + } + + template + requires(!treat_as_floating_point) && (!treat_as_floating_point) && + detail::CommonlyInvocableQuantities, quantity, quantity> + [[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs) + { + MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); + using ret = detail::common_quantity_for, quantity, quantity>; + const ret ret_lhs(lhs); + const ret ret_rhs(rhs); + return ::mp_units::quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit), + ret::reference}; + } + + template + requires detail::InvocableQuantities, quantity, quantity> + [[nodiscard]] friend constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) + { + return ::mp_units::quantity{lhs.numerical_value_ref_in(get_unit(R)) * rhs.numerical_value_ref_in(get_unit(R2)), + R * R2}; + } + + template + requires(!Quantity) && (!Reference) && + detail::InvokeResultOf, Rep, const Value&> + [[nodiscard]] friend constexpr QuantityOf auto operator*(const quantity& q, const Value& v) + { + return ::mp_units::quantity{q.numerical_value_ref_in(get_unit(R)) * v, R}; + } + + template + requires(!Quantity) && (!Reference) && + detail::InvokeResultOf, const Value&, Rep> + [[nodiscard]] friend constexpr QuantityOf auto operator*(const Value& v, const quantity& q) + { + return ::mp_units::quantity{v * q.numerical_value_ref_in(get_unit(R)), R}; + } + + template + requires detail::InvocableQuantities, quantity, quantity> + [[nodiscard]] friend constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) + { + MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); + return ::mp_units::quantity{lhs.numerical_value_ref_in(get_unit(R)) / rhs.numerical_value_ref_in(get_unit(R2)), + R / R2}; + } + + template + requires(!Quantity) && (!Reference) && + detail::InvokeResultOf, Rep, const Value&> + [[nodiscard]] friend constexpr QuantityOf auto operator/(const quantity& q, const Value& v) + { + MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); + return ::mp_units::quantity{q.numerical_value_ref_in(get_unit(R)) / v, R}; + } + + template + requires(!Quantity) && (!Reference) && + detail::InvokeResultOf, const Value&, Rep> + [[nodiscard]] friend constexpr QuantityOf auto operator/(const Value& v, + const quantity& q) + { + return ::mp_units::quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R}; + } + + template + requires requires { typename std::common_type_t>; } && + std::equality_comparable>::rep> + [[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity& rhs) + { + using ct = std::common_type_t>; + const ct ct_lhs(lhs); + const ct ct_rhs(rhs); + return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit); + } + + template + requires requires { typename std::common_type_t>; } && + std::three_way_comparable>::rep> + [[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) + { + using ct = std::common_type_t>; + const ct ct_lhs(lhs); + const ct ct_rhs(rhs); + return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit); + } }; // CTAD @@ -423,113 +532,6 @@ explicit( is_specialization_of::to_numerical_value(std::declval())), convert_explicitly>) quantity(Q) -> quantity::reference, typename quantity_like_traits::rep>; -// binary operators on quantities -template - requires detail::CommonlyInvocableQuantities, quantity, quantity> -[[nodiscard]] constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) -{ - using ret = detail::common_quantity_for, quantity, quantity>; - const ret ret_lhs(lhs); - const ret ret_rhs(rhs); - return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit), - ret::reference}; -} - -template - requires detail::CommonlyInvocableQuantities, quantity, quantity> -[[nodiscard]] constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) -{ - using ret = detail::common_quantity_for, quantity, quantity>; - const ret ret_lhs(lhs); - const ret ret_rhs(rhs); - return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit), - ret::reference}; -} - -template - requires(!treat_as_floating_point) && (!treat_as_floating_point) && - detail::CommonlyInvocableQuantities, quantity, quantity> -[[nodiscard]] constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs) -{ - MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); - using ret = detail::common_quantity_for, quantity, quantity>; - const ret ret_lhs(lhs); - const ret ret_rhs(rhs); - return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit), - ret::reference}; -} - -template - requires detail::InvocableQuantities, quantity, quantity> -[[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) -{ - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), R1 * R2}; -} - -template - requires(!Quantity) && (!Reference) && - detail::InvokeResultOf, Rep, const Value&> -[[nodiscard]] constexpr QuantityOf auto operator*(const quantity& q, const Value& v) -{ - return quantity{q.numerical_value_ref_in(get_unit(R)) * v, R}; -} - -template - requires(!Quantity) && (!Reference) && - detail::InvokeResultOf, const Value&, Rep> -[[nodiscard]] constexpr QuantityOf auto operator*(const Value& v, const quantity& q) -{ - return quantity{v * q.numerical_value_ref_in(get_unit(R)), R}; -} - -template - requires detail::InvocableQuantities, quantity, quantity> -[[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) -{ - MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2}; -} - -template - requires(!Quantity) && (!Reference) && - detail::InvokeResultOf, Rep, const Value&> -[[nodiscard]] constexpr QuantityOf auto operator/(const quantity& q, const Value& v) -{ - MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); - return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R}; -} - -template - requires(!Quantity) && (!Reference) && - detail::InvokeResultOf, const Value&, Rep> -[[nodiscard]] constexpr QuantityOf auto operator/(const Value& v, - const quantity& q) -{ - return quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R}; -} - -template - requires requires { typename std::common_type_t, quantity>; } && - std::equality_comparable, quantity>::rep> -[[nodiscard]] constexpr bool operator==(const quantity& lhs, const quantity& rhs) -{ - using ct = std::common_type_t, quantity>; - const ct ct_lhs(lhs); - const ct ct_rhs(rhs); - return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit); -} - -template - requires requires { typename std::common_type_t, quantity>; } && - std::three_way_comparable, quantity>::rep> -[[nodiscard]] constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) -{ - using ct = std::common_type_t, quantity>; - const ct ct_lhs(lhs); - const ct ct_rhs(rhs); - return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit); -} - MP_UNITS_EXPORT_END } // namespace mp_units diff --git a/src/core/include/mp-units/framework/quantity_point.h b/src/core/include/mp-units/framework/quantity_point.h index adacb6b795..9c0e0e1f58 100644 --- a/src/core/include/mp-units/framework/quantity_point.h +++ b/src/core/include/mp-units/framework/quantity_point.h @@ -370,6 +370,102 @@ class quantity_point { qp.quantity_from_origin_is_an_implementation_detail_ -= q; return std::forward(qp); } + + // binary operators on quantity points + template + // TODO simplify when gcc catches up + requires ReferenceOf, PO.quantity_spec> + [[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity_point& qp, const quantity& q) + requires requires { qp.quantity_ref_from(PO) + q; } + { + if constexpr (detail::is_zeroth_point_origin(PO)) + return ::mp_units::quantity_point{qp.quantity_ref_from(PO) + q}; + else + return ::mp_units::quantity_point{qp.quantity_ref_from(PO) + q, PO}; + } + + template + // TODO simplify when gcc catches up + requires ReferenceOf, PO.quantity_spec> + [[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity& q, const quantity_point& qp) + requires requires { q + qp.quantity_ref_from(PO); } + { + return qp + q; + } + + template + // TODO simplify when gcc catches up + requires ReferenceOf, PO.quantity_spec> + [[nodiscard]] friend constexpr QuantityPoint auto operator-(const quantity_point& qp, const quantity& q) + requires requires { qp.quantity_ref_from(PO) - q; } + { + if constexpr (detail::is_zeroth_point_origin(PO)) + return ::mp_units::quantity_point{qp.quantity_ref_from(PO) - q}; + else + return ::mp_units::quantity_point{qp.quantity_ref_from(PO) - q, PO}; + } + + template QP2> + [[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP2& rhs) + // TODO consider constraining it for both branches + requires requires { lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin); } + { + if constexpr (point_origin == QP2::point_origin) + return lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin); + else + return lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin) + + (lhs.point_origin - rhs.point_origin); + } + + template + requires QuantityPointOf && + ReferenceOf, PO2::quantity_spec> + [[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& qp, PO2 po) + { + if constexpr (point_origin == po) + return qp.quantity_ref_from(point_origin); + else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin) { + if constexpr (point_origin == absolute_point_origin) + return qp.quantity_ref_from(point_origin); + else + return qp.quantity_ref_from(point_origin) + (qp.point_origin - qp.absolute_point_origin); + } else { + if constexpr (point_origin == po.quantity_point.point_origin) + return qp.quantity_ref_from(point_origin) - po.quantity_point.quantity_ref_from(po.quantity_point.point_origin); + else + return qp.quantity_ref_from(point_origin) - + po.quantity_point.quantity_ref_from(po.quantity_point.point_origin) + + (qp.point_origin - po.quantity_point.point_origin); + } + } + + template + requires QuantityPointOf && + ReferenceOf, PO1::quantity_spec> + [[nodiscard]] friend constexpr Quantity auto operator-(PO1 po, const quantity_point& qp) + { + return -(qp - po); + } + + template QP2> + requires std::equality_comparable_with + [[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP2& rhs) + { + if constexpr (point_origin == QP2::point_origin) + return lhs.quantity_ref_from(point_origin) == rhs.quantity_ref_from(QP2::point_origin); + else + return lhs - lhs.absolute_point_origin == rhs - rhs.absolute_point_origin; + } + + template QP2> + requires std::three_way_comparable_with + [[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP2& rhs) + { + if constexpr (point_origin == QP2::point_origin) + return lhs.quantity_ref_from(point_origin) <=> rhs.quantity_ref_from(QP2::point_origin); + else + return lhs - lhs.absolute_point_origin <=> rhs - rhs.absolute_point_origin; + } }; // CTAD @@ -386,29 +482,7 @@ explicit( -> quantity_point::reference, quantity_point_like_traits::point_origin, typename quantity_point_like_traits::rep>; -template -// TODO simplify when gcc catches up - requires ReferenceOf, PO1.quantity_spec> -[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point& qp, - const quantity& q) - requires requires { qp.quantity_ref_from(PO1) + q; } -{ - if constexpr (detail::is_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 -// TODO simplify when gcc catches up - requires ReferenceOf, PO2.quantity_spec> -[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity& q, - const quantity_point& qp) - requires requires { q + qp.quantity_ref_from(PO2); } -{ - return qp + q; -} - +// binary operators on point origins template requires ReferenceOf, PO::quantity_spec> [[nodiscard]] constexpr quantity_point operator+(PO, Q&& q) @@ -423,19 +497,6 @@ template return po + std::forward(q); } -template -// TODO simplify when gcc catches up - requires ReferenceOf, PO1.quantity_spec> -[[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point& qp, - const quantity& q) - requires requires { qp.quantity_ref_from(PO1) - q; } -{ - if constexpr (detail::is_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 requires ReferenceOf, PO::quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator-(PO po, const Q& q) @@ -444,47 +505,6 @@ template return po + (-q); } -template QP2> -[[nodiscard]] constexpr Quantity auto operator-(const QP1& lhs, const QP2& rhs) - // TODO consider constraining it for both branches - requires requires { lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin); } -{ - if constexpr (QP1::point_origin == QP2::point_origin) - return lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin); - else - return lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin) + - (lhs.point_origin - rhs.point_origin); -} - -template QP> - requires ReferenceOf, PO::quantity_spec> -[[nodiscard]] constexpr Quantity auto operator-(const QP& qp, PO po) -{ - if constexpr (QP::point_origin == po) - return qp.quantity_ref_from(QP::point_origin); - else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin) { - if constexpr (QP::point_origin == QP::absolute_point_origin) - return qp.quantity_ref_from(QP::point_origin); - else - return qp.quantity_ref_from(QP::point_origin) + (qp.point_origin - qp.absolute_point_origin); - } else { - if constexpr (QP::point_origin == po.quantity_point.point_origin) - return qp.quantity_ref_from(QP::point_origin) - - po.quantity_point.quantity_ref_from(po.quantity_point.point_origin); - else - return qp.quantity_ref_from(QP::point_origin) - - po.quantity_point.quantity_ref_from(po.quantity_point.point_origin) + - (qp.point_origin - po.quantity_point.point_origin); - } -} - -template QP> - requires ReferenceOf, PO::quantity_spec> -[[nodiscard]] constexpr Quantity auto operator-(PO po, const QP& qp) -{ - return -(qp - po); -} - template PO2> requires QuantitySpecOf, PO2::quantity_spec> && (detail::is_derived_from_specialization_of_relative_point_origin || @@ -500,26 +520,6 @@ template PO2> } } -template QP2> - requires std::three_way_comparable_with -[[nodiscard]] constexpr auto operator<=>(const QP1& lhs, const QP2& rhs) -{ - if constexpr (QP1::point_origin == QP2::point_origin) - return lhs.quantity_ref_from(QP1::point_origin) <=> rhs.quantity_ref_from(QP2::point_origin); - else - return lhs - lhs.absolute_point_origin <=> rhs - rhs.absolute_point_origin; -} - -template QP2> - requires std::equality_comparable_with -[[nodiscard]] constexpr bool operator==(const QP1& lhs, const QP2& rhs) -{ - if constexpr (QP1::point_origin == QP2::point_origin) - return lhs.quantity_ref_from(QP1::point_origin) == rhs.quantity_ref_from(QP2::point_origin); - else - return lhs - lhs.absolute_point_origin == rhs - rhs.absolute_point_origin; -} - MP_UNITS_EXPORT_END } // namespace mp_units