diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 5892742a8..e87d0d97a 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -112,6 +112,9 @@ concept SameValueAs = (equivalent(get_unit(R1), get_unit(R2))) && std::convertib template using quantity_like_type = quantity::reference, typename quantity_like_traits::rep>; +template +concept Forwarding = std::derived_from, U>; + } // namespace detail MP_UNITS_EXPORT_BEGIN @@ -335,14 +338,14 @@ class quantity { return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference}; } - template Q = std::remove_cvref_t> - friend constexpr decltype(auto) operator++(FwdQ&& q) + template Q> + friend constexpr decltype(auto) operator++(Q&& q) requires requires(rep v) { { ++v } -> std::same_as; } { ++q.numerical_value_is_an_implementation_detail_; - return std::forward(q); + return std::forward(q); } [[nodiscard]] constexpr QuantityOf auto operator++(int) @@ -353,14 +356,14 @@ class quantity { return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference}; } - template Q = std::remove_cvref_t> - friend constexpr decltype(auto) operator--(FwdQ&& q) + template Q> + friend constexpr decltype(auto) operator--(Q&& q) requires requires(rep v) { { --v } -> std::same_as; } { --q.numerical_value_is_an_implementation_detail_; - return std::forward(q); + return std::forward(q); } [[nodiscard]] constexpr QuantityOf auto operator--(int) @@ -372,38 +375,38 @@ class quantity { } // compound assignment operators - template Q = std::remove_cvref_t> + template Q, auto R2, typename Rep2> requires detail::QuantityConvertibleTo, quantity> && requires(rep a, Rep2 b) { { a += b } -> std::same_as; } - friend constexpr decltype(auto) operator+=(FwdQ&& lhs, const quantity& rhs) + friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs) { if constexpr (equivalent(unit, get_unit(R2))) lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_; else lhs.numerical_value_is_an_implementation_detail_ += rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_; - return std::forward(lhs); + return std::forward(lhs); } - template Q = std::remove_cvref_t> + template Q, auto R2, typename Rep2> requires detail::QuantityConvertibleTo, quantity> && requires(rep a, Rep2 b) { { a -= b } -> std::same_as; } - friend constexpr decltype(auto) operator-=(FwdQ&& lhs, const quantity& rhs) + friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs) { if constexpr (equivalent(unit, get_unit(R2))) lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_; else lhs.numerical_value_is_an_implementation_detail_ -= rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_; - return std::forward(lhs); + return std::forward(lhs); } - template Q = std::remove_cvref_t> + template Q, auto R2, typename Rep2> requires detail::QuantityConvertibleTo, quantity> && (!treat_as_floating_point) && requires(rep a, Rep2 b) { { a %= b } -> std::same_as; } - friend constexpr decltype(auto) operator%=(FwdQ&& lhs, const quantity& rhs) + friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs) { MP_UNITS_EXPECTS_DEBUG(rhs != zero()); @@ -411,59 +414,59 @@ class quantity { lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_; else lhs.numerical_value_is_an_implementation_detail_ %= rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_; - return std::forward(lhs); + return std::forward(lhs); } - template Q = std::remove_cvref_t> + template Q, typename Value> requires(!Quantity) && requires(rep a, Value b) { { a *= b } -> std::same_as; } - friend constexpr decltype(auto) operator*=(FwdQ&& lhs, const Value& v) + friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v) { // TODO use *= when compiler bug is resolved: // https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ * v; - return std::forward(lhs); + return std::forward(lhs); } - template Q2, std::derived_from Q1 = std::remove_cvref_t> + template Q1, QuantityOf Q2> requires(Q2::unit == ::mp_units::one) && requires(rep a, Q2::rep b) { { a *= b } -> std::same_as; } - friend constexpr decltype(auto) operator*=(FwdQ1&& lhs, const Q2& rhs) + friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs) { // TODO use *= when compiler bug is resolved: // https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ * rhs.numerical_value_is_an_implementation_detail_; - return std::forward(lhs); + return std::forward(lhs); } - template Q = std::remove_cvref_t> + template Q, typename Value> requires(!Quantity) && requires(rep a, Value b) { { a /= b } -> std::same_as; } - friend constexpr decltype(auto) operator/=(FwdQ&& lhs, const Value& v) + friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v) { MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); // TODO use /= when compiler bug is resolved: // https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ / v; - return std::forward(lhs); + return std::forward(lhs); } - template Q2, std::derived_from Q1 = std::remove_cvref_t> + template Q1, QuantityOf Q2> requires(Q2::unit == ::mp_units::one) && requires(rep a, Q2::rep b) { { a /= b } -> std::same_as; } - friend constexpr decltype(auto) operator/=(FwdQ1&& lhs, const Q2& rhs) + friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs) { MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); // TODO use /= when compiler bug is resolved: // https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ / rhs.numerical_value_is_an_implementation_detail_; - return std::forward(lhs); + return std::forward(lhs); } // binary operators on quantities diff --git a/src/core/include/mp-units/framework/quantity_point.h b/src/core/include/mp-units/framework/quantity_point.h index 5cbd474bf..fb0f1d5a4 100644 --- a/src/core/include/mp-units/framework/quantity_point.h +++ b/src/core/include/mp-units/framework/quantity_point.h @@ -402,12 +402,12 @@ class quantity_point { } // member unary operators - template QP = std::remove_cvref_t> - friend constexpr decltype(auto) operator++(FwdQP&& qp) + template QP> + friend constexpr decltype(auto) operator++(QP&& qp) requires requires { ++qp.quantity_from_origin_is_an_implementation_detail_; } { ++qp.quantity_from_origin_is_an_implementation_detail_; - return std::forward(qp); + return std::forward(qp); } [[nodiscard]] constexpr quantity_point operator++(int) @@ -416,12 +416,12 @@ class quantity_point { return {quantity_from_origin_is_an_implementation_detail_++, PO}; } - template QP = std::remove_cvref_t> - friend constexpr decltype(auto) operator--(FwdQP&& qp) + template QP> + friend constexpr decltype(auto) operator--(QP&& qp) requires requires { --qp.quantity_from_origin_is_an_implementation_detail_; } { --qp.quantity_from_origin_is_an_implementation_detail_; - return std::forward(qp); + return std::forward(qp); } [[nodiscard]] constexpr quantity_point operator--(int) @@ -431,20 +431,20 @@ class quantity_point { } // compound assignment operators - template QP = std::remove_cvref_t> + template QP> requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; } - friend constexpr decltype(auto) operator+=(FwdQP&& qp, const quantity_type& q) + friend constexpr decltype(auto) operator+=(QP&& qp, const quantity_type& q) { qp.quantity_from_origin_is_an_implementation_detail_ += q; - return std::forward(qp); + return std::forward(qp); } - template QP = std::remove_cvref_t> + template QP> requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; } - friend constexpr decltype(auto) operator-=(FwdQP&& qp, const quantity_type& q) + friend constexpr decltype(auto) operator-=(QP&& qp, const quantity_type& q) { qp.quantity_from_origin_is_an_implementation_detail_ -= q; - return std::forward(qp); + return std::forward(qp); } // binary operators on quantity points