refactor: Forwarding concept applied to quantity and quantity_point

This commit is contained in:
Mateusz Pusz
2024-10-29 13:56:02 +01:00
parent 699b0e7c23
commit c51b6e1f75
2 changed files with 42 additions and 39 deletions

View File

@ -112,6 +112,9 @@ concept SameValueAs = (equivalent(get_unit(R1), get_unit(R2))) && std::convertib
template<typename T> template<typename T>
using quantity_like_type = quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>; using quantity_like_type = quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;
template<typename T, typename U>
concept Forwarding = std::derived_from<std::remove_cvref_t<T>, U>;
} // namespace detail } // namespace detail
MP_UNITS_EXPORT_BEGIN MP_UNITS_EXPORT_BEGIN
@ -335,14 +338,14 @@ public:
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference}; return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference};
} }
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q>
friend constexpr decltype(auto) operator++(FwdQ&& q) friend constexpr decltype(auto) operator++(Q&& q)
requires requires(rep v) { requires requires(rep v) {
{ ++v } -> std::same_as<rep&>; { ++v } -> std::same_as<rep&>;
} }
{ {
++q.numerical_value_is_an_implementation_detail_; ++q.numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ>(q); return std::forward<Q>(q);
} }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator++(int) [[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator++(int)
@ -353,14 +356,14 @@ public:
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference}; return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference};
} }
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q>
friend constexpr decltype(auto) operator--(FwdQ&& q) friend constexpr decltype(auto) operator--(Q&& q)
requires requires(rep v) { requires requires(rep v) {
{ --v } -> std::same_as<rep&>; { --v } -> std::same_as<rep&>;
} }
{ {
--q.numerical_value_is_an_implementation_detail_; --q.numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ>(q); return std::forward<Q>(q);
} }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator--(int) [[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator--(int)
@ -372,38 +375,38 @@ public:
} }
// compound assignment operators // compound assignment operators
template<typename FwdQ, auto R2, typename Rep2, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, rep>, quantity> && requires(rep a, Rep2 b) { requires detail::QuantityConvertibleTo<quantity<R2, rep>, quantity> && requires(rep a, Rep2 b) {
{ a += b } -> std::same_as<rep&>; { a += b } -> std::same_as<rep&>;
} }
friend constexpr decltype(auto) operator+=(FwdQ&& lhs, const quantity<R2, Rep2>& rhs) friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{ {
if constexpr (equivalent(unit, get_unit(R2))) if constexpr (equivalent(unit, get_unit(R2)))
lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_;
else else
lhs.numerical_value_is_an_implementation_detail_ += rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ += rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ>(lhs); return std::forward<Q>(lhs);
} }
template<typename FwdQ, auto R2, typename Rep2, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, rep>, quantity> && requires(rep a, Rep2 b) { requires detail::QuantityConvertibleTo<quantity<R2, rep>, quantity> && requires(rep a, Rep2 b) {
{ a -= b } -> std::same_as<rep&>; { a -= b } -> std::same_as<rep&>;
} }
friend constexpr decltype(auto) operator-=(FwdQ&& lhs, const quantity<R2, Rep2>& rhs) friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{ {
if constexpr (equivalent(unit, get_unit(R2))) if constexpr (equivalent(unit, get_unit(R2)))
lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_;
else else
lhs.numerical_value_is_an_implementation_detail_ -= rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ -= rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ>(lhs); return std::forward<Q>(lhs);
} }
template<typename FwdQ, auto R2, typename Rep2, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, rep>, quantity> && (!treat_as_floating_point<rep>) && requires detail::QuantityConvertibleTo<quantity<R2, rep>, quantity> && (!treat_as_floating_point<rep>) &&
requires(rep a, Rep2 b) { requires(rep a, Rep2 b) {
{ a %= b } -> std::same_as<rep&>; { a %= b } -> std::same_as<rep&>;
} }
friend constexpr decltype(auto) operator%=(FwdQ&& lhs, const quantity<R2, Rep2>& rhs) friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{ {
MP_UNITS_EXPECTS_DEBUG(rhs != zero()); MP_UNITS_EXPECTS_DEBUG(rhs != zero());
@ -411,59 +414,59 @@ public:
lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
else else
lhs.numerical_value_is_an_implementation_detail_ %= rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ %= rhs.in(lhs.unit).numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ>(lhs); return std::forward<Q>(lhs);
} }
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q, typename Value>
requires(!Quantity<Value>) && requires(rep a, Value b) { requires(!Quantity<Value>) && requires(rep a, Value b) {
{ a *= b } -> std::same_as<rep&>; { a *= b } -> std::same_as<rep&>;
} }
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: // TODO use *= when compiler bug is resolved:
// https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 // 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; lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ * v;
return std::forward<FwdQ>(lhs); return std::forward<Q>(lhs);
} }
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>> template<detail::Forwarding<quantity> Q1, QuantityOf<dimensionless> Q2>
requires(Q2::unit == ::mp_units::one) && requires(rep a, Q2::rep b) { requires(Q2::unit == ::mp_units::one) && requires(rep a, Q2::rep b) {
{ a *= b } -> std::same_as<rep&>; { a *= b } -> std::same_as<rep&>;
} }
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: // TODO use *= when compiler bug is resolved:
// https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 // 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_ =
lhs.numerical_value_is_an_implementation_detail_ * rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ * rhs.numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ1>(lhs); return std::forward<Q1>(lhs);
} }
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>> template<detail::Forwarding<quantity> Q, typename Value>
requires(!Quantity<Value>) && requires(rep a, Value b) { requires(!Quantity<Value>) && requires(rep a, Value b) {
{ a /= b } -> std::same_as<rep&>; { a /= b } -> std::same_as<rep&>;
} }
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<Value>::zero()); MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
// TODO use /= when compiler bug is resolved: // TODO use /= when compiler bug is resolved:
// https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 // 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; lhs.numerical_value_is_an_implementation_detail_ = lhs.numerical_value_is_an_implementation_detail_ / v;
return std::forward<FwdQ>(lhs); return std::forward<Q>(lhs);
} }
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>> template<detail::Forwarding<quantity> Q1, QuantityOf<dimensionless> Q2>
requires(Q2::unit == ::mp_units::one) && requires(rep a, Q2::rep b) { requires(Q2::unit == ::mp_units::one) && requires(rep a, Q2::rep b) {
{ a /= b } -> std::same_as<rep&>; { a /= b } -> std::same_as<rep&>;
} }
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()); MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
// TODO use /= when compiler bug is resolved: // TODO use /= when compiler bug is resolved:
// https://developercommunity.visualstudio.com/t/Discrepancy-in-Behavior-of-operator-an/10732445 // 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_ =
lhs.numerical_value_is_an_implementation_detail_ / rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ / rhs.numerical_value_is_an_implementation_detail_;
return std::forward<FwdQ1>(lhs); return std::forward<Q1>(lhs);
} }
// binary operators on quantities // binary operators on quantities

