From 50cc9dfdedf0e8e4cea3578a018d3ee3410ee783 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 11 Jul 2024 16:08:47 +0200 Subject: [PATCH 1/5] refactor: binary operators of `quantity` and `quantity_point` are now hidden friends --- .../include/mp-units/framework/quantity.h | 216 +++++++++--------- .../mp-units/framework/quantity_point.h | 194 ++++++++-------- 2 files changed, 206 insertions(+), 204 deletions(-) diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 960835b3..1017693b 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -461,6 +461,115 @@ public: 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 @@ -473,113 +582,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 1b5e22ab..8dbfdc48 100644 --- a/src/core/include/mp-units/framework/quantity_point.h +++ b/src/core/include/mp-units/framework/quantity_point.h @@ -413,6 +413,102 @@ public: 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 + [[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 + [[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 + [[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 @@ -428,29 +524,7 @@ explicit(is_specialization_of::to_numeri -> quantity_point::reference, quantity_point_like_traits::point_origin, typename quantity_point_like_traits::rep>; -template -// TODO simplify when gcc catches up - requires ReferenceOf -[[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 -[[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) @@ -465,19 +539,6 @@ template return po + std::forward(q); } -template -// TODO simplify when gcc catches up - requires ReferenceOf -[[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) @@ -486,47 +547,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 || @@ -542,26 +562,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 From bfb964b01766b2ffd2f44bfbf617654a8f98d10c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 11 Jul 2024 16:08:47 +0200 Subject: [PATCH 2/5] docs: CHANGELOG updated --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b0781df..2e86989e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ - refactor: `terminate` replaced with `abort` and a header file added - refactor: most `std::remove_const_t` removed and some replaced with the GCC-specific workaround - refactor: not needed `remove_reference_t` and `remove_cvref_t` removed +- refactor: binary operators of `quantity` and `quantity_point` are now hidden friends - fix: `QuantityLike` conversions required `Q::rep` instead of using one provided by `quantity_like_traits` - fix: `QuantitySpec[Unit]` replaced with `make_reference` in `value_cast` - fix: `ice_point` is now defined with the integral offset from `absolute_zero` From 037964bbbae7da8ce142a80f096d00d9165d8053 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 11 Jul 2024 17:19:31 +0200 Subject: [PATCH 3/5] fix: disabled convertibility of `quantity` binary operators arguments --- .../include/mp-units/framework/quantity.h | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 1017693b..81b98217 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -463,9 +463,9 @@ public: } // binary operators on quantities - template + template Q, auto R2, typename Rep2> requires detail::CommonlyInvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const quantity& rhs) { using ret = detail::common_quantity_for, quantity, quantity>; const ret ret_lhs(lhs); @@ -474,9 +474,9 @@ public: ret::reference}; } - template + template Q, auto R2, typename Rep2> requires detail::CommonlyInvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const quantity& rhs) { using ret = detail::common_quantity_for, quantity, quantity>; const ret ret_lhs(lhs); @@ -485,10 +485,10 @@ public: ret::reference}; } - template + template Q, auto R2, typename Rep2> 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) + [[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const quantity& rhs) { MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); using ret = detail::common_quantity_for, quantity, quantity>; @@ -498,61 +498,61 @@ public: ret::reference}; } - template + template Q, auto R2, typename Rep2> requires detail::InvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr Quantity auto operator*(const Q& 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 + template Q, typename Value> requires(!Quantity) && (!Reference) && detail::InvokeResultOf, Rep, const Value&> - [[nodiscard]] friend constexpr QuantityOf auto operator*(const quantity& q, const Value& v) + [[nodiscard]] friend constexpr QuantityOf auto operator*(const Q& q, const Value& v) { return ::mp_units::quantity{q.numerical_value_ref_in(get_unit(R)) * v, R}; } - template + template Q> requires(!Quantity) && (!Reference) && detail::InvokeResultOf, const Value&, Rep> - [[nodiscard]] friend constexpr QuantityOf auto operator*(const Value& v, const quantity& q) + [[nodiscard]] friend constexpr QuantityOf auto operator*(const Value& v, const Q& q) { return ::mp_units::quantity{v * q.numerical_value_ref_in(get_unit(R)), R}; } - template + template Q, auto R2, typename Rep2> requires detail::InvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr Quantity auto operator/(const Q& 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 + template Q, typename Value> requires(!Quantity) && (!Reference) && detail::InvokeResultOf, Rep, const Value&> - [[nodiscard]] friend constexpr QuantityOf auto operator/(const quantity& q, const Value& v) + [[nodiscard]] friend constexpr QuantityOf auto operator/(const Q& 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 + template Q> requires(!Quantity) && (!Reference) && detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] friend constexpr QuantityOf auto operator/(const Value& v, - const quantity& q) + const Q& q) { return ::mp_units::quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R}; } - template + template Q, auto R2, typename Rep2> requires requires { typename std::common_type_t>; } && std::equality_comparable>::rep> - [[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr bool operator==(const Q& lhs, const quantity& rhs) { using ct = std::common_type_t>; const ct ct_lhs(lhs); @@ -560,10 +560,10 @@ public: return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit); } - template + template Q, auto R2, typename Rep2> requires requires { typename std::common_type_t>; } && std::three_way_comparable>::rep> - [[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const quantity& rhs) { using ct = std::common_type_t>; const ct ct_lhs(lhs); From a70ef1ebc34b53df6ad06b27bf19d234bc4794ce Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 11 Jul 2024 18:05:51 +0200 Subject: [PATCH 4/5] Revert "fix: disabled convertibility of `quantity` binary operators arguments" This reverts commit 037964bbbae7da8ce142a80f096d00d9165d8053. --- .../include/mp-units/framework/quantity.h | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 81b98217..1017693b 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -463,9 +463,9 @@ public: } // binary operators on quantities - template Q, auto R2, typename Rep2> + template requires detail::CommonlyInvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const quantity& rhs) + [[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); @@ -474,9 +474,9 @@ public: ret::reference}; } - template Q, auto R2, typename Rep2> + template requires detail::CommonlyInvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const quantity& rhs) + [[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); @@ -485,10 +485,10 @@ public: ret::reference}; } - template Q, auto R2, typename Rep2> + template requires(!treat_as_floating_point) && (!treat_as_floating_point) && detail::CommonlyInvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const quantity& rhs) + [[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>; @@ -498,61 +498,61 @@ public: ret::reference}; } - template Q, auto R2, typename Rep2> + template requires detail::InvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator*(const Q& lhs, const quantity& rhs) + [[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 Q, typename Value> + template requires(!Quantity) && (!Reference) && detail::InvokeResultOf, Rep, const Value&> - [[nodiscard]] friend constexpr QuantityOf auto operator*(const Q& q, const Value& v) + [[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 Q> + template requires(!Quantity) && (!Reference) && detail::InvokeResultOf, const Value&, Rep> - [[nodiscard]] friend constexpr QuantityOf auto operator*(const Value& v, const Q& q) + [[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 Q, auto R2, typename Rep2> + template requires detail::InvocableQuantities, quantity, quantity> - [[nodiscard]] friend constexpr Quantity auto operator/(const Q& lhs, const quantity& rhs) + [[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 Q, typename Value> + template requires(!Quantity) && (!Reference) && detail::InvokeResultOf, Rep, const Value&> - [[nodiscard]] friend constexpr QuantityOf auto operator/(const Q& q, const Value& v) + [[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 Q> + template requires(!Quantity) && (!Reference) && detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] friend constexpr QuantityOf auto operator/(const Value& v, - const Q& q) + const quantity& q) { return ::mp_units::quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R}; } - template Q, auto R2, typename Rep2> + template requires requires { typename std::common_type_t>; } && std::equality_comparable>::rep> - [[nodiscard]] friend constexpr bool operator==(const Q& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t>; const ct ct_lhs(lhs); @@ -560,10 +560,10 @@ public: return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit); } - template Q, auto R2, typename Rep2> + template requires requires { typename std::common_type_t>; } && std::three_way_comparable>::rep> - [[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const quantity& rhs) + [[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t>; const ct ct_lhs(lhs); From 175fd04c3a89de81406c51c53e55edc9df94573e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 11 Jul 2024 19:18:28 +0200 Subject: [PATCH 5/5] fix: LA library bug workaround Blocked by BobSteagall/wg21#77 --- CMakeLists.txt | 2 +- conanfile.py | 3 ++- docs/getting_started/installation_and_usage.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17624eb8..2523ab49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") set(projectPrefix MP_UNITS_) -option(${projectPrefix}DEV_BUILD_LA "Build code depending on the linear algebra library" ON) +option(${projectPrefix}DEV_BUILD_LA "Build code depending on the linear algebra library" OFF) option(${projectPrefix}DEV_IWYU "Enables include-what-you-use" OFF) option(${projectPrefix}DEV_CLANG_TIDY "Enables clang-tidy" OFF) diff --git a/conanfile.py b/conanfile.py index cc559918..e944fdc1 100644 --- a/conanfile.py +++ b/conanfile.py @@ -178,7 +178,8 @@ class MPUnitsConan(ConanFile): @property def _skip_la(self): - return bool(self.conf.get("user.mp-units.build:skip_la", default=False)) + # broken until https://github.com/BobSteagall/wg21/issues/77 is fixed + return bool(self.conf.get("user.mp-units.build:skip_la", default=True)) @property def _run_clang_tidy(self): diff --git a/docs/getting_started/installation_and_usage.md b/docs/getting_started/installation_and_usage.md index 05c43fec..eb283fdc 100644 --- a/docs/getting_started/installation_and_usage.md +++ b/docs/getting_started/installation_and_usage.md @@ -304,7 +304,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"} [`user.mp-units.build:skip_la`](#user-skip-la){ #user-skip-la } -: [:octicons-tag-24: 2.2.0][conan skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`) +: [:octicons-tag-24: 2.2.0][conan skip la support] · :octicons-milestone-24: `True`/`False` (Default: `True`) If `user.mp-units.build:all` is enabled, among others, Conan installs the external [wg21-linear_algebra](https://conan.io/center/recipes/wg21-linear_algebra)