From 32aa05700b9b194116eb55b98d9ad11dcc72d992 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 16 May 2023 13:41:41 +0200 Subject: [PATCH] refactor: `quantity` binary operators are not hidden friends anymore to prevent surprising conversions --- src/core/include/mp_units/quantity.h | 307 +++++++++++++-------------- 1 file changed, 151 insertions(+), 156 deletions(-) diff --git a/src/core/include/mp_units/quantity.h b/src/core/include/mp_units/quantity.h index 77170bb8..765b92ee 100644 --- a/src/core/include/mp_units/quantity.h +++ b/src/core/include/mp_units/quantity.h @@ -317,162 +317,6 @@ public: return *this; } - // Hidden Friends - // Below friend functions are to be found via argument-dependent lookup only - template - requires detail::InvocableQuantities, quantity, Q> - [[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const Q& rhs) - { - using ret = detail::common_quantity_for, quantity, Q>; - return make_quantity(ret(lhs).number() + ret(rhs).number()); - } - - template - requires detail::InvocableQuantities, quantity, Q> - [[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const Q& rhs) - { - using ret = detail::common_quantity_for, quantity, Q>; - return make_quantity(ret(lhs).number() - ret(rhs).number()); - } - - template - requires detail::InvokeResultOf<(quantity_spec * Q::quantity_spec).character, std::multiplies<>, rep, - typename Q::rep> - [[nodiscard]] friend constexpr Quantity auto operator*(const quantity& lhs, const Q& rhs) - { - return make_quantity(lhs.number() * rhs.number()); - } - - template - requires(!Quantity) && detail::InvokeResultOf, rep, const Value&> - [[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v) - { - return make_quantity(q.number() * v); - } - - template - requires(!Quantity) && detail::InvokeResultOf, const Value&, rep> - [[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q) - { - return make_quantity(v * q.number()); - } - - template - requires detail::InvokeResultOf<(quantity_spec / Q::quantity_spec).character, std::divides<>, rep, typename Q::rep> - [[nodiscard]] friend constexpr Quantity auto operator/(const quantity& lhs, const Q& rhs) - { - gsl_ExpectsAudit(rhs.number() != quantity_values::zero()); - return make_quantity(lhs.number() / rhs.number()); - } - - template - requires(!Quantity) && detail::InvokeResultOf, rep, const Value&> - [[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v) - { - gsl_ExpectsAudit(v != quantity_values::zero()); - return make_quantity(q.number() / v); - } - - template - requires(!Quantity) && detail::InvokeResultOf, const Value&, rep> - [[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q) - { - return make_quantity<::mp_units::one / reference>(v / q.number()); - } - - template - requires(!treat_as_floating_point) && - (!treat_as_floating_point) && detail::InvocableQuantities, quantity, Q> - [[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const Q& rhs) - { - gsl_ExpectsAudit(rhs.number() != quantity_values::zero()); - using ret = detail::common_quantity_for, quantity, Q>; - return make_quantity(ret(lhs).number() % ret(rhs).number()); - } - - template - requires requires { typename std::common_type_t; } && - std::equality_comparable::rep> - [[nodiscard]] friend constexpr bool operator==(const quantity& lhs, const Q& rhs) - { - using ct = std::common_type_t; - return ct(lhs).number() == ct(rhs).number(); - } - - template - requires requires { typename std::common_type_t; } && - std::three_way_comparable::rep> - [[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const Q& rhs) - { - using ct = std::common_type_t; - return ct(lhs).number() <=> ct(rhs).number(); - } - - - // dimensionless quantities support for interacting with raw values - template - requires(dimension == dimension_one) && - (unit == ::mp_units::one) && detail::RepSafeConstructibleFrom> - constexpr explicit(false) quantity(Value&& v) : number_(std::forward(v)) - { - } - - template - requires(!Quantity) && - (dimension == dimension_one) && detail::InvokeResultOf, rep, Value> - [[nodiscard]] friend constexpr Quantity auto operator+(const quantity& q, const Value& v) - { - return q + make_quantity<::mp_units::one>(v); - } - - template - requires(!Quantity) && - (dimension == dimension_one) && detail::InvokeResultOf, Value, rep> - [[nodiscard]] friend constexpr Quantity auto operator+(const Value& v, const quantity& q) - { - return make_quantity<::mp_units::one>(v) + q; - } - - template - requires(!Quantity) && - (dimension == dimension_one) && detail::InvokeResultOf, rep, Value> - [[nodiscard]] friend constexpr Quantity auto operator-(const quantity& q, const Value& v) - { - return q - make_quantity<::mp_units::one>(v); - } - - template - requires(!Quantity) && - (dimension == dimension_one) && detail::InvokeResultOf, Value, rep> - [[nodiscard]] friend constexpr Quantity auto operator-(const Value& v, const quantity& q) - { - return make_quantity<::mp_units::one>(v) - q; - } - - template - requires(!Quantity) && (dimension == dimension_one) && (unit == ::mp_units::one) && - (!treat_as_floating_point) && (!treat_as_floating_point) && - detail::InvokeResultOf, Value, rep> - [[nodiscard]] friend constexpr Quantity auto operator%(const Value& v, const quantity& q) - { - gsl_ExpectsAudit(q.number() != quantity_values::zero()); - return make_quantity(v % q.number()); - } - - template - requires(!Quantity) && (dimension == dimension_one) && std::equality_comparable_with - [[nodiscard]] friend constexpr bool operator==(const quantity& q, const Value& v) - { - return q == make_quantity<::mp_units::one>(v); - } - - template - requires(!Quantity) && (dimension == dimension_one) && std::three_way_comparable_with - [[nodiscard]] friend constexpr auto operator<=>(const quantity& q, const Value& v) - { - return q <=> make_quantity<::mp_units::one>(v); - } - private: template requires RepresentationOf, get_quantity_spec(R2).character> @@ -489,6 +333,157 @@ private: template explicit quantity(Q) -> quantity::reference, typename quantity_like_traits::rep>; +template + requires detail::InvocableQuantities, quantity, quantity> +[[nodiscard]] constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) +{ + using ret = detail::common_quantity_for, quantity, quantity>; + return make_quantity(ret(lhs).number() + ret(rhs).number()); +} + +template + requires detail::InvocableQuantities, quantity, quantity> +[[nodiscard]] constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) +{ + using ret = detail::common_quantity_for, quantity, quantity>; + return make_quantity(ret(lhs).number() - ret(rhs).number()); +} + +template + requires detail::InvokeResultOf<(get_quantity_spec(R1) * get_quantity_spec(R2)).character, std::multiplies<>, Rep1, + Rep2> +[[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) +{ + return make_quantity(lhs.number() * rhs.number()); +} + +template + requires(!Quantity) && + detail::InvokeResultOf, Rep, const Value&> +[[nodiscard]] constexpr Quantity auto operator*(const quantity& q, const Value& v) +{ + return make_quantity(q.number() * v); +} + +template + requires(!Quantity) && + detail::InvokeResultOf, const Value&, Rep> +[[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity& q) +{ + return make_quantity(v * q.number()); +} + +template + requires detail::InvokeResultOf<(get_quantity_spec(R1) / get_quantity_spec(R2)).character, std::divides<>, Rep1, Rep2> +[[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) +{ + gsl_ExpectsAudit(rhs.number() != quantity_values::zero()); + return make_quantity(lhs.number() / rhs.number()); +} + +template + requires(!Quantity) && + detail::InvokeResultOf, Rep, const Value&> +[[nodiscard]] constexpr Quantity auto operator/(const quantity& q, const Value& v) +{ + gsl_ExpectsAudit(v != quantity_values::zero()); + return make_quantity(q.number() / v); +} + +template + requires(!Quantity) && + detail::InvokeResultOf, const Value&, Rep> +[[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity& q) +{ + return make_quantity<::mp_units::one / R>(v / q.number()); +} + +template + requires(!treat_as_floating_point) && (!treat_as_floating_point) && + detail::InvocableQuantities, quantity, quantity> +[[nodiscard]] constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs) +{ + gsl_ExpectsAudit(rhs.number() != quantity_values::zero()); + using ret = detail::common_quantity_for, quantity, quantity>; + return make_quantity(ret(lhs).number() % ret(rhs).number()); +} + +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>; + return ct(lhs).number() == ct(rhs).number(); +} + +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>; + return ct(lhs).number() <=> ct(rhs).number(); +} + +template + requires(!Quantity) && (quantity::dimension == dimension_one) && + detail::InvokeResultOf, Rep, Value> +[[nodiscard]] constexpr Quantity auto operator+(const quantity& q, const Value& v) +{ + return q + make_quantity<::mp_units::one>(v); +} + +template + requires(!Quantity) && (quantity::dimension == dimension_one) && + detail::InvokeResultOf, Value, Rep> +[[nodiscard]] constexpr Quantity auto operator+(const Value& v, const quantity& q) +{ + return make_quantity<::mp_units::one>(v) + q; +} + +template + requires(!Quantity) && (quantity::dimension == dimension_one) && + detail::InvokeResultOf, Rep, Value> +[[nodiscard]] constexpr Quantity auto operator-(const quantity& q, const Value& v) +{ + return q - make_quantity<::mp_units::one>(v); +} + +template + requires(!Quantity) && (quantity::dimension == dimension_one) && + detail::InvokeResultOf, Value, Rep> +[[nodiscard]] constexpr Quantity auto operator-(const Value& v, const quantity& q) +{ + return make_quantity<::mp_units::one>(v) - q; +} + +template + requires(!Quantity) && (quantity::dimension == dimension_one) && (get_unit(R) == ::mp_units::one) && + (!treat_as_floating_point) && (!treat_as_floating_point) && + detail::InvokeResultOf, Value, Rep> +[[nodiscard]] constexpr Quantity auto operator%(const Value& v, const quantity& q) +{ + gsl_ExpectsAudit(q.number() != quantity_values::zero()); + return make_quantity(v % q.number()); +} + +template + requires(!Quantity) && + (quantity::dimension == dimension_one) && std::equality_comparable_with +[[nodiscard]] constexpr bool operator==(const quantity& q, const Value& v) +{ + return q == make_quantity<::mp_units::one>(v); +} + +template + requires(!Quantity) && + (quantity::dimension == dimension_one) && std::three_way_comparable_with +[[nodiscard]] constexpr auto operator<=>(const quantity& q, const Value& v) +{ + return q <=> make_quantity<::mp_units::one>(v); +} + template requires RepresentationOf, get_quantity_spec(R).character> [[nodiscard]] constexpr quantity> make_quantity(Rep&& v)