View File

@ -402,12 +402,12 @@ public:
} }
// member unary operators // member unary operators
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>> template<detail::Forwarding<quantity_point> QP>
friend constexpr decltype(auto) operator++(FwdQP&& qp) friend constexpr decltype(auto) operator++(QP&& qp)
requires requires { ++qp.quantity_from_origin_is_an_implementation_detail_; } requires requires { ++qp.quantity_from_origin_is_an_implementation_detail_; }
{ {
++qp.quantity_from_origin_is_an_implementation_detail_; ++qp.quantity_from_origin_is_an_implementation_detail_;
return std::forward<FwdQP>(qp); return std::forward<QP>(qp);
} }
[[nodiscard]] constexpr quantity_point operator++(int) [[nodiscard]] constexpr quantity_point operator++(int)
@ -416,12 +416,12 @@ public:
return {quantity_from_origin_is_an_implementation_detail_++, PO}; return {quantity_from_origin_is_an_implementation_detail_++, PO};
} }
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>> template<detail::Forwarding<quantity_point> QP>
friend constexpr decltype(auto) operator--(FwdQP&& qp) friend constexpr decltype(auto) operator--(QP&& qp)
requires requires { --qp.quantity_from_origin_is_an_implementation_detail_; } requires requires { --qp.quantity_from_origin_is_an_implementation_detail_; }
{ {
--qp.quantity_from_origin_is_an_implementation_detail_; --qp.quantity_from_origin_is_an_implementation_detail_;
return std::forward<FwdQP>(qp); return std::forward<QP>(qp);
} }
[[nodiscard]] constexpr quantity_point operator--(int) [[nodiscard]] constexpr quantity_point operator--(int)
@ -431,20 +431,20 @@ public:
} }
// compound assignment operators // compound assignment operators
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>> template<detail::Forwarding<quantity_point> QP>
requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; } 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; qp.quantity_from_origin_is_an_implementation_detail_ += q;
return std::forward<FwdQP>(qp); return std::forward<QP>(qp);
} }
template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>> template<detail::Forwarding<quantity_point> QP>
requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; } 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; qp.quantity_from_origin_is_an_implementation_detail_ -= q;
return std::forward<FwdQP>(qp); return std::forward<QP>(qp);
} }
// binary operators on quantity points // binary operators on quantity points