diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index c73652cf..63e89b47 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -132,9 +132,6 @@ concept CommonlyInvocableQuantities = template using quantity_like_type = quantity::reference, typename quantity_like_traits::rep>; -template> -concept Mutable = (!std::is_const_v) && std::derived_from; - } // namespace detail MP_UNITS_EXPORT_BEGIN @@ -352,14 +349,13 @@ public: return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference}; } - template Q> - friend constexpr decltype(auto) operator++(Q&& q) + constexpr quantity& operator++() & requires requires(rep& v) { { ++v } -> std::same_as; } { - ++q.numerical_value_is_an_implementation_detail_; - return std::forward(q); + ++numerical_value_is_an_implementation_detail_; + return *this; } [[nodiscard]] constexpr QuantityOf auto operator++(int) @@ -370,14 +366,13 @@ public: return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference}; } - template Q> - friend constexpr decltype(auto) operator--(Q&& q) + constexpr quantity& operator--() & requires requires(rep& v) { { --v } -> std::same_as; } { - --q.numerical_value_is_an_implementation_detail_; - return std::forward(q); + --numerical_value_is_an_implementation_detail_; + return *this; } [[nodiscard]] constexpr QuantityOf auto operator--(int) @@ -389,87 +384,86 @@ public: } // compound assignment operators - template Q, auto R2, typename Rep2> + template requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) && detail::ValuePreservingScaling2Reps && requires(rep& a, const Rep2 b) { { a += b } -> std::same_as; } - friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs) + constexpr quantity& operator+=(const quantity& other) & { if constexpr (equivalent(unit, get_unit(R2))) - lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_; + numerical_value_is_an_implementation_detail_ += other.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); + numerical_value_is_an_implementation_detail_ += other.in(unit).numerical_value_is_an_implementation_detail_; + return *this; } - template Q, auto R2, typename Rep2> + template requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) && detail::ValuePreservingScaling2Reps && requires(rep& a, const Rep2 b) { { a -= b } -> std::same_as; } - friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs) + constexpr quantity& operator-=(const quantity& other) & { if constexpr (equivalent(unit, get_unit(R2))) - lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_; + numerical_value_is_an_implementation_detail_ -= other.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); + numerical_value_is_an_implementation_detail_ -= other.in(unit).numerical_value_is_an_implementation_detail_; + return *this; } - template Q, auto R2, typename Rep2> + template requires(!treat_as_floating_point) && (implicitly_convertible(get_quantity_spec(R2), quantity_spec)) && detail::ValuePreservingScaling2Reps && requires(rep& a, const Rep2 b) { { a %= b } -> std::same_as; } - friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs) - + constexpr quantity& operator%=(const quantity& other) & { - MP_UNITS_EXPECTS_DEBUG(is_neq_zero(rhs)); + MP_UNITS_EXPECTS_DEBUG(is_neq_zero(other)); if constexpr (equivalent(unit, get_unit(R2))) - lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_; + numerical_value_is_an_implementation_detail_ %= other.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); + numerical_value_is_an_implementation_detail_ %= other.in(unit).numerical_value_is_an_implementation_detail_; + return *this; } - template Q, detail::ScalarValuePreservingTo Value> + template Value> requires requires(rep& a, const Value b) { { a *= b } -> std::same_as; } - friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& val) + constexpr quantity& operator*=(const Value& val) & { - lhs.numerical_value_is_an_implementation_detail_ *= val; - return std::forward(lhs); + numerical_value_is_an_implementation_detail_ *= val; + return *this; } - template Q1, detail::NumberLikeQuantity Q2> + template requires detail::ScalarValuePreservingTo && requires(rep& a, const Q2::rep b) { { a *= b } -> std::same_as; } - friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs) + constexpr quantity& operator*=(const Q2& other) & { - return std::forward(lhs) *= rhs.numerical_value_is_an_implementation_detail_; + return *this *= other.numerical_value_is_an_implementation_detail_; } - template Q, detail::ScalarValuePreservingTo Value> + template Value> requires requires(rep& a, const Value b) { { a /= b } -> std::same_as; } - friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& val) + constexpr quantity& operator/=(const Value& val) & { MP_UNITS_EXPECTS_DEBUG(val != representation_values::zero()); - lhs.numerical_value_is_an_implementation_detail_ /= val; - return std::forward(lhs); + numerical_value_is_an_implementation_detail_ /= val; + return *this; } - template Q1, detail::NumberLikeQuantity Q2> + template requires detail::ScalarValuePreservingTo && requires(rep& a, const Q2::rep b) { { a /= b } -> std::same_as; } - friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs) + constexpr quantity& operator/=(const Q2& rhs) & { - return std::forward(lhs) /= rhs.numerical_value_is_an_implementation_detail_; + return *this /= rhs.numerical_value_is_an_implementation_detail_; } // 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 6586d883..dd535a7b 100644 --- a/src/core/include/mp-units/framework/quantity_point.h +++ b/src/core/include/mp-units/framework/quantity_point.h @@ -411,12 +411,11 @@ public: } // member unary operators - template QP> - friend constexpr decltype(auto) operator++(QP&& qp) - requires requires { ++qp.quantity_from_origin_is_an_implementation_detail_; } + constexpr quantity_point& operator++() & + requires requires { ++quantity_from_origin_is_an_implementation_detail_; } { - ++qp.quantity_from_origin_is_an_implementation_detail_; - return std::forward(qp); + ++quantity_from_origin_is_an_implementation_detail_; + return *this; } [[nodiscard]] constexpr quantity_point operator++(int) @@ -425,12 +424,11 @@ public: return {quantity_from_origin_is_an_implementation_detail_++, PO}; } - template QP> - friend constexpr decltype(auto) operator--(QP&& qp) - requires requires { --qp.quantity_from_origin_is_an_implementation_detail_; } + constexpr quantity_point& operator--() & + requires requires { --quantity_from_origin_is_an_implementation_detail_; } { - --qp.quantity_from_origin_is_an_implementation_detail_; - return std::forward(qp); + --quantity_from_origin_is_an_implementation_detail_; + return *this; } [[nodiscard]] constexpr quantity_point operator--(int) @@ -440,24 +438,24 @@ public: } // compound assignment operators - template QP, auto R2, typename Rep2> + template requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) && detail::ValuePreservingScaling2Reps && requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; } - friend constexpr decltype(auto) operator+=(QP&& qp, const quantity& q) + constexpr quantity_point& operator+=(const quantity& q) & { - qp.quantity_from_origin_is_an_implementation_detail_ += q; - return std::forward(qp); + quantity_from_origin_is_an_implementation_detail_ += q; + return *this; } - template QP, auto R2, typename Rep2> + template requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) && detail::ValuePreservingScaling2Reps && requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; } - friend constexpr decltype(auto) operator-=(QP&& qp, const quantity& q) + constexpr quantity_point& operator-=(const quantity& q) & { - qp.quantity_from_origin_is_an_implementation_detail_ -= q; - return std::forward(qp); + quantity_from_origin_is_an_implementation_detail_ -= q; + return *this; } // binary operators on quantity points diff --git a/test/static/chrono_test.cpp b/test/static/chrono_test.cpp index 409833bd..b2a178da 100644 --- a/test/static/chrono_test.cpp +++ b/test/static/chrono_test.cpp @@ -137,8 +137,8 @@ static_assert(std::chrono::nanoseconds(quantity{1 * ns}) == 1ns); static_assert(std::chrono::nanoseconds(quantity{1 * s}) == 1s); // operators -static_assert((1 * s += quantity{1s}) == 2 * s); -static_assert((2 * s -= quantity{1s}) == 1 * s); +static_assert([q = 1 * s]() mutable { return q += quantity{1s}; }() == 2 * s); +static_assert([q = 2 * s]() mutable { return q -= quantity{1s}; }() == 1 * s); static_assert(quantity{1s} + 1 * s == 2 * s); static_assert(quantity{1s} + 1 * min == 61 * s); static_assert(1 * s + quantity{1s} == 2 * s); diff --git a/test/static/quantity_point_test.cpp b/test/static/quantity_point_test.cpp index ba5b47aa..67fc8e80 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -1007,14 +1007,24 @@ static_assert([](auto v) { //////////////////////// // same type -static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_zero().numerical_value_in(m) == 2); -static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_zero().numerical_value_in(m) == 1); +static_assert( + [qp = mean_sea_level + 1 * m]() mutable { return qp += 1 * m; }().quantity_from_zero().numerical_value_in(m) == 2); +static_assert( + [qp = mean_sea_level + 2 * m]() mutable { return qp -= 1 * m; }().quantity_from_zero().numerical_value_in(m) == 1); // different types -static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_zero().numerical_value_in(m) == 5.5); -static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_zero().numerical_value_in(m) == 1123); -static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_zero().numerical_value_in(m) == 2.5); -static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_zero().numerical_value_in(m) == 123); +static_assert( + [qp = mean_sea_level + 2.5 * m]() mutable { return qp += 3 * m; }().quantity_from_zero().numerical_value_in(m) == + 5.5); +static_assert( + [qp = mean_sea_level + 123 * m]() mutable { return qp += 1 * km; }().quantity_from_zero().numerical_value_in(m) == + 1123); +static_assert( + [qp = mean_sea_level + 5.5 * m]() mutable { return qp -= 3 * m; }().quantity_from_zero().numerical_value_in(m) == + 2.5); +static_assert( + [qp = mean_sea_level + 1123 * m]() mutable { return qp -= 1 * km; }().quantity_from_zero().numerical_value_in(m) == + 123); template typename QP> diff --git a/test/static/quantity_test.cpp b/test/static/quantity_test.cpp index 5a41d0dc..8b31a0c4 100644 --- a/test/static/quantity_test.cpp +++ b/test/static/quantity_test.cpp @@ -534,73 +534,81 @@ static_assert(is_same_v) //////////////////////// // same type -static_assert((1 * m += 1 * m).numerical_value_in(m) == 2); -static_assert((2 * m -= 1 * m).numerical_value_in(m) == 1); -static_assert((1 * m *= 2).numerical_value_in(m) == 2); -static_assert((2 * m /= 2).numerical_value_in(m) == 1); -static_assert((1 * m *= 2 * one).numerical_value_in(m) == 2); -static_assert((2 * m /= 2 * one).numerical_value_in(m) == 1); -static_assert((7 * m %= 2 * m).numerical_value_in(m) == 1); +static_assert([q = 1 * m]() mutable { return q += 1 * m; }().numerical_value_in(m) == 2); +static_assert([q = 2 * m]() mutable { return q -= 1 * m; }().numerical_value_in(m) == 1); +static_assert([q = 1 * m]() mutable { return q *= 2; }().numerical_value_in(m) == 2); +static_assert([q = 2 * m]() mutable { return q /= 2; }().numerical_value_in(m) == 1); +static_assert([q = 1 * m]() mutable { return q *= 2 * one; }().numerical_value_in(m) == 2); +static_assert([q = 2 * m]() mutable { return q /= 2 * one; }().numerical_value_in(m) == 1); +static_assert([q = 7 * m]() mutable { return q %= 2 * m; }().numerical_value_in(m) == 1); #if MP_UNITS_HOSTED -static_assert(((1. + 1i) * V += (1. + 1i) * V).numerical_value_in(V) == 2. + 2i); -static_assert(((2. + 2i) * V -= (1. + 1i) * V).numerical_value_in(V) == 1. + 1i); -static_assert(((1. + 1i) * V += 1. * V).numerical_value_in(V) == 2. + 1i); -static_assert(((2. + 2i) * V -= 1. * V).numerical_value_in(V) == 1. + 2i); -static_assert(((1. + 1i) * V *= 2.).numerical_value_in(V) == 2. + 2i); -static_assert(((2. + 2i) * V /= 2.).numerical_value_in(V) == 1. + 1i); -static_assert(((1. + 1i) * V *= 2. * one).numerical_value_in(V) == 2. + 2i); -static_assert(((2. + 2i) * V /= 2. * one).numerical_value_in(V) == 1. + 1i); -static_assert(((1. + 1i) * V *= 2. + 1i).numerical_value_in(V) == (1. + 1i) * (2. + 1i)); -static_assert(((2. + 2i) * V /= 2. + 1i).numerical_value_in(V) == (2. + 2i) / (2. + 1i)); -static_assert(((1. + 1i) * V *= (2. + 1i) * one).numerical_value_in(V) == (1. + 1i) * (2. + 1i)); -static_assert(((2. + 2i) * V /= (2. + 1i) * one).numerical_value_in(V) == (2. + 2i) / (2. + 1i)); +static_assert([q = (1. + 1i) * V]() mutable { return q += (1. + 1i) * V; }().numerical_value_in(V) == 2. + 2i); +static_assert([q = (2. + 2i) * V]() mutable { return q -= (1. + 1i) * V; }().numerical_value_in(V) == 1. + 1i); +static_assert([q = (1. + 1i) * V]() mutable { return q += 1. * V; }().numerical_value_in(V) == 2. + 1i); +static_assert([q = (2. + 2i) * V]() mutable { return q -= 1. * V; }().numerical_value_in(V) == 1. + 2i); +static_assert([q = (1. + 1i) * V]() mutable { return q *= 2.; }().numerical_value_in(V) == 2. + 2i); +static_assert([q = (2. + 2i) * V]() mutable { return q /= 2.; }().numerical_value_in(V) == 1. + 1i); +static_assert([q = (1. + 1i) * V]() mutable { return q *= 2. * one; }().numerical_value_in(V) == 2. + 2i); +static_assert([q = (2. + 2i) * V]() mutable { return q /= 2. * one; }().numerical_value_in(V) == 1. + 1i); +static_assert([q = (1. + 1i) * V]() mutable { return q *= (2. + 1i) * one; }().numerical_value_in(V) == + (1. + 1i) * (2. + 1i)); +static_assert([q = (2. + 2i) * V]() mutable { return q /= (2. + 1i) * one; }().numerical_value_in(V) == + (2. + 2i) / (2. + 1i)); -static_assert((v{1., 2., 3.}* m += v{1., 2., 3.} * m).numerical_value_in(m) == v{2., 4., 6.}); -static_assert((v{2., 4., 6.}* m -= v{1., 2., 3.} * m).numerical_value_in(m) == v{1., 2., 3.}); -static_assert((v{1., 2., 3.}* m *= 2.).numerical_value_in(m) == v{2., 4., 6.}); -static_assert((v{2., 4., 6.}* m /= 2.).numerical_value_in(m) == v{1., 2., 3.}); -static_assert((v{1., 2., 3.}* m *= 2. * one).numerical_value_in(m) == v{2., 4., 6.}); -static_assert((v{2., 4., 6.}* m /= 2. * one).numerical_value_in(m) == v{1., 2., 3.}); +static_assert([q = v{1., 2., 3.} * m]() mutable { return q += v{1., 2., 3.} * m; }().numerical_value_in(m) == + v{2., 4., 6.}); +static_assert([q = v{2., 4., 6.} * m]() mutable { return q -= v{1., 2., 3.} * m; }().numerical_value_in(m) == + v{1., 2., 3.}); +static_assert([q = v{1., 2., 3.} * m]() mutable { return q *= 2.; }().numerical_value_in(m) == v{2., 4., 6.}); +static_assert([q = v{2., 4., 6.} * m]() mutable { return q /= 2.; }().numerical_value_in(m) == v{1., 2., 3.}); +static_assert([q = v{1., 2., 3.} * m]() mutable { return q *= 2. * one; }().numerical_value_in(m) == v{2., 4., 6.}); +static_assert([q = v{2., 4., 6.} * m]() mutable { return q /= 2. * one; }().numerical_value_in(m) == v{1., 2., 3.}); #endif // different representation types -static_assert((2.5 * m += 3 * m).numerical_value_in(m) == 5.5); -static_assert((5.5 * m -= 3 * m).numerical_value_in(m) == 2.5); -static_assert((2.5 * m *= 3).numerical_value_in(m) == 7.5); -static_assert((7.5 * m /= 3).numerical_value_in(m) == 2.5); -static_assert((2.5 * m *= 3 * one).numerical_value_in(m) == 7.5); -static_assert((7.5 * m /= 3 * one).numerical_value_in(m) == 2.5); +static_assert([q = 2.5 * m]() mutable { return q += 3 * m; }().numerical_value_in(m) == 5.5); +static_assert([q = 5.5 * m]() mutable { return q -= 3 * m; }().numerical_value_in(m) == 2.5); +static_assert([q = 2.5 * m]() mutable { return q *= 3; }().numerical_value_in(m) == 7.5); +static_assert([q = 7.5 * m]() mutable { return q /= 3; }().numerical_value_in(m) == 2.5); +static_assert([q = 2.5 * m]() mutable { return q *= 3 * one; }().numerical_value_in(m) == 7.5); +static_assert([q = 7.5 * m]() mutable { return q /= 3 * one; }().numerical_value_in(m) == 2.5); // different units -static_assert((1 * m += 1 * km).numerical_value_in(m) == 1001); -static_assert((2000 * m -= 1 * km).numerical_value_in(m) == 1000); -static_assert((3500 * m %= 1 * km).numerical_value_in(m) == 500); +static_assert([q = 1 * m]() mutable { return q += 1 * km; }().numerical_value_in(m) == 1001); +static_assert([q = 2000 * m]() mutable { return q -= 1 * km; }().numerical_value_in(m) == 1000); +static_assert([q = 3500 * m]() mutable { return q %= 1 * km; }().numerical_value_in(m) == 500); #if MP_UNITS_HOSTED -static_assert(((1000. + 1000i) * V += (1. + 1i) * kV).numerical_value_in(V) == 2000. + 2000i); -static_assert(((2000. + 2000i) * V -= (1. + 1i) * kV).numerical_value_in(V) == 1000. + 1000i); -static_assert((v{1000., 2000., 3000.}* m += v{1., 2., 3.} * km).numerical_value_in(m) == v{2000., 4000., 6000.}); -static_assert((v{2000., 4000., 6000.}* m -= v{1., 2., 3.} * km).numerical_value_in(m) == v{1000., 2000., 3000.}); +static_assert([q = (1000. + 1000i) * V]() mutable { return q += (1. + 1i) * kV; }().numerical_value_in(V) == + 2000. + 2000i); +static_assert([q = (2000. + 2000i) * V]() mutable { return q -= (1. + 1i) * kV; }().numerical_value_in(V) == + 1000. + 1000i); +static_assert([q = (v{1000., 2000., 3000.} * m)]() mutable { return q += v{1., 2., 3.} * km; }().numerical_value_in( + m) == v{2000., 4000., 6000.}); +static_assert([q = (v{2000., 4000., 6000.} * m)]() mutable { return q -= v{1., 2., 3.} * km; }().numerical_value_in( + m) == v{1000., 2000., 3000.}); #endif // convertible quantity types -static_assert((isq::length(1 * m) += isq::height(1 * m)).numerical_value_in(m) == 2); -static_assert((isq::length(2 * m) -= isq::height(1 * m)).numerical_value_in(m) == 1); -static_assert((isq::length(7 * m) %= isq::height(2 * m)).numerical_value_in(m) == 1); +static_assert([q = isq::length(1 * m)]() mutable { return q += isq::height(1 * m); }().numerical_value_in(m) == 2); +static_assert([q = isq::length(2 * m)]() mutable { return q -= isq::height(1 * m); }().numerical_value_in(m) == 1); +static_assert([q = isq::length(7 * m)]() mutable { return q %= isq::height(2 * m); }().numerical_value_in(m) == 1); -// static_assert((std::uint8_t{255} * m %= 256 * m).numerical_value_in(m) == [] { -// std::uint8_t ui(255); -// return ui %= 256; -// }()); // UB -static_assert((std::uint8_t{255}* m %= 257 * m).numerical_value_in(m) == [] { - std::uint8_t ui(255); - return ui %= 257; -}()); +static_assert([q = std::uint8_t{255} * m]() mutable { return q %= 256 * m; }().numerical_value_in(m) == + [] { + std::uint8_t ui(255); + return ui %= 256; + }()); +static_assert([q = std::uint8_t{255} * m]() mutable { return q %= 257 * m; }().numerical_value_in(m) == + [] { + std::uint8_t ui(255); + return ui %= 257; + }()); // lack of consistency with binary operator static_assert( is_of_type<1 * (isq::length / isq::time)[m / s] + 1 * isq::speed[m / s], quantity>); -static_assert(is_of_type<(1 * (isq::length / isq::time)[m / s] += 1 * isq::speed[m / s]), +static_assert(is_of_type<[q = 1 * (isq::length / isq::time)[m / s]]() mutable { return q += 1 * isq::speed[m / s]; }(), quantity<(isq::length / isq::time)[m / s], int>>); template typename Q> @@ -990,8 +998,8 @@ static_assert(1 * si::si2019::speed_of_light_in_vacuum + 10 * isq::speed[m / s] [[maybe_unused]] constexpr quantity speed = 120 * isq::length[km] / (2 * isq::time[h]); // dimensionless -static_assert((3 * one *= 2 * one) == 6 * one); -static_assert((6 * one /= 2 * one) == 3 * one); +static_assert([q = 3 * one]() mutable { return q *= 2 * one; }() == 6 * one); +static_assert([q = 6 * one]() mutable { return q /= 2 * one; }() == 3 * one); static_assert(1 * one + 1 * one == 2 * one); static_assert(2 * one - 1 * one == 1 * one); static_assert(2 * one * (2 * one) == 4 * one); @@ -1003,8 +1011,8 @@ static_assert(4 * one / 2 == 2 * one); static_assert(4 * one % (2 * one) == 0 * one); #if MP_UNITS_HOSTED -static_assert(((3. + 3i) * one *= (2. + 2i) * one) == (3. + 3i) * (2. + 2i) * one); -static_assert(((6. + 6i) * one /= (2. + 2i) * one) == (6. + 6i) / (2. + 2i) * one); +static_assert([q = (3. + 3i) * one]() mutable { return q *= (2. + 2i) * one; }() == (3. + 3i) * (2. + 2i) * one); +static_assert([q = (6. + 6i) * one]() mutable { return q /= (2. + 2i) * one; }() == (6. + 6i) / (2. + 2i) * one); static_assert((1. + 1i) * one + (1. + 1i) * one == (2. + 2i) * one); static_assert((2. + 2i) * one - (1. + 1i) * one == (1. + 1i) * one); static_assert((2. + 2i) * one * (2. * one) == (4. + 4i) * one);