From a7711cb3017277725f075050e40956f1566b7ac8 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 27 Aug 2023 20:19:26 +0200 Subject: [PATCH 01/22] refactor: `quantity::value()` refactored to `quantity::value_ref_in(U)` --- example/conversion_factor.cpp | 6 +- example/currency.cpp | 8 +- src/core-fmt/include/mp-units/format.h | 5 +- src/core-io/include/mp-units/ostream.h | 6 +- .../include/mp-units/bits/quantity_cast.h | 4 +- src/core/include/mp-units/bits/sudo_cast.h | 13 +- src/core/include/mp-units/quantity.h | 76 ++++-- src/core/include/mp-units/quantity_spec.h | 9 +- src/utility/include/mp-units/chrono.h | 2 +- src/utility/include/mp-units/math.h | 130 +++++---- src/utility/include/mp-units/random.h | 41 ++- test/unit_test/runtime/almost_equals.h | 4 +- test/unit_test/runtime/distribution_test.cpp | 16 +- .../unit_test/runtime/linear_algebra_test.cpp | 76 +++--- test/unit_test/runtime/math_test.cpp | 5 +- test/unit_test/static/quantity_point_test.cpp | 153 +++++------ test/unit_test/static/quantity_test.cpp | 249 +++++++++--------- 17 files changed, 451 insertions(+), 352 deletions(-) diff --git a/example/conversion_factor.cpp b/example/conversion_factor.cpp index a3b810512..cd9a4cfbc 100644 --- a/example/conversion_factor.cpp +++ b/example/conversion_factor.cpp @@ -33,7 +33,7 @@ template requires std::constructible_from inline constexpr double conversion_factor(Target, Source) { - return mp_units::value_cast(1. * Source::reference).numerical_value(); + return mp_units::value_cast(1. * Source::reference).numerical_value_ref_in(Target::unit); } } // namespace @@ -56,6 +56,8 @@ int main() std::cout << MP_UNITS_STD_FMT::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n", lengthA, lengthB) << MP_UNITS_STD_FMT::format("lengthB.value( {} ) == lengthA.value( {} ) * conversion_factor( {} )\n", - lengthB.numerical_value(), lengthA.numerical_value(), + lengthB.numerical_value_ref_in(lengthB.unit), + lengthA.numerical_value_ref_in(lengthA.unit), + conversion_factor(lengthB, lengthA)); } diff --git a/example/currency.cpp b/example/currency.cpp index 587f1f7da..bb5d9b393 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -81,9 +81,11 @@ quantity exchange_to(quantity q) template auto To, ReferenceOf auto From, auto PO, typename Rep> quantity_point exchange_to(quantity_point q) { - return quantity_point{ - zero + - static_cast(exchange_rate() * (q - q.absolute_point_origin).numerical_value()) * To}; + return quantity_point{zero + + + static_cast(exchange_rate() * + (q - q.absolute_point_origin).numerical_value_ref_in(q.unit)) * + To}; } int main() diff --git a/src/core-fmt/include/mp-units/format.h b/src/core-fmt/include/mp-units/format.h index 4b0a3ec4c..510584d90 100644 --- a/src/core-fmt/include/mp-units/format.h +++ b/src/core-fmt/include/mp-units/format.h @@ -226,7 +226,7 @@ struct quantity_formatter { explicit quantity_formatter(OutputIt o, quantity q, const quantity_format_specs& fspecs, Locale lc) : - out(o), val(std::move(q).numerical_value()), specs(fspecs), loc(std::move(lc)) + out(o), val(std::move(q).numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc)) { } @@ -396,7 +396,8 @@ struct MP_UNITS_STD_FMT::formatter, CharT> { if (begin == end || *begin == '}') { // default format should print value followed by the unit separated with 1 space - out = mp_units::detail::format_units_quantity_value(out, q.numerical_value(), specs.rep, ctx.locale()); + out = mp_units::detail::format_units_quantity_value(out, q.numerical_value_ref_in(q.unit), specs.rep, + ctx.locale()); if constexpr (mp_units::detail::has_unit_symbol(get_unit(Reference))) { if constexpr (mp_units::space_before_unit_symbol) *out++ = CharT(' '); out = unit_symbol_to(out, get_unit(Reference)); diff --git a/src/core-io/include/mp-units/ostream.h b/src/core-io/include/mp-units/ostream.h index 5fc8489c1..c648a8100 100644 --- a/src/core-io/include/mp-units/ostream.h +++ b/src/core-io/include/mp-units/ostream.h @@ -36,9 +36,9 @@ void to_stream(std::basic_ostream& os, const quantity& q) { if constexpr (is_same_v || is_same_v) // promote the value to int - os << +q.numerical_value(); + os << +q.numerical_value_ref_in(q.unit); else - os << q.numerical_value(); + os << q.numerical_value_ref_in(q.unit); if constexpr (has_unit_symbol(get_unit(R))) { if constexpr (space_before_unit_symbol) os << " "; unit_symbol_to(std::ostream_iterator(os), get_unit(R)); @@ -49,7 +49,7 @@ void to_stream(std::basic_ostream& os, const quantity& q) template std::basic_ostream& operator<<(std::basic_ostream& os, const quantity& q) - requires requires { os << q.numerical_value(); } + requires requires { os << q.numerical_value_ref_in(q.unit); } { if (os.width()) { // std::setw() applies to the whole quantity output so it has to be first put into std::string diff --git a/src/core/include/mp-units/bits/quantity_cast.h b/src/core/include/mp-units/bits/quantity_cast.h index fea62a498..fe88b85a5 100644 --- a/src/core/include/mp-units/bits/quantity_cast.h +++ b/src/core/include/mp-units/bits/quantity_cast.h @@ -51,9 +51,9 @@ template { if constexpr (detail::QuantityKindSpec> && AssociatedUnit>) - return make_quantity(std::forward(q).numerical_value()); + return make_quantity(std::forward(q).numerical_value_ref_in(q.unit)); else - return make_quantity{}>(std::forward(q).numerical_value()); + return make_quantity{}>(std::forward(q).numerical_value_ref_in(q.unit)); } } // namespace mp_units diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index e8a2c1f02..75b53dc9e 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -63,10 +63,10 @@ template if constexpr (q_unit == To::unit) { // no scaling of the number needed return make_quantity(static_cast( - std::forward(q).numerical_value())); // this is the only (and recommended) way to do - // a truncating conversion on a number, so we are - // using static_cast to suppress all the compiler - // warnings on conversions + std::forward(q).numerical_value_ref_in(q_unit))); // this is the only (and recommended) way to do + // a truncating conversion on a number, so we are + // using static_cast to suppress all the compiler + // warnings on conversions } else { // scale the number constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag; @@ -78,8 +78,9 @@ template using multiplier_type = conditional, std::common_type_t, c_mag_type>; constexpr auto val = [](Magnitude auto m) { return get_value(m); }; - return static_cast(static_cast(std::forward(q).numerical_value()) * - val(num) / val(den) * val(irr)) * + return static_cast( + static_cast(std::forward(q).numerical_value_ref_in(q_unit)) * val(num) / val(den) * + val(irr)) * To::reference; } } diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 674f44c77..81600158b 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -126,7 +126,7 @@ class quantity { template Q> constexpr explicit(!std::convertible_to) quantity(const Q& q) : - value_(detail::sudo_cast(q).numerical_value()) + value_(detail::sudo_cast(q).numerical_value_ref_in(unit)) { } @@ -143,23 +143,44 @@ class quantity { // data access #ifdef __cpp_explicit_this_parameter - template - [[nodiscard]] constexpr auto&& value(this Self&& self) noexcept + template + requires(U{} == unit) + [[nodiscard]] constexpr auto&& value_ref_in(this Self&& self, U) noexcept { return std::forward(self).value_; } #else - [[nodiscard]] constexpr rep& numerical_value() & noexcept { return value_; } - [[nodiscard]] constexpr const rep& numerical_value() const& noexcept { return value_; } - [[nodiscard]] constexpr rep&& numerical_value() && noexcept { return std::move(value_); } - [[nodiscard]] constexpr const rep&& numerical_value() const&& noexcept { return std::move(value_); } + template + requires(U{} == unit) + [[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept + { + return value_; + } + template + requires(U{} == unit) + [[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept + { + return value_; + } + template + requires(U{} == unit) + [[nodiscard]] constexpr rep&& numerical_value_ref_in(U) && noexcept + { + return std::move(value_); + } + template + requires(U{} == unit) + [[nodiscard]] constexpr const rep&& numerical_value_ref_in(U) const&& noexcept + { + return std::move(value_); + } #endif template requires requires(quantity q) { q.in(U{}); } [[nodiscard]] constexpr rep numerical_value_in(U) const noexcept { - return (*this).in(U{}).numerical_value(); + return (*this).in(U{}).numerical_value_ref_in(U{}); } template @@ -177,7 +198,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(+numerical_value()); + return make_quantity(+numerical_value_ref_in(unit)); } [[nodiscard]] constexpr Quantity auto operator-() const @@ -187,7 +208,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(-numerical_value()); + return make_quantity(-numerical_value_ref_in(unit)); } constexpr quantity& operator++() @@ -240,7 +261,7 @@ class quantity { } -> std::same_as; } { - value_ += q.numerical_value(); + value_ += q.numerical_value_ref_in(unit); return *this; } @@ -251,7 +272,7 @@ class quantity { } -> std::same_as; } { - value_ -= q.numerical_value(); + value_ -= q.numerical_value_ref_in(unit); return *this; } @@ -263,7 +284,7 @@ class quantity { } { gsl_ExpectsAudit(q != zero()); - value_ %= q.numerical_value(); + value_ %= q.numerical_value_ref_in(unit); return *this; } @@ -287,7 +308,7 @@ class quantity { } constexpr quantity& operator*=(const Q& rhs) { - value_ *= rhs.numerical_value(); + value_ *= rhs.numerical_value_ref_in(::mp_units::one); return *this; } @@ -313,7 +334,7 @@ class quantity { constexpr quantity& operator/=(const Q& rhs) { gsl_ExpectsAudit(rhs != rhs.zero()); - value_ /= rhs.numerical_value(); + value_ /= rhs.numerical_value_ref_in(::mp_units::one); return *this; } @@ -342,7 +363,8 @@ template [[nodiscard]] constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) { using ret = detail::common_quantity_for, quantity, quantity>; - return make_quantity(ret(lhs).numerical_value() + ret(rhs).numerical_value()); + return make_quantity(ret(lhs).numerical_value_ref_in(ret::unit) + + ret(rhs).numerical_value_ref_in(ret::unit)); } template @@ -350,7 +372,8 @@ template [[nodiscard]] constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) { using ret = detail::common_quantity_for, quantity, quantity>; - return make_quantity(ret(lhs).numerical_value() - ret(rhs).numerical_value()); + return make_quantity(ret(lhs).numerical_value_ref_in(ret::unit) - + ret(rhs).numerical_value_ref_in(ret::unit)); } template @@ -360,7 +383,8 @@ template { gsl_ExpectsAudit(rhs != rhs.zero()); using ret = detail::common_quantity_for, quantity, quantity>; - return make_quantity(ret(lhs).numerical_value() % ret(rhs).numerical_value()); + return make_quantity(ret(lhs).numerical_value_ref_in(ret::unit) % + ret(rhs).numerical_value_ref_in(ret::unit)); } template @@ -368,7 +392,7 @@ template Rep2> [[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) { - return make_quantity(lhs.numerical_value() * rhs.numerical_value()); + return make_quantity(lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2))); } template @@ -376,7 +400,7 @@ template detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] constexpr Quantity auto operator*(const quantity& q, const Value& v) { - return make_quantity(q.numerical_value() * v); + return make_quantity(q.numerical_value_ref_in(get_unit(R)) * v); } template @@ -384,7 +408,7 @@ template detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity& q) { - return make_quantity(v * q.numerical_value()); + return make_quantity(v * q.numerical_value_ref_in(get_unit(R))); } template @@ -392,7 +416,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) { gsl_ExpectsAudit(rhs != rhs.zero()); - return make_quantity(lhs.numerical_value() / rhs.numerical_value()); + return make_quantity(lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2))); } template @@ -401,7 +425,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& q, const Value& v) { gsl_ExpectsAudit(v != quantity_values::zero()); - return make_quantity(q.numerical_value() / v); + return make_quantity(q.numerical_value_ref_in(get_unit(R)) / v); } template @@ -409,7 +433,7 @@ template 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.numerical_value()); + return make_quantity<::mp_units::one / R>(v / q.numerical_value_ref_in(get_unit(R))); } template @@ -418,7 +442,7 @@ template [[nodiscard]] constexpr bool operator==(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t, quantity>; - return ct(lhs).numerical_value() == ct(rhs).numerical_value(); + return ct(lhs).numerical_value_ref_in(ct::unit) == ct(rhs).numerical_value_ref_in(ct::unit); } template @@ -427,7 +451,7 @@ template [[nodiscard]] constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t, quantity>; - return ct(lhs).numerical_value() <=> ct(rhs).numerical_value(); + return ct(lhs).numerical_value_ref_in(ct::unit) <=> ct(rhs).numerical_value_ref_in(ct::unit); } // make_quantity diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index 0bd2fe95e..b55adf620 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -111,7 +111,8 @@ struct quantity_spec_interface { requires Quantity> && (explicitly_convertible(std::remove_reference_t::quantity_spec, self)) { - return make_quantity::unit>{}>(std::forward(q).numerical_value()); + return make_quantity::unit>{}>( + std::forward(q).numerical_value_ref_in(q.unit)); } #else template U> @@ -128,7 +129,8 @@ struct quantity_spec_interface { (explicitly_convertible(std::remove_reference_t::quantity_spec, Self_{})) [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { - return make_quantity::unit>{}>(std::forward(q).numerical_value()); + return make_quantity::unit>{}>( + std::forward(q).numerical_value_ref_in(q.unit)); } #endif }; @@ -307,7 +309,8 @@ struct quantity_spec : std::remove_const_t { (explicitly_convertible(std::remove_reference_t::quantity_spec, Self_{})) [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { - return make_quantity::unit>{}>(std::forward(q).numerical_value()); + return make_quantity::unit>{}>( + std::forward(q).numerical_value_ref_in(q.unit)); } #endif }; diff --git a/src/utility/include/mp-units/chrono.h b/src/utility/include/mp-units/chrono.h index aca9ad487..f868d84b0 100644 --- a/src/utility/include/mp-units/chrono.h +++ b/src/utility/include/mp-units/chrono.h @@ -92,7 +92,7 @@ template Q> { constexpr auto canonical = detail::get_canonical_unit(Q::unit); constexpr ratio r = as_ratio(canonical.mag); - return std::chrono::duration>{q.numerical_value()}; + return std::chrono::duration>{q.numerical_value_ref_in(Q::unit)}; } template QP> diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index e367ce4b2..00b5aff4e 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -54,7 +54,8 @@ template requires detail::non_zero && requires { quantity_values::one(); } [[nodiscard]] constexpr quantity(R), Rep> pow(const quantity& q) noexcept - requires requires { pow(q.numerical_value(), 1.0); } || requires { std::pow(q.numerical_value(), 1.0); } + requires requires { pow(q.numerical_value_ref_in(q.unit), 1.0); } || + requires { std::pow(q.numerical_value_ref_in(q.unit), 1.0); } { if constexpr (Num == 0) { return quantity(R), Rep>::one(); @@ -63,7 +64,7 @@ template } else { using std::pow; return make_quantity(R)>( - static_cast(pow(q.numerical_value(), static_cast(Num) / static_cast(Den)))); + static_cast(pow(q.numerical_value_ref_in(q.unit), static_cast(Num) / static_cast(Den)))); } } @@ -77,10 +78,11 @@ template */ template [[nodiscard]] constexpr quantity sqrt(const quantity& q) noexcept - requires requires { sqrt(q.numerical_value()); } || requires { std::sqrt(q.numerical_value()); } + requires requires { sqrt(q.numerical_value_ref_in(q.unit)); } || + requires { std::sqrt(q.numerical_value_ref_in(q.unit)); } { using std::sqrt; - return make_quantity(static_cast(sqrt(q.numerical_value()))); + return make_quantity(static_cast(sqrt(q.numerical_value_ref_in(q.unit)))); } /** @@ -93,10 +95,11 @@ template */ template [[nodiscard]] constexpr quantity cbrt(const quantity& q) noexcept - requires requires { cbrt(q.numerical_value()); } || requires { std::cbrt(q.numerical_value()); } + requires requires { cbrt(q.numerical_value_ref_in(q.unit)); } || + requires { std::cbrt(q.numerical_value_ref_in(q.unit)); } { using std::cbrt; - return make_quantity(static_cast(cbrt(q.numerical_value()))); + return make_quantity(static_cast(cbrt(q.numerical_value_ref_in(q.unit)))); } /** @@ -109,11 +112,12 @@ template */ template auto R, typename Rep> [[nodiscard]] constexpr quantity exp(const quantity& q) - requires requires { exp(q.numerical_value()); } || requires { std::exp(q.numerical_value()); } + requires requires { exp(q.numerical_value_ref_in(q.unit)); } || + requires { std::exp(q.numerical_value_ref_in(q.unit)); } { using std::exp; - return value_cast( - make_quantity(R)>(static_cast(exp(value_cast(q).numerical_value())))); + return value_cast(make_quantity(R)>( + static_cast(exp(value_cast(q).numerical_value_ref_in(q.unit))))); } /** @@ -124,10 +128,11 @@ template auto R, typename Rep> */ template [[nodiscard]] constexpr quantity abs(const quantity& q) noexcept - requires requires { abs(q.numerical_value()); } || requires { std::abs(q.numerical_value()); } + requires requires { abs(q.numerical_value_ref_in(q.unit)); } || + requires { std::abs(q.numerical_value_ref_in(q.unit)); } { using std::abs; - return make_quantity(static_cast(abs(q.numerical_value()))); + return make_quantity(static_cast(abs(q.numerical_value_ref_in(q.unit)))); } /** @@ -153,8 +158,9 @@ template */ template [[nodiscard]] constexpr quantity(R), Rep> floor(const quantity& q) noexcept - requires((!treat_as_floating_point) || requires { floor(q.numerical_value()); } || - requires { std::floor(q.numerical_value()); }) && + requires((!treat_as_floating_point) || requires { floor(q.numerical_value_ref_in(q.unit)); } || + + requires { std::floor(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { ::mp_units::value_cast(q); quantity_values::one(); @@ -169,10 +175,11 @@ template if constexpr (treat_as_floating_point) { using std::floor; if constexpr (To == get_unit(R)) { - return make_quantity(R)>(static_cast(floor(q.numerical_value()))); + return make_quantity(R)>( + static_cast(floor(q.numerical_value_ref_in(q.unit)))); } else { return handle_signed_results(make_quantity(R)>( - static_cast(floor(value_cast(q).numerical_value())))); + static_cast(floor(value_cast(q).numerical_value_ref_in(To))))); } } else { if constexpr (To == get_unit(R)) { @@ -191,8 +198,9 @@ template */ template [[nodiscard]] constexpr quantity(R), Rep> ceil(const quantity& q) noexcept - requires((!treat_as_floating_point) || requires { ceil(q.numerical_value()); } || - requires { std::ceil(q.numerical_value()); }) && + requires((!treat_as_floating_point) || requires { ceil(q.numerical_value_ref_in(q.unit)); } || + + requires { std::ceil(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { ::mp_units::value_cast(q); quantity_values::one(); @@ -207,10 +215,11 @@ template if constexpr (treat_as_floating_point) { using std::ceil; if constexpr (To == get_unit(R)) { - return make_quantity(R)>(static_cast(ceil(q.numerical_value()))); + return make_quantity(R)>( + static_cast(ceil(q.numerical_value_ref_in(q.unit)))); } else { return handle_signed_results(make_quantity(R)>( - static_cast(ceil(value_cast(q).numerical_value())))); + static_cast(ceil(value_cast(q).numerical_value_ref_in(To))))); } } else { if constexpr (To == get_unit(R)) { @@ -231,8 +240,9 @@ template */ template [[nodiscard]] constexpr quantity(R), Rep> round(const quantity& q) noexcept - requires((!treat_as_floating_point) || requires { round(q.numerical_value()); } || - requires { std::round(q.numerical_value()); }) && + requires((!treat_as_floating_point) || requires { round(q.numerical_value_ref_in(q.unit)); } || + + requires { std::round(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { ::mp_units::floor(q); quantity_values::one(); @@ -241,7 +251,8 @@ template if constexpr (To == get_unit(R)) { if constexpr (treat_as_floating_point) { using std::round; - return make_quantity(R)>(static_cast(round(q.numerical_value()))); + return make_quantity(R)>( + static_cast(round(q.numerical_value_ref_in(q.unit)))); } else { return value_cast(q); } @@ -251,7 +262,7 @@ template const auto diff0 = q - res_low; const auto diff1 = res_high - q; if (diff0 == diff1) { - if (static_cast(res_low.numerical_value()) & 1) { + if (static_cast(res_low.numerical_value_ref_in(To)) & 1) { return res_high; } return res_low; @@ -272,8 +283,9 @@ template const quantity& x, const quantity& y) noexcept requires requires { common_reference(R1, R2); } && ( - requires { hypot(x.numerical_value(), y.numerical_value()); } || - requires { std::hypot(x.numerical_value(), y.numerical_value()); }) + requires { hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit)); } || + + requires { std::hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit)); }) { constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); @@ -290,8 +302,14 @@ template const quantity& x, const quantity& y, const quantity& z) noexcept requires requires { common_reference(R1, R2, R3); } && ( - requires { hypot(x.numerical_value(), y.numerical_value(), z.numerical_value()); } || - requires { std::hypot(x.numerical_value(), y.numerical_value(), z.numerical_value()); }) + requires { + hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit), + z.numerical_value_ref_in(z.unit)); + } || + requires { + std::hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit), + z.numerical_value_ref_in(z.unit)); + }) { constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); @@ -303,12 +321,13 @@ namespace isq { template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto sin(const quantity& q) noexcept - requires requires { sin(q.numerical_value()); } || requires { std::sin(q.numerical_value()); } + requires requires { sin(q.numerical_value_ref_in(q.unit)); } || + requires { std::sin(q.numerical_value_ref_in(q.unit)); } { using std::sin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(sin(value_cast(q).numerical_value())); + using rep = decltype(sin(value_cast(q).numerical_value_in(si::radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(sin(value_cast(q).numerical_value_in(si::radian))); } else @@ -317,12 +336,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto cos(const quantity& q) noexcept - requires requires { cos(q.numerical_value()); } || requires { std::cos(q.numerical_value()); } + requires requires { cos(q.numerical_value_ref_in(q.unit)); } || + requires { std::cos(q.numerical_value_ref_in(q.unit)); } { using std::cos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(cos(value_cast(q).numerical_value())); + using rep = decltype(cos(value_cast(q).numerical_value_in(si::radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(cos(value_cast(q).numerical_value_in(si::radian))); } else @@ -331,12 +351,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto tan(const quantity& q) noexcept - requires requires { tan(q.numerical_value()); } || requires { std::tan(q.numerical_value()); } + requires requires { tan(q.numerical_value_ref_in(q.unit)); } || + requires { std::tan(q.numerical_value_ref_in(q.unit)); } { using std::tan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(tan(value_cast(q).numerical_value())); + using rep = decltype(tan(value_cast(q).numerical_value_in(si::radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(tan(value_cast(q).numerical_value_in(si::radian))); } else @@ -345,12 +366,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto asin(const quantity& q) noexcept - requires requires { asin(q.numerical_value()); } || requires { std::asin(q.numerical_value()); } + requires requires { asin(q.numerical_value_ref_in(q.unit)); } || + requires { std::asin(q.numerical_value_ref_in(q.unit)); } { using std::asin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(asin(value_cast(q).numerical_value())); + using rep = decltype(asin(value_cast(q).numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(asin(value_cast(q).numerical_value_in(one))); } else @@ -359,7 +381,8 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto acos(const quantity& q) noexcept - requires requires { acos(q.numerical_value()); } || requires { std::acos(q.numerical_value()); } + requires requires { acos(q.numerical_value_ref_in(q.unit)); } || + requires { std::acos(q.numerical_value_ref_in(q.unit)); } { using std::acos; if constexpr (!treat_as_floating_point) { @@ -373,12 +396,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto atan(const quantity& q) noexcept - requires requires { atan(q.numerical_value()); } || requires { std::atan(q.numerical_value()); } + requires requires { atan(q.numerical_value_ref_in(q.unit)); } || + requires { std::atan(q.numerical_value_ref_in(q.unit)); } { using std::atan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(atan(value_cast(q).numerical_value())); + using rep = decltype(atan(value_cast(q).numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(atan(value_cast(q).numerical_value_in(one))); } else @@ -391,12 +415,13 @@ namespace angular { template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto sin(const quantity& q) noexcept - requires requires { sin(q.numerical_value()); } || requires { std::sin(q.numerical_value()); } + requires requires { sin(q.numerical_value_ref_in(q.unit)); } || + requires { std::sin(q.numerical_value_ref_in(q.unit)); } { using std::sin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(sin(value_cast(q).numerical_value())); + using rep = decltype(sin(value_cast(q).numerical_value_in(radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(sin(value_cast(q).numerical_value_in(radian))); } else @@ -405,12 +430,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto cos(const quantity& q) noexcept - requires requires { cos(q.numerical_value()); } || requires { std::cos(q.numerical_value()); } + requires requires { cos(q.numerical_value_ref_in(q.unit)); } || + requires { std::cos(q.numerical_value_ref_in(q.unit)); } { using std::cos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(cos(value_cast(q).numerical_value())); + using rep = decltype(cos(value_cast(q).numerical_value_in(radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(cos(value_cast(q).numerical_value_in(radian))); } else @@ -419,12 +445,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto tan(const quantity& q) noexcept - requires requires { tan(q.numerical_value()); } || requires { std::tan(q.numerical_value()); } + requires requires { tan(q.numerical_value_ref_in(q.unit)); } || + requires { std::tan(q.numerical_value_ref_in(q.unit)); } { using std::tan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(tan(value_cast(q).numerical_value())); + using rep = decltype(tan(value_cast(q).numerical_value_in(radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(tan(value_cast(q).numerical_value_in(radian))); } else @@ -433,12 +460,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto asin(const quantity& q) noexcept - requires requires { asin(q.numerical_value()); } || requires { std::asin(q.numerical_value()); } + requires requires { asin(q.numerical_value_ref_in(q.unit)); } || + requires { std::asin(q.numerical_value_ref_in(q.unit)); } { using std::asin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(asin(value_cast(q).numerical_value())); + using rep = decltype(asin(value_cast(q).numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(asin(value_cast(q).numerical_value_in(one))); } else @@ -447,12 +475,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto acos(const quantity& q) noexcept - requires requires { acos(q.numerical_value()); } || requires { std::acos(q.numerical_value()); } + requires requires { acos(q.numerical_value_ref_in(q.unit)); } || + requires { std::acos(q.numerical_value_ref_in(q.unit)); } { using std::acos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(acos(value_cast(q).numerical_value())); + using rep = decltype(acos(value_cast(q).numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(acos(value_cast(q).numerical_value_in(one))); } else @@ -461,12 +490,13 @@ template auto R, typename Rep> template auto R, typename Rep> [[nodiscard]] inline QuantityOf auto atan(const quantity& q) noexcept - requires requires { atan(q.numerical_value()); } || requires { std::atan(q.numerical_value()); } + requires requires { atan(q.numerical_value_ref_in(q.unit)); } || + requires { std::atan(q.numerical_value_ref_in(q.unit)); } { using std::atan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(atan(value_cast(q).numerical_value())); + using rep = decltype(atan(value_cast(q).numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(atan(value_cast(q).numerical_value_in(one))); } else diff --git a/src/utility/include/mp-units/random.h b/src/utility/include/mp-units/random.h index 2c26b97a9..fd2ceda9a 100644 --- a/src/utility/include/mp-units/random.h +++ b/src/utility/include/mp-units/random.h @@ -35,7 +35,7 @@ static std::vector i_qty_to_rep(InputIt first, InputIt last) std::vector intervals_rep; intervals_rep.reserve(static_cast(std::distance(first, last))); for (auto itr = first; itr != last; ++itr) { - intervals_rep.push_back(itr->numerical_value()); + intervals_rep.push_back(itr->numerical_value_ref_in(Q::unit)); } return intervals_rep; } @@ -46,7 +46,7 @@ static std::vector bl_qty_to_rep(std::initializer_list& bl) std::vector bl_rep; bl_rep.reserve(bl.size()); for (const Q& qty : bl) { - bl_rep.push_back(qty.numerical_value()); + bl_rep.push_back(qty.numerical_value_ref_in(Q::unit)); } return bl_rep; } @@ -88,7 +88,10 @@ struct uniform_int_distribution : public std::uniform_int_distribution; uniform_int_distribution() : base() {} - uniform_int_distribution(const Q& a, const Q& b) : base(a.numerical_value(), b.numerical_value()) {} + uniform_int_distribution(const Q& a, const Q& b) : + base(a.numerical_value_ref_in(Q::unit), b.numerical_value_ref_in(Q::unit)) + { + } template Q operator()(Generator& g) @@ -110,7 +113,10 @@ struct uniform_real_distribution : public std::uniform_real_distribution; uniform_real_distribution() : base() {} - uniform_real_distribution(const Q& a, const Q& b) : base(a.numerical_value(), b.numerical_value()) {} + uniform_real_distribution(const Q& a, const Q& b) : + base(a.numerical_value_ref_in(Q::unit), b.numerical_value_ref_in(Q::unit)) + { + } template Q operator()(Generator& g) @@ -132,7 +138,7 @@ struct binomial_distribution : public std::binomial_distribution; binomial_distribution() : base() {} - binomial_distribution(const Q& t, double p) : base(t.numerical_value(), p) {} + binomial_distribution(const Q& t, double p) : base(t.numerical_value_ref_in(Q::unit), p) {} template Q operator()(Generator& g) @@ -153,7 +159,7 @@ struct negative_binomial_distribution : public std::negative_binomial_distributi using base = MP_UNITS_TYPENAME std::negative_binomial_distribution; negative_binomial_distribution() : base() {} - negative_binomial_distribution(const Q& k, double p) : base(k.numerical_value(), p) {} + negative_binomial_distribution(const Q& k, double p) : base(k.numerical_value_ref_in(Q::unit), p) {} template Q operator()(Generator& g) @@ -269,7 +275,7 @@ struct extreme_value_distribution : public std::extreme_value_distribution; extreme_value_distribution() : base() {} - extreme_value_distribution(const Q& a, const rep& b) : base(a.numerical_value(), b) {} + extreme_value_distribution(const Q& a, const rep& b) : base(a.numerical_value_ref_in(Q::unit), b) {} template Q operator()(Generator& g) @@ -290,7 +296,10 @@ struct normal_distribution : public std::normal_distribution { using base = MP_UNITS_TYPENAME std::normal_distribution; normal_distribution() : base() {} - normal_distribution(const Q& mean, const Q& stddev) : base(mean.numerical_value(), stddev.numerical_value()) {} + normal_distribution(const Q& mean, const Q& stddev) : + base(mean.numerical_value_ref_in(Q::unit), stddev.numerical_value_ref_in(Q::unit)) + { + } template Q operator()(Generator& g) @@ -312,7 +321,10 @@ struct lognormal_distribution : public std::lognormal_distribution; lognormal_distribution() : base() {} - lognormal_distribution(const Q& m, const Q& s) : base(m.numerical_value(), s.numerical_value()) {} + lognormal_distribution(const Q& m, const Q& s) : + base(m.numerical_value_ref_in(Q::unit), s.numerical_value_ref_in(Q::unit)) + { + } template Q operator()(Generator& g) @@ -353,7 +365,10 @@ struct cauchy_distribution : public std::cauchy_distribution { using base = MP_UNITS_TYPENAME std::cauchy_distribution; cauchy_distribution() : base() {} - cauchy_distribution(const Q& a, const Q& b) : base(a.numerical_value(), b.numerical_value()) {} + cauchy_distribution(const Q& a, const Q& b) : + base(a.numerical_value_ref_in(Q::unit), b.numerical_value_ref_in(Q::unit)) + { + } template Q operator()(Generator& g) @@ -470,7 +485,8 @@ class piecewise_constant_distribution : public std::piecewise_constant_distribut template piecewise_constant_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) : - base(nw, xmin.numerical_value(), xmax.numerical_value(), [fw](rep val) { return fw(val * Q::reference); }) + base(nw, xmin.numerical_value_ref_in(Q::unit), xmax.numerical_value_ref_in(Q::unit), + [fw](rep val) { return fw(val * Q::reference); }) { } @@ -528,7 +544,8 @@ class piecewise_linear_distribution : public std::piecewise_linear_distribution< template piecewise_linear_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw) : - base(nw, xmin.numerical_value(), xmax.numerical_value(), [fw](rep val) { return fw(val * Q::reference); }) + base(nw, xmin.numerical_value_ref_in(Q::unit), xmax.numerical_value_ref_in(Q::unit), + [fw](rep val) { return fw(val * Q::reference); }) { } diff --git a/test/unit_test/runtime/almost_equals.h b/test/unit_test/runtime/almost_equals.h index 69b972c1e..038dfb6e5 100644 --- a/test/unit_test/runtime/almost_equals.h +++ b/test/unit_test/runtime/almost_equals.h @@ -36,8 +36,8 @@ struct AlmostEqualsMatcher : Catch::Matchers::MatcherGenericBase { { using std::abs; using common = std::common_type_t; - const auto x = common(target_).numerical_value(); - const auto y = common(other).numerical_value(); + const auto x = common(target_).numerical_value_ref_in(common::unit); + const auto y = common(other).numerical_value_ref_in(common::unit); const auto maxXYOne = std::max({typename T::rep{1}, abs(x), abs(y)}); return abs(x - y) <= std::numeric_limits::epsilon() * maxXYOne; } diff --git a/test/unit_test/runtime/distribution_test.cpp b/test/unit_test/runtime/distribution_test.cpp index b7f459713..bbf7c5ef9 100644 --- a/test/unit_test/runtime/distribution_test.cpp +++ b/test/unit_test/runtime/distribution_test.cpp @@ -560,7 +560,9 @@ TEST_CASE("piecewise_constant_distribution") auto stl_dist = std::piecewise_constant_distribution(intervals_rep, [](rep val) { return val; }); auto units_dist = - mp_units::piecewise_constant_distribution(intervals_qty, [](q qty) { return qty.numerical_value(); }); + + mp_units::piecewise_constant_distribution(intervals_qty, + [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); @@ -573,8 +575,8 @@ TEST_CASE("piecewise_constant_distribution") constexpr q xmin_qty = 1.0 * isq::length[si::metre], xmax_qty = 3.0 * isq::length[si::metre]; auto stl_dist = std::piecewise_constant_distribution(nw, xmin_rep, xmax_rep, [](rep val) { return val; }); - auto units_dist = - mp_units::piecewise_constant_distribution(nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value(); }); + auto units_dist = mp_units::piecewise_constant_distribution( + nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); @@ -628,7 +630,9 @@ TEST_CASE("piecewise_linear_distribution") auto stl_dist = std::piecewise_linear_distribution(intervals_rep, [](rep val) { return val; }); auto units_dist = - mp_units::piecewise_linear_distribution(intervals_qty, [](q qty) { return qty.numerical_value(); }); + + mp_units::piecewise_linear_distribution(intervals_qty, + [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); @@ -641,8 +645,8 @@ TEST_CASE("piecewise_linear_distribution") constexpr q xmin_qty = 1.0 * isq::length[si::metre], xmax_qty = 3.0 * isq::length[si::metre]; auto stl_dist = std::piecewise_linear_distribution(nw, xmin_rep, xmax_rep, [](rep val) { return val; }); - auto units_dist = - mp_units::piecewise_linear_distribution(nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value(); }); + auto units_dist = mp_units::piecewise_linear_distribution( + nw, xmin_qty, xmax_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); diff --git a/test/unit_test/runtime/linear_algebra_test.cpp b/test/unit_test/runtime/linear_algebra_test.cpp index 818031f4b..8d2cd1e7d 100644 --- a/test/unit_test/runtime/linear_algebra_test.cpp +++ b/test/unit_test/runtime/linear_algebra_test.cpp @@ -74,7 +74,8 @@ template requires(typename Q1::rep v1, typename Q2::rep v2) { cross_product(v1, v2); } [[nodiscard]] QuantityOf auto cross_product(const Q1& q1, const Q2& q2) { - return cross_product(q1.numerical_value(), q2.numerical_value()) * (Q1::reference * Q2::reference); + return cross_product(q1.numerical_value_ref_in(q1.unit), q2.numerical_value_ref_in(q2.unit)) * + (Q1::reference * Q2::reference); } } // namespace @@ -86,21 +87,22 @@ TEST_CASE("vector quantity", "[la]") SECTION("non-truncating") { const auto v = vector{3, 2, 1} * isq::position_vector[km]; - CHECK(v.in(m).numerical_value() == vector{3000, 2000, 1000}); + CHECK(v.numerical_value_in(m) == vector{3000, 2000, 1000}); } SECTION("truncating") { const auto v = vector{1001, 1002, 1003} * isq::position_vector[m]; - CHECK(value_cast(v).numerical_value() == vector{1, 1, 1}); + CHECK(value_cast(v).numerical_value_ref_in(km) == vector{1, 1, 1}); } } SECTION("to scalar magnitude") { const auto v = vector{2, 3, 6} * isq::velocity[km / h]; - const auto speed = get_magnitude(v.numerical_value()) * isq::speed[v.unit]; // TODO can we do better here? - CHECK(speed.numerical_value() == 7); + const auto speed = + get_magnitude(v.numerical_value_ref_in(km / h)) * isq::speed[v.unit]; // TODO can we do better here? + CHECK(speed.numerical_value_ref_in(km / h) == 7); } SECTION("multiply by scalar value") @@ -109,14 +111,14 @@ TEST_CASE("vector quantity", "[la]") SECTION("integral") { - SECTION("scalar on LHS") { CHECK((2 * v).numerical_value() == vector{2, 4, 6}); } - SECTION("scalar on RHS") { CHECK((v * 2).numerical_value() == vector{2, 4, 6}); } + SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_ref_in(m) == vector{2, 4, 6}); } + SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_ref_in(m) == vector{2, 4, 6}); } } SECTION("floating-point") { - SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value() == vector{0.5, 1., 1.5}); } - SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value() == vector{0.5, 1., 1.5}); } + SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_ref_in(m) == vector{0.5, 1., 1.5}); } + SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_ref_in(m) == vector{0.5, 1., 1.5}); } } } @@ -124,8 +126,8 @@ TEST_CASE("vector quantity", "[la]") { const auto v = vector{2, 4, 6} * isq::position_vector[m]; - SECTION("integral") { CHECK((v / 2).numerical_value() == vector{1, 2, 3}); } - SECTION("floating-point") { CHECK((v / 0.5).numerical_value() == vector{4., 8., 12.}); } + SECTION("integral") { CHECK((v / 2).numerical_value_ref_in(m) == vector{1, 2, 3}); } + SECTION("floating-point") { CHECK((v / 0.5).numerical_value_ref_in(m) == vector{4., 8., 12.}); } } SECTION("add") @@ -135,12 +137,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("same unit") { const auto u = vector{3, 2, 1} * isq::position_vector[m]; - CHECK((v + u).numerical_value() == vector{4, 4, 4}); + CHECK((v + u).numerical_value_ref_in(m) == vector{4, 4, 4}); } SECTION("different units") { const auto u = vector{3, 2, 1} * isq::position_vector[km]; - CHECK((v + u).numerical_value() == vector{3001, 2002, 1003}); + CHECK((v + u).numerical_value_ref_in(m) == vector{3001, 2002, 1003}); } } @@ -151,12 +153,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("same unit") { const auto u = vector{3, 2, 1} * isq::position_vector[m]; - CHECK((v - u).numerical_value() == vector{-2, 0, 2}); + CHECK((v - u).numerical_value_ref_in(m) == vector{-2, 0, 2}); } SECTION("different units") { const auto u = vector{3, 2, 1} * isq::position_vector[km]; - CHECK((v - u).numerical_value() == vector{-2999, -1998, -997}); + CHECK((v - u).numerical_value_ref_in(m) == vector{-2999, -1998, -997}); } } @@ -170,18 +172,18 @@ TEST_CASE("vector quantity", "[la]") SECTION("derived_quantity_spec") { - SECTION("scalar on LHS") { CHECK((mass * v).numerical_value() == vector{2, 4, 6}); } - SECTION("scalar on RHS") { CHECK((v * mass).numerical_value() == vector{2, 4, 6}); } + SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ref_in(N * s) == vector{2, 4, 6}); } + SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ref_in(N * s) == vector{2, 4, 6}); } } SECTION("quantity_cast to momentum") { SECTION("scalar on LHS") { - CHECK(quantity_cast(mass * v).numerical_value() == vector{2, 4, 6}); + CHECK(quantity_cast(mass * v).numerical_value_ref_in(N * s) == vector{2, 4, 6}); } SECTION("scalar on RHS") { - CHECK(quantity_cast(v * mass).numerical_value() == vector{2, 4, 6}); + CHECK(quantity_cast(v * mass).numerical_value_ref_in(N * s) == vector{2, 4, 6}); } } SECTION("quantity of momentum") @@ -189,12 +191,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("scalar on LHS") { const quantity> momentum = mass * v; - CHECK(momentum.numerical_value() == vector{2, 4, 6}); + CHECK(momentum.numerical_value_ref_in(N * s) == vector{2, 4, 6}); } SECTION("scalar on RHS") { const quantity> momentum = v * mass; - CHECK(momentum.numerical_value() == vector{2, 4, 6}); + CHECK(momentum.numerical_value_ref_in(N * s) == vector{2, 4, 6}); } } } @@ -205,18 +207,18 @@ TEST_CASE("vector quantity", "[la]") SECTION("derived_quantity_spec") { - SECTION("scalar on LHS") { CHECK((mass * v).numerical_value() == vector{0.5, 1., 1.5}); } - SECTION("scalar on RHS") { CHECK((v * mass).numerical_value() == vector{0.5, 1., 1.5}); } + SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } + SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } } SECTION("quantity_cast to momentum") { SECTION("scalar on LHS") { - CHECK(quantity_cast(mass * v).numerical_value() == vector{0.5, 1., 1.5}); + CHECK(quantity_cast(mass * v).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } SECTION("scalar on RHS") { - CHECK(quantity_cast(v * mass).numerical_value() == vector{0.5, 1., 1.5}); + CHECK(quantity_cast(v * mass).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } } SECTION("quantity of momentum") @@ -224,12 +226,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("scalar on LHS") { const quantity> momentum = mass * v; - CHECK(momentum.numerical_value() == vector{0.5, 1., 1.5}); + CHECK(momentum.numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } SECTION("scalar on RHS") { const quantity> momentum = v * mass; - CHECK(momentum.numerical_value() == vector{0.5, 1., 1.5}); + CHECK(momentum.numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } } } @@ -243,15 +245,15 @@ TEST_CASE("vector quantity", "[la]") { const auto dur = 2 * isq::duration[h]; - SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value() == vector{15, 10, 5}); } + SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ref_in(km / h) == vector{15, 10, 5}); } SECTION("quantity_cast to velocity") { - CHECK(quantity_cast(pos / dur).numerical_value() == vector{15, 10, 5}); + CHECK(quantity_cast(pos / dur).numerical_value_ref_in(km / h) == vector{15, 10, 5}); } SECTION("quantity of velocity") { const quantity> v = pos / dur; - CHECK(v.numerical_value() == vector{15, 10, 5}); + CHECK(v.numerical_value_ref_in(km / h) == vector{15, 10, 5}); } } @@ -259,15 +261,18 @@ TEST_CASE("vector quantity", "[la]") { const auto dur = 0.5 * isq::duration[h]; - SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value() == vector{60, 40, 20}); } + SECTION("derived_quantity_spec") + { + CHECK((pos / dur).numerical_value_ref_in(km / h) == vector{60, 40, 20}); + } SECTION("quantity_cast to velocity") { - CHECK(quantity_cast(pos / dur).numerical_value() == vector{60, 40, 20}); + CHECK(quantity_cast(pos / dur).numerical_value_ref_in(km / h) == vector{60, 40, 20}); } SECTION("quantity of velocity") { const quantity> v = pos / dur; - CHECK(v.numerical_value() == vector{60, 40, 20}); + CHECK(v.numerical_value_ref_in(km / h) == vector{60, 40, 20}); } } } @@ -303,8 +308,9 @@ TEST_CASE("vector of quantities", "[la]") SECTION("to scalar magnitude") { const vector> v = {2 * (km / h), 3 * (km / h), 6 * (km / h)}; - const auto speed = get_magnitude(v).numerical_value() * isq::speed[v(0).unit]; // TODO can we do better here? - CHECK(speed.numerical_value() == 7); + const auto speed = + get_magnitude(v).numerical_value_ref_in(km / h) * isq::speed[v(0).unit]; // TODO can we do better here? + CHECK(speed.numerical_value_ref_in(km / h) == 7); } SECTION("multiply by scalar value") diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index 4e838273e..3391e9007 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -90,12 +90,13 @@ TEST_CASE("numeric_limits functions", "[limits]") { SECTION("'epsilon' works as expected using default floating type") { - REQUIRE(epsilon(isq::length[m]).numerical_value() == + REQUIRE(epsilon(isq::length[m]).numerical_value_ref_in(m) == std::numeric_limits::epsilon()); } SECTION("'epsilon' works as expected using integers") { - REQUIRE(epsilon(isq::length[m]).numerical_value() == + REQUIRE(epsilon(isq::length[m]).numerical_value_ref_in(m) == + std::numeric_limits::epsilon()); } } diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index e93ebf09f..b86478c3e 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -241,17 +241,19 @@ static_assert( // static member functions //////////////////////////// -static_assert(quantity_point::zero().quantity_from_origin().numerical_value() == 0); -static_assert(quantity_point::min().quantity_from_origin().numerical_value() == +static_assert(quantity_point::zero().quantity_from_origin().numerical_value_ref_in(m) == + 0); +static_assert(quantity_point::min().quantity_from_origin().numerical_value_ref_in(m) == std::numeric_limits::lowest()); -static_assert(quantity_point::max().quantity_from_origin().numerical_value() == +static_assert(quantity_point::max().quantity_from_origin().numerical_value_ref_in(m) == std::numeric_limits::max()); -static_assert(quantity_point::zero().quantity_from_origin().numerical_value() == 0); -static_assert(quantity_point::min().quantity_from_origin().numerical_value() == - std::numeric_limits::lowest()); -static_assert(quantity_point::max().quantity_from_origin().numerical_value() == - std::numeric_limits::max()); +static_assert( + quantity_point::zero().quantity_from_origin().numerical_value_ref_in(m) == 0); +static_assert(quantity_point::min().quantity_from_origin().numerical_value_ref_in( + m) == std::numeric_limits::lowest()); +static_assert(quantity_point::max().quantity_from_origin().numerical_value_ref_in( + m) == std::numeric_limits::max()); ////////////////////////////// @@ -576,15 +578,15 @@ static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(m // converting to a different unit /////////////////////////////////// -static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin().numerical_value() == 2.); -static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin().numerical_value() == 2000.); -static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin().numerical_value() == 2.); -static_assert((ground_level + 2. * km).in(km).quantity_from_origin().numerical_value() == 2.); -static_assert((ground_level + 2. * km).in(m).quantity_from_origin().numerical_value() == 2000.); -static_assert((ground_level + 2000. * m).in(km).quantity_from_origin().numerical_value() == 2.); -static_assert((tower_peak + 2. * km).in(km).quantity_from_origin().numerical_value() == 2.); -static_assert((tower_peak + 2. * km).in(m).quantity_from_origin().numerical_value() == 2000.); -static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin().numerical_value() == 2.); +static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); +static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.); +static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); +static_assert((ground_level + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); +static_assert((ground_level + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.); +static_assert((ground_level + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); +static_assert((tower_peak + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); +static_assert((tower_peak + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.); +static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); #if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2 template typename QP> @@ -657,14 +659,14 @@ static_assert([](auto v) { //////////////////////// // same type -static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin().numerical_value() == 2); -static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin().numerical_value() == 1); +static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2); +static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1); // different types -static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin().numerical_value() == 5.5); -static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin().numerical_value() == 1123); -static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin().numerical_value() == 2.5); -static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin().numerical_value() == 123); +static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin().numerical_value_ref_in(m) == 5.5); +static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1123); +static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5); +static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 123); template typename QP> @@ -935,31 +937,32 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu // check for integral types promotion -static_assert( - is_same_v< - decltype(((mean_sea_level + std::uint8_t(0) * m) + std::uint8_t(0) * m).quantity_from_origin().numerical_value()), - int&&>); -static_assert( - is_same_v< - decltype((std::uint8_t(0) * m + (mean_sea_level + std::uint8_t(0) * m)).quantity_from_origin().numerical_value()), - int&&>); -static_assert( - is_same_v< - decltype(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(0) * m).quantity_from_origin().numerical_value()), - int&&>); +static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); static_assert(is_same_v); static_assert( - ((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m).quantity_from_origin().numerical_value() == + ((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m).quantity_from_origin().numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); static_assert( - (std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)).quantity_from_origin().numerical_value() == + (std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)).quantity_from_origin().numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); -static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin().numerical_value() == - std::uint8_t(0) - std::uint8_t(1)); -static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value() == - std::uint8_t(0) - std::uint8_t(1)); +static_assert( + ((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin().numerical_value_ref_in(m) == + std::uint8_t(0) - std::uint8_t(1)); +static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)) + .numerical_value_ref_in(m) == std::uint8_t(0) - std::uint8_t(1)); // different representation types static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * m, quantity_point>); @@ -1013,39 +1016,39 @@ static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m), static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity>); -static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin().numerical_value() == 2); -static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 2); -static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin().numerical_value() == 1001); -static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value() == 1001); -static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin().numerical_value() == 1001); -static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 1001); -static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin().numerical_value() == 1); -static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin().numerical_value() == 999); - -static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin().numerical_value() == 2.5); -static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 2.5); -static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin().numerical_value() == 1001.5); -static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value() == 1001.5); -static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin().numerical_value() == 1501); -static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value() == 1501); -static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin().numerical_value() == 1.5); -static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin().numerical_value() == 1499); - -static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin().numerical_value() == 2.5); -static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value() == 2.5); -static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin().numerical_value() == 1501); -static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin().numerical_value() == 1501); -static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin().numerical_value() == 1001.5); -static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value() == 1001.5); -static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin().numerical_value() == 0.5); -static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin().numerical_value() == 998.5); - -static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value() == 1); -static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value() == 999); -static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value() == 1.5); -static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value() == 1499); -static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value() == 0.5); -static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value() == 998.5); +static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2); +static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2); +static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1001); +static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1001); +static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1001); +static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1001); +static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1); +static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 999); + +static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5); +static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2.5); +static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); +static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); +static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1501); +static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1501); +static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1.5); +static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1499); + +static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5); +static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2.5); +static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin().numerical_value_ref_in(m) == 1501); +static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1501); +static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); +static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); +static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 0.5); +static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 998.5); + +static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1); +static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 999); +static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1.5); +static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1499); +static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_ref_in(m) == 0.5); +static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_ref_in(m) == 998.5); static_assert((mean_sea_level + 42 * m) - (ground_level + 42 * m) == -42 * m); static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 0fdc13b3f..83c43c969 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -112,14 +112,15 @@ static_assert(is_same_v::rep, int>); // static member functions //////////////////////////// -static_assert(quantity::zero().numerical_value() == 0); -static_assert(quantity::one().numerical_value() == 1); -static_assert(quantity::min().numerical_value() == std::numeric_limits::lowest()); -static_assert(quantity::max().numerical_value() == std::numeric_limits::max()); -static_assert(quantity::zero().numerical_value() == 0.0); -static_assert(quantity::one().numerical_value() == 1.0); -static_assert(quantity::min().numerical_value() == std::numeric_limits::lowest()); -static_assert(quantity::max().numerical_value() == std::numeric_limits::max()); +static_assert(quantity::zero().numerical_value_ref_in(m) == 0); +static_assert(quantity::one().numerical_value_ref_in(m) == 1); +static_assert(quantity::min().numerical_value_ref_in(m) == std::numeric_limits::lowest()); +static_assert(quantity::max().numerical_value_ref_in(m) == std::numeric_limits::max()); +static_assert(quantity::zero().numerical_value_ref_in(m) == 0.0); +static_assert(quantity::one().numerical_value_ref_in(m) == 1.0); +static_assert(quantity::min().numerical_value_ref_in(m) == + std::numeric_limits::lowest()); +static_assert(quantity::max().numerical_value_ref_in(m) == std::numeric_limits::max()); ////////////////////////////// @@ -190,10 +191,10 @@ static_assert(std::convertible_to, quantity(123 * m).numerical_value() == 123); -static_assert(quantity(2 * km).numerical_value() == 2000); -static_assert(quantity(2 * km).numerical_value() == 2); -static_assert(quantity(1500 * m).numerical_value() == 1.5); +static_assert(quantity(123 * m).numerical_value_ref_in(m) == 123); +static_assert(quantity(2 * km).numerical_value_ref_in(m) == 2000); +static_assert(quantity(2 * km).numerical_value_ref_in(km) == 2); +static_assert(quantity(1500 * m).numerical_value_ref_in(km) == 1.5); /////////////////////////////////// @@ -204,11 +205,11 @@ static_assert(is_of_type<(2. * km).in(m), quantity>); static_assert(is_of_type>); static_assert(is_of_type>); -static_assert(quantity(2. * km).in(km).numerical_value() == 2.); -static_assert(quantity(2. * km).in(m).numerical_value() == 2000.); -static_assert(quantity(2000. * m).in(km).numerical_value() == 2.); -static_assert(quantity(2 * km).in(km).numerical_value() == 2); -static_assert(quantity(2 * km).in(m).numerical_value() == 2000); +static_assert(quantity(2. * km).in(km).numerical_value_ref_in(km) == 2.); +static_assert(quantity(2. * km).in(m).numerical_value_ref_in(m) == 2000.); +static_assert(quantity(2000. * m).in(km).numerical_value_ref_in(km) == 2.); +static_assert(quantity(2 * km).in(km).numerical_value_ref_in(km) == 2); +static_assert(quantity(2 * km).in(m).numerical_value_ref_in(m) == 2000); #if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2 template typename Q> @@ -308,28 +309,28 @@ static_assert([] { auto l1(1 * m), l2(2 * m); return l2 = l1; }() - .numerical_value() == 1); + .numerical_value_ref_in(m) == 1); static_assert([] { const auto l1(1 * m); auto l2(2 * m); return l2 = l1; }() - .numerical_value() == 1); + .numerical_value_ref_in(m) == 1); static_assert([]() { auto l1(1 * m), l2(2 * m); return l2 = std::move(l1); }() - .numerical_value() == 1); + .numerical_value_ref_in(m) == 1); //////////////////// // unary operators //////////////////// -static_assert((+123 * m).numerical_value() == 123); -static_assert((-123 * m).numerical_value() == -123); -static_assert((+(-123 * m)).numerical_value() == -123); -static_assert((-(-123 * m)).numerical_value() == 123); +static_assert((+123 * m).numerical_value_ref_in(m) == 123); +static_assert((-123 * m).numerical_value_ref_in(m) == -123); +static_assert((+(-123 * m)).numerical_value_ref_in(m) == -123); +static_assert((-(-123 * m)).numerical_value_ref_in(m) == 123); static_assert([](auto v) { auto vv = v++; @@ -348,7 +349,7 @@ static_assert([](auto v) { return std::pair(v, vv); }(123 * m) == std::pair(122 * m, 122 * m)); -static_assert(is_same_v); +static_assert(is_same_v); //////////////////////// @@ -356,29 +357,30 @@ static_assert(is_same_v); //////////////////////// // same type -static_assert((1 * m += 1 * m).numerical_value() == 2); -static_assert((2 * m -= 1 * m).numerical_value() == 1); -static_assert((1 * m *= 2).numerical_value() == 2); -static_assert((2 * m /= 2).numerical_value() == 1); -static_assert((1 * m *= 2 * one).numerical_value() == 2); -static_assert((2 * m /= 2 * one).numerical_value() == 1); -static_assert((7 * m %= 2 * m).numerical_value() == 1); +static_assert((1 * m += 1 * m).numerical_value_ref_in(m) == 2); +static_assert((2 * m -= 1 * m).numerical_value_ref_in(m) == 1); +static_assert((1 * m *= 2).numerical_value_ref_in(m) == 2); +static_assert((2 * m /= 2).numerical_value_ref_in(m) == 1); +static_assert((1 * m *= 2 * one).numerical_value_ref_in(m) == 2); +static_assert((2 * m /= 2 * one).numerical_value_ref_in(m) == 1); +static_assert((7 * m %= 2 * m).numerical_value_ref_in(m) == 1); // different types -static_assert((2.5 * m += 3 * m).numerical_value() == 5.5); -static_assert((123 * m += 1 * km).numerical_value() == 1123); -static_assert((5.5 * m -= 3 * m).numerical_value() == 2.5); -static_assert((1123 * m -= 1 * km).numerical_value() == 123); -static_assert((2.5 * m *= 3).numerical_value() == 7.5); -static_assert((7.5 * m /= 3).numerical_value() == 2.5); -static_assert((2.5 * m *= 3 * one).numerical_value() == 7.5); -static_assert((7.5 * m /= 3 * one).numerical_value() == 2.5); -static_assert((3500 * m %= 1 * km).numerical_value() == 500); - -// static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value() != [] { std::uint8_t ui(255); return ui %= 256; +static_assert((2.5 * m += 3 * m).numerical_value_ref_in(m) == 5.5); +static_assert((123 * m += 1 * km).numerical_value_ref_in(m) == 1123); +static_assert((5.5 * m -= 3 * m).numerical_value_ref_in(m) == 2.5); +static_assert((1123 * m -= 1 * km).numerical_value_ref_in(m) == 123); +static_assert((2.5 * m *= 3).numerical_value_ref_in(m) == 7.5); +static_assert((7.5 * m /= 3).numerical_value_ref_in(m) == 2.5); +static_assert((2.5 * m *= 3 * one).numerical_value_ref_in(m) == 7.5); +static_assert((7.5 * m /= 3 * one).numerical_value_ref_in(m) == 2.5); +static_assert((3500 * m %= 1 * km).numerical_value_ref_in(m) == 500); + +// static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value_ref_in(m) != [] { std::uint8_t ui(255); return ui %= +// 256; // }()); // UB // TODO: Fix -static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value() != [] { +static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value_ref_in(m) != [] { std::uint8_t ui(255); return ui %= 257; }()); @@ -388,10 +390,10 @@ static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value() != [] { #ifndef MP_UNITS_COMP_MSVC // next two lines trigger conversions warnings // (warning disabled in CMake for this file) -static_assert((22 * m *= 33.33).numerical_value() == 733); -static_assert((22 * m /= 3.33).numerical_value() == 6); -static_assert((22 * m *= 33.33 * one).numerical_value() == 733); -static_assert((22 * m /= 3.33 * one).numerical_value() == 6); +static_assert((22 * m *= 33.33).numerical_value_ref_in(m) == 733); +static_assert((22 * m /= 3.33).numerical_value_ref_in(m) == 6); +static_assert((22 * m *= 33.33 * one).numerical_value_ref_in(m) == 733); +static_assert((22 * m /= 3.33 * one).numerical_value_ref_in(m) == 6); #endif template typename Q> @@ -516,13 +518,14 @@ static_assert(is_of_type<1 * km % (300 * m), quantity>); static_assert(is_of_type<4 * one % (2 * one), quantity>); // check for integral types promotion -static_assert(is_same_v); -static_assert(is_same_v); -static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value() == +static_assert(is_same_v); +static_assert(is_same_v); +static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); -static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value() == std::uint8_t(0) - std::uint8_t(1)); +static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_ref_in(m) == + std::uint8_t(0) - std::uint8_t(1)); -static_assert(is_same_v); // different representation types @@ -596,67 +599,67 @@ static_assert(is_of_type<1 * m / (1 * s), quantity>{}, int>>); static_assert(is_of_type<1 * min / (1 * m), quantity>{}, int>>); -static_assert((1 * m + 1 * m).numerical_value() == 2); -static_assert((1 * m + 1 * km).numerical_value() == 1001); -static_assert((1 * km + 1 * m).numerical_value() == 1001); -static_assert((2 * m - 1 * m).numerical_value() == 1); -static_assert((1 * km - 1 * m).numerical_value() == 999); -static_assert((2 * m * 2).numerical_value() == 4); -static_assert((2 * m * (2 * one)).numerical_value() == 4); -static_assert((2 * m * (2 * percent)).numerical_value() == 4); -static_assert((3 * 3 * m).numerical_value() == 9); -static_assert(((3 * one) * (3 * m)).numerical_value() == 9); -static_assert(((3 * percent) * (3 * m)).numerical_value() == 9); -static_assert((4 * m / 2).numerical_value() == 2); -static_assert((4 * m / (2 * one)).numerical_value() == 2); -static_assert((4 * m / (2 * percent)).numerical_value() == 2); -static_assert((4 * km / (2 * m)).numerical_value() == 2); -static_assert((4000 * m / (2 * m)).numerical_value() == 2000); - -static_assert((1.5 * m + 1 * m).numerical_value() == 2.5); -static_assert((1.5 * m + 1 * km).numerical_value() == 1001.5); -static_assert((1.5 * km + 1 * m).numerical_value() == 1501); -static_assert((2.5 * m - 1 * m).numerical_value() == 1.5); -static_assert((1.5 * km - 1 * m).numerical_value() == 1499); -static_assert((2.5 * m * 2).numerical_value() == 5); -static_assert((2.5 * m * (2 * one)).numerical_value() == 5); -static_assert((2.5 * m * (2 * percent)).numerical_value() == 5); -static_assert((2.5L * (2 * m)).numerical_value() == 5); -static_assert((2.5L * one * (2 * m)).numerical_value() == 5); -static_assert((2.5L * percent * (2 * m)).numerical_value() == 5); -static_assert((5. * m / 2).numerical_value() == 2.5); -static_assert((5. * m / (2 * one)).numerical_value() == 2.5); -static_assert((5. * m / (2 * percent)).numerical_value() == 2.5); -static_assert((5. * km / (2 * m)).numerical_value() == 2.5); -static_assert((5000. * m / (2 * m)).numerical_value() == 2500); - -static_assert((1 * m + 1.5 * m).numerical_value() == 2.5); -static_assert((1 * m + 1.5 * km).numerical_value() == 1501); -static_assert((1 * km + 1.5 * m).numerical_value() == 1001.5); -static_assert((2 * m - 1.5 * m).numerical_value() == 0.5); -static_assert((1 * km - 1.5 * m).numerical_value() == 998.5); -static_assert((2 * m * 2.5L).numerical_value() == 5); -static_assert((2 * m * (2.5L * one)).numerical_value() == 5); -static_assert((2 * m * (2.5L * percent)).numerical_value() == 5); -static_assert((2 * 2.5 * m).numerical_value() == 5); -static_assert((2 * one * (2.5 * m)).numerical_value() == 5); -static_assert((2 * percent * (2.5 * m)).numerical_value() == 5); -static_assert((5 * m / 2.5L).numerical_value() == 2); -static_assert((5 * m / (2.5L * one)).numerical_value() == 2); -static_assert((5 * m / (2.5L * percent)).numerical_value() == 2); -static_assert((5 * km / (2.5 * m)).numerical_value() == 2); -static_assert((5000 * m / (2.5 * m)).numerical_value() == 2000); - -static_assert((7 * m % (2 * m)).numerical_value() == 1); -static_assert((7 * km % (2000 * m)).numerical_value() == 1000); -static_assert((1300 * m % (1 * km)).numerical_value() == 300); -static_assert((7 * one % (2 * one)).numerical_value() == 1); +static_assert((1 * m + 1 * m).numerical_value_ref_in(m) == 2); +static_assert((1 * m + 1 * km).numerical_value_ref_in(m) == 1001); +static_assert((1 * km + 1 * m).numerical_value_ref_in(m) == 1001); +static_assert((2 * m - 1 * m).numerical_value_ref_in(m) == 1); +static_assert((1 * km - 1 * m).numerical_value_ref_in(m) == 999); +static_assert((2 * m * 2).numerical_value_ref_in(m) == 4); +static_assert((2 * m * (2 * one)).numerical_value_ref_in(m) == 4); +static_assert((2 * m * (2 * percent)).numerical_value_ref_in(m * percent) == 4); +static_assert((3 * 3 * m).numerical_value_ref_in(m) == 9); +static_assert(((3 * one) * (3 * m)).numerical_value_ref_in(m) == 9); +static_assert(((3 * percent) * (3 * m)).numerical_value_ref_in(m * percent) == 9); +static_assert((4 * m / 2).numerical_value_ref_in(m) == 2); +static_assert((4 * m / (2 * one)).numerical_value_ref_in(m) == 2); +static_assert((4 * m / (2 * percent)).numerical_value_ref_in(m / percent) == 2); +static_assert((4 * km / (2 * m)).numerical_value_ref_in(km / m) == 2); +static_assert((4000 * m / (2 * m)).numerical_value_ref_in(one) == 2000); + +static_assert((1.5 * m + 1 * m).numerical_value_ref_in(m) == 2.5); +static_assert((1.5 * m + 1 * km).numerical_value_ref_in(m) == 1001.5); +static_assert((1.5 * km + 1 * m).numerical_value_ref_in(m) == 1501); +static_assert((2.5 * m - 1 * m).numerical_value_ref_in(m) == 1.5); +static_assert((1.5 * km - 1 * m).numerical_value_ref_in(m) == 1499); +static_assert((2.5 * m * 2).numerical_value_ref_in(m) == 5); +static_assert((2.5 * m * (2 * one)).numerical_value_ref_in(m) == 5); +static_assert((2.5 * m * (2 * percent)).numerical_value_ref_in(m * percent) == 5); +static_assert((2.5L * (2 * m)).numerical_value_ref_in(m) == 5); +static_assert((2.5L * one * (2 * m)).numerical_value_ref_in(m) == 5); +static_assert((2.5L * percent * (2 * m)).numerical_value_ref_in(m * percent) == 5); +static_assert((5. * m / 2).numerical_value_ref_in(m) == 2.5); +static_assert((5. * m / (2 * one)).numerical_value_ref_in(m) == 2.5); +static_assert((5. * m / (2 * percent)).numerical_value_ref_in(m / percent) == 2.5); +static_assert((5. * km / (2 * m)).numerical_value_ref_in(km / m) == 2.5); +static_assert((5000. * m / (2 * m)).numerical_value_ref_in(one) == 2500); + +static_assert((1 * m + 1.5 * m).numerical_value_ref_in(m) == 2.5); +static_assert((1 * m + 1.5 * km).numerical_value_ref_in(m) == 1501); +static_assert((1 * km + 1.5 * m).numerical_value_ref_in(m) == 1001.5); +static_assert((2 * m - 1.5 * m).numerical_value_ref_in(m) == 0.5); +static_assert((1 * km - 1.5 * m).numerical_value_ref_in(m) == 998.5); +static_assert((2 * m * 2.5L).numerical_value_ref_in(m) == 5); +static_assert((2 * m * (2.5L * one)).numerical_value_ref_in(m) == 5); +static_assert((2 * m * (2.5L * percent)).numerical_value_ref_in(m * percent) == 5); +static_assert((2 * 2.5 * m).numerical_value_ref_in(m) == 5); +static_assert((2 * one * (2.5 * m)).numerical_value_ref_in(m) == 5); +static_assert((2 * percent * (2.5 * m)).numerical_value_ref_in(m * percent) == 5); +static_assert((5 * m / 2.5L).numerical_value_ref_in(m) == 2); +static_assert((5 * m / (2.5L * one)).numerical_value_ref_in(m) == 2); +static_assert((5 * m / (2.5L * percent)).numerical_value_ref_in(m / percent) == 2); +static_assert((5 * km / (2.5 * m)).numerical_value_ref_in(km / m) == 2); +static_assert((5000 * m / (2.5 * m)).numerical_value_ref_in(one) == 2000); + +static_assert((7 * m % (2 * m)).numerical_value_ref_in(m) == 1); +static_assert((7 * km % (2000 * m)).numerical_value_ref_in(m) == 1000); +static_assert((1300 * m % (1 * km)).numerical_value_ref_in(m) == 300); +static_assert((7 * one % (2 * one)).numerical_value_ref_in(one) == 1); static_assert((10 * m2 * (10 * m2)) / (50 * m2) == 2 * m2); -static_assert((10 * km / (5 * m)).numerical_value() == 2); -static_assert((10 * km / (5 * m)).in(one).numerical_value() == 2000); -static_assert((10 * s * (2 * kHz)).numerical_value() == 20); +static_assert((10 * km / (5 * m)).numerical_value_ref_in(km / m) == 2); +static_assert((10 * km / (5 * m)).numerical_value_in(one) == 2000); +static_assert((10 * s * (2 * kHz)).numerical_value_ref_in(s * kHz) == 20); // commutativity and associativity static_assert(10 * isq::length[si::metre] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]); @@ -740,13 +743,15 @@ static_assert(is_same_v); static_assert(1 * one - 30 * percent == (100 - 30) * percent); static_assert(1 * one + 30 * percent == (100 + 30) * percent); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value() == +static_assert(is_same_v); +static_assert(is_same_v); +static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_ref_in(one) == + std::uint8_t(128) + std::uint8_t(128)); -static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value() == std::uint8_t(0) - std::uint8_t(1)); +static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_ref_in(one) == + std::uint8_t(0) - std::uint8_t(1)); -static_assert(is_same_v); static_assert(2 * one * (1 * m) == 2 * m); @@ -880,20 +885,20 @@ static_assert(!(123 * km >= 321'000 * m)); static_assert(is_of_type<10 * km / (5 * km), quantity>); -static_assert((50. * m / (100. * m)).in(percent).numerical_value() == 50); +static_assert((50. * m / (100. * m)).numerical_value_in(percent) == 50); static_assert(50. * m / (100. * m) == 50 * percent); -static_assert((50. * percent).in(one).numerical_value() == 0.5); +static_assert((50. * percent).numerical_value_in(one) == 0.5); ////////////////// // value_cast ////////////////// -static_assert(value_cast(2 * km).numerical_value() == 2000); -static_assert(value_cast(2000 * m).numerical_value() == 2); -static_assert(value_cast(1.23 * m).numerical_value() == 1); -static_assert(value_cast(2000.0 * m / (3600.0 * s)).numerical_value() == 2); +static_assert(value_cast(2 * km).numerical_value_ref_in(m) == 2000); +static_assert(value_cast(2000 * m).numerical_value_ref_in(km) == 2); +static_assert(value_cast(1.23 * m).numerical_value_ref_in(m) == 1); +static_assert(value_cast(2000.0 * m / (3600.0 * s)).numerical_value_ref_in(km / h) == 2); ////////////////// // quantity_cast From 3b2ca4084adaf97fe9ba72bacb04a94548b44905 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 27 Aug 2023 21:16:29 +0200 Subject: [PATCH 02/22] refactor: `quantity_point::quantity_from_origin()` refactored to `quantity_point::quantity_ref_from(PO)` Resolves #479 and relates to #477 --- example/currency.cpp | 4 +- example/include/geographic.h | 14 +- example/kalman_filter/kalman.h | 2 +- .../kalman_filter/kalman_filter-example_6.cpp | 2 +- .../kalman_filter/kalman_filter-example_7.cpp | 2 +- .../kalman_filter/kalman_filter-example_8.cpp | 2 +- example/unmanned_aerial_vehicle.cpp | 8 +- src/core/include/mp-units/quantity_point.h | 65 +++-- test/unit_test/static/quantity_point_test.cpp | 243 ++++++++++-------- 9 files changed, 193 insertions(+), 149 deletions(-) diff --git a/example/currency.cpp b/example/currency.cpp index bb5d9b393..070ee4682 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -93,6 +93,6 @@ int main() quantity_point price_usd = zero + 100 * us_dollar; quantity_point price_euro = exchange_to(price_usd); - std::cout << price_usd.quantity_from_origin() << " -> " << price_euro.quantity_from_origin() << "\n"; - // std::cout << price_usd.quantity_from_origin() + price_euro.quantity_from_origin() << "\n"; // does not compile + std::cout << price_usd.quantity_ref_from(zero) << " -> " << price_euro.quantity_ref_from(zero) << "\n"; + // std::cout << price_usd.quantity_ref_from(zero) + price_euro.quantity_ref_from(zero) << "\n"; // does not compile } diff --git a/example/include/geographic.h b/example/include/geographic.h index e24a0aaba..3f5d77ca3 100644 --- a/example/include/geographic.h +++ b/example/include/geographic.h @@ -138,7 +138,7 @@ struct MP_UNITS_STD_FMT::formatter> : auto format(geographic::latitude lat, FormatContext& ctx) { formatter::quantity_type>::format( - is_gt_zero(lat) ? lat.quantity_from_origin() : -lat.quantity_from_origin(), ctx); + is_gt_zero(lat) ? lat.quantity_ref_from(geographic::equator) : -lat.quantity_ref_from(geographic::equator), ctx); MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lat) ? " N" : "S"); return ctx.out(); } @@ -151,7 +151,9 @@ struct MP_UNITS_STD_FMT::formatter> : auto format(geographic::longitude lon, FormatContext& ctx) { formatter::quantity_type>::format( - is_gt_zero(lon) ? lon.quantity_from_origin() : -lon.quantity_from_origin(), ctx); + is_gt_zero(lon) ? lon.quantity_ref_from(geographic::prime_meridian) + : -lon.quantity_ref_from(geographic::prime_meridian), + ctx); MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lon) ? " E" : " W"); return ctx.out(); } @@ -175,10 +177,10 @@ distance spherical_distance(position from, position to) using isq::sin, isq::cos, isq::asin, isq::acos; - const auto& from_lat = from.lat.quantity_from_origin(); - const auto& from_lon = from.lon.quantity_from_origin(); - const auto& to_lat = to.lat.quantity_from_origin(); - const auto& to_lon = to.lon.quantity_from_origin(); + const auto& from_lat = from.lat.quantity_ref_from(equator); + const auto& from_lon = from.lon.quantity_ref_from(prime_meridian); + const auto& to_lat = to.lat.quantity_ref_from(equator); + const auto& to_lon = to.lon.quantity_ref_from(prime_meridian); // https://en.wikipedia.org/wiki/Great-circle_distance#Formulae if constexpr (sizeof(T) >= 8) { diff --git a/example/kalman_filter/kalman.h b/example/kalman_filter/kalman.h index 0d38ebaa7..50621236a 100644 --- a/example/kalman_filter/kalman.h +++ b/example/kalman_filter/kalman.h @@ -212,7 +212,7 @@ struct MP_UNITS_STD_FMT::formatter> { if constexpr (mp_units::Quantity) return t; else - return t.quantity_from_origin(); + return t.quantity_ref_from(t.point_origin); }(kalman::get<0>(e.state)); std::string value_buffer; diff --git a/example/kalman_filter/kalman_filter-example_6.cpp b/example/kalman_filter/kalman_filter-example_6.cpp index ec2954088..23660370e 100644 --- a/example/kalman_filter/kalman_filter-example_6.cpp +++ b/example/kalman_filter/kalman_filter-example_6.cpp @@ -45,7 +45,7 @@ template K> void print(auto iteration, K gain, QP measured, kalman::estimation current, kalman::estimation next) { std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain, - measured.quantity_from_origin(), current, next); + measured.quantity_ref_from(QP::point_origin), current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_7.cpp b/example/kalman_filter/kalman_filter-example_7.cpp index 613a6da7c..d82d73231 100644 --- a/example/kalman_filter/kalman_filter-example_7.cpp +++ b/example/kalman_filter/kalman_filter-example_7.cpp @@ -45,7 +45,7 @@ template K> void print(auto iteration, K gain, QP measured, kalman::estimation current, kalman::estimation next) { std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain, - measured.quantity_from_origin(), current, next); + measured.quantity_ref_from(QP::point_origin), current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_8.cpp b/example/kalman_filter/kalman_filter-example_8.cpp index 081b8507b..ca02b7bdd 100644 --- a/example/kalman_filter/kalman_filter-example_8.cpp +++ b/example/kalman_filter/kalman_filter-example_8.cpp @@ -45,7 +45,7 @@ template K> void print(auto iteration, K gain, QP measured, kalman::estimation current, kalman::estimation next) { std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain, - measured.quantity_from_origin(), current, next); + measured.quantity_ref_from(QP::point_origin), current, next); } int main() diff --git a/example/unmanned_aerial_vehicle.cpp b/example/unmanned_aerial_vehicle.cpp index 0aca9c832..ff83668a0 100644 --- a/example/unmanned_aerial_vehicle.cpp +++ b/example/unmanned_aerial_vehicle.cpp @@ -97,8 +97,8 @@ template hae_altitude to_hae(msl_altitude msl, position pos) { const auto geoid_undulation = - isq::height(GeographicLibWhatsMyOffset(pos.lat.quantity_from_origin().numerical_value_in(si::degree), - pos.lon.quantity_from_origin().numerical_value_in(si::degree)) * + isq::height(GeographicLibWhatsMyOffset(pos.lat.quantity_ref_from(equator).numerical_value_in(si::degree), + pos.lon.quantity_ref_from(prime_meridian).numerical_value_in(si::degree)) * si::metre); return height_above_ellipsoid + (msl - mean_sea_level - geoid_undulation); } @@ -115,7 +115,7 @@ using hal_altitude = quantity_point std::basic_ostream& operator<<(std::basic_ostream& os, const hal_altitude& a) { - return os << a.quantity_from_origin() << " HAL"; + return os << a.quantity_ref_from(height_above_launch) << " HAL"; } template<> @@ -123,7 +123,7 @@ struct MP_UNITS_STD_FMT::formatter : formatter auto format(const hal_altitude& a, FormatContext& ctx) { - formatter::format(a.quantity_from_origin(), ctx); + formatter::format(a.quantity_ref_from(height_above_launch), ctx); return MP_UNITS_STD_FMT::format_to(ctx.out(), " HAL"); } }; diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index d736d2790..ae046af5c 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -115,7 +115,7 @@ class quantity_point { q_([&] { if constexpr (is_same_v, std::remove_const_t>) - return qp.quantity_from_origin(); + return qp.quantity_ref_from(point_origin); else return qp - point_origin; }()) @@ -146,23 +146,39 @@ class quantity_point { // data access #ifdef __cpp_explicit_this_parameter - template - [[nodiscard]] constexpr auto&& quantity_from_origin(this Self&& self) noexcept + template> PO2> + [[nodiscard]] constexpr auto&& quantity_ref_from(this Self&& self, PO2) noexcept { return std::forward(self).q_; } #else - [[nodiscard]] constexpr quantity_type& quantity_from_origin() & noexcept { return q_; } - [[nodiscard]] constexpr const quantity_type& quantity_from_origin() const& noexcept { return q_; } - [[nodiscard]] constexpr quantity_type&& quantity_from_origin() && noexcept { return std::move(q_); } - [[nodiscard]] constexpr const quantity_type&& quantity_from_origin() const&& noexcept { return std::move(q_); } + template> PO2> + [[nodiscard]] constexpr quantity_type& quantity_ref_from(PO2) & noexcept + { + return q_; + } + template> PO2> + [[nodiscard]] constexpr const quantity_type& quantity_ref_from(PO2) const& noexcept + { + return q_; + } + template> PO2> + [[nodiscard]] constexpr quantity_type&& quantity_ref_from(PO2) && noexcept + { + return std::move(q_); + } + template> PO2> + [[nodiscard]] constexpr const quantity_type&& quantity_ref_from(PO2) const&& noexcept + { + return std::move(q_); + } #endif template requires detail::QuantityConvertibleTo{}, Rep>> [[nodiscard]] constexpr quantity_point<::mp_units::reference{}, PO, Rep> in(U) const { - return make_quantity_point(quantity_from_origin().in(U{})); + return make_quantity_point(quantity_ref_from(PO).in(U{})); } // member unary operators @@ -235,9 +251,9 @@ template requires ReferenceOf, PO1.quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point& qp, const quantity& q) - requires requires { qp.quantity_from_origin() + q; } + requires requires { qp.quantity_ref_from(PO1) + q; } { - return make_quantity_point(qp.quantity_from_origin() + q); + return make_quantity_point(qp.quantity_ref_from(PO1) + q); } template @@ -245,7 +261,7 @@ template requires ReferenceOf, PO2.quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator+(const quantity& q, const quantity_point& qp) - requires requires { q + qp.quantity_from_origin(); } + requires requires { q + qp.quantity_ref_from(PO2); } { return qp + q; } @@ -269,9 +285,9 @@ template requires ReferenceOf, PO1.quantity_spec> [[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point& qp, const quantity& q) - requires requires { qp.quantity_from_origin() - q; } + requires requires { qp.quantity_ref_from(PO1) - q; } { - return make_quantity_point(qp.quantity_from_origin() - q); + return make_quantity_point(qp.quantity_ref_from(PO1) - q); } template @@ -285,13 +301,14 @@ template template QP2> [[nodiscard]] constexpr Quantity auto operator-(const QP1& lhs, const QP2& rhs) // TODO consider constraining it for both branches - requires requires { lhs.quantity_from_origin() - rhs.quantity_from_origin(); } + requires requires { lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin); } { if constexpr (is_same_v, std::remove_const_t>) - return lhs.quantity_from_origin() - rhs.quantity_from_origin(); + return lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin); else - return lhs.quantity_from_origin() - rhs.quantity_from_origin() + (lhs.point_origin - rhs.point_origin); + return lhs.quantity_ref_from(QP1::point_origin) - rhs.quantity_ref_from(QP2::point_origin) + + (lhs.point_origin - rhs.point_origin); } template QP> @@ -299,19 +316,21 @@ template QP> [[nodiscard]] constexpr Quantity auto operator-(const QP& qp, PO po) { if constexpr (is_same_v, std::remove_const_t>) - return qp.quantity_from_origin(); + return qp.quantity_ref_from(QP::point_origin); else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin) { if constexpr (is_same_v, std::remove_const_t>) - return qp.quantity_from_origin(); + return qp.quantity_ref_from(QP::point_origin); else - return qp.quantity_from_origin() + (qp.point_origin - qp.absolute_point_origin); + return qp.quantity_ref_from(QP::point_origin) + (qp.point_origin - qp.absolute_point_origin); } else { if constexpr (is_same_v, std::remove_const_t>) - return qp.quantity_from_origin() - po.quantity_point.quantity_from_origin(); + return qp.quantity_ref_from(QP::point_origin) - + po.quantity_point.quantity_ref_from(po.quantity_point.point_origin); else - return qp.quantity_from_origin() - po.quantity_point.quantity_from_origin() + + 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); } } @@ -344,7 +363,7 @@ template QP2> { if constexpr (is_same_v, std::remove_const_t>) - return lhs.quantity_from_origin() <=> rhs.quantity_from_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; } @@ -355,7 +374,7 @@ template QP2> { if constexpr (is_same_v, std::remove_const_t>) - return lhs.quantity_from_origin() == rhs.quantity_from_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; } diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index b86478c3e..559cbd818 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -241,19 +241,26 @@ static_assert( // static member functions //////////////////////////// -static_assert(quantity_point::zero().quantity_from_origin().numerical_value_ref_in(m) == - 0); -static_assert(quantity_point::min().quantity_from_origin().numerical_value_ref_in(m) == - std::numeric_limits::lowest()); -static_assert(quantity_point::max().quantity_from_origin().numerical_value_ref_in(m) == - std::numeric_limits::max()); +static_assert( + quantity_point::zero().quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 0); +static_assert( + quantity_point::min().quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + std::numeric_limits::lowest()); +static_assert( + quantity_point::max().quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + std::numeric_limits::max()); + +static_assert( + quantity_point::zero().quantity_ref_from(ground_level).numerical_value_ref_in(m) == + 0); static_assert( - quantity_point::zero().quantity_from_origin().numerical_value_ref_in(m) == 0); -static_assert(quantity_point::min().quantity_from_origin().numerical_value_ref_in( - m) == std::numeric_limits::lowest()); -static_assert(quantity_point::max().quantity_from_origin().numerical_value_ref_in( - m) == std::numeric_limits::max()); + quantity_point::min().quantity_ref_from(ground_level).numerical_value_ref_in(m) == + std::numeric_limits::lowest()); +static_assert( + quantity_point::max().quantity_ref_from(ground_level).numerical_value_ref_in(m) == + std::numeric_limits::max()); ////////////////////////////// @@ -539,36 +546,42 @@ static_assert( // obtaining a relative quantity ////////////////////////////////// -static_assert((mean_sea_level + 42 * m).quantity_from_origin() == 42 * m); -static_assert((mean_sea_level + isq::height(42 * m)).quantity_from_origin() == 42 * m); +static_assert((mean_sea_level + 42 * m).quantity_ref_from(mean_sea_level) == 42 * m); +static_assert((mean_sea_level + isq::height(42 * m)).quantity_ref_from(mean_sea_level) == 42 * m); -static_assert((zero + 1 * one).quantity_from_origin() == 1 * one); -static_assert((zero + dimensionless(1 * one)).quantity_from_origin() == 1 * one); +static_assert((zero + 1 * one).quantity_ref_from(zero) == 1 * one); +static_assert((zero + dimensionless(1 * one)).quantity_ref_from(zero) == 1 * one); -static_assert((mean_sea_level + 42 * m).quantity_from_origin() == 42 * m); -static_assert((ground_level + 42 * m).quantity_from_origin() == 42 * m); -static_assert((tower_peak + 42 * m).quantity_from_origin() == 42 * m); +static_assert((mean_sea_level + 42 * m).quantity_ref_from(mean_sea_level) == 42 * m); +static_assert((ground_level + 42 * m).quantity_ref_from(ground_level) == 42 * m); +static_assert((tower_peak + 42 * m).quantity_ref_from(tower_peak) == 42 * m); -static_assert(quantity_point(ground_level + 42 * m).quantity_from_origin() == 84 * m); -static_assert(quantity_point(tower_peak + 42 * m).quantity_from_origin() == 126 * m); +static_assert(quantity_point(ground_level + 42 * m).quantity_ref_from(mean_sea_level) == + 84 * m); +static_assert(quantity_point(tower_peak + 42 * m).quantity_ref_from(mean_sea_level) == + 126 * m); -static_assert(quantity_point(mean_sea_level + 84 * m).quantity_from_origin() == 42 * m); -static_assert(quantity_point(tower_peak + 42 * m).quantity_from_origin() == 84 * m); +static_assert(quantity_point(mean_sea_level + 84 * m).quantity_ref_from(ground_level) == + 42 * m); +static_assert(quantity_point(tower_peak + 42 * m).quantity_ref_from(ground_level) == + 84 * m); -static_assert(quantity_point(mean_sea_level + 42 * m).quantity_from_origin() == -42 * m); -static_assert(quantity_point(ground_level + 84 * m).quantity_from_origin() == 42 * m); +static_assert(quantity_point(mean_sea_level + 42 * m).quantity_ref_from(tower_peak) == + -42 * m); +static_assert(quantity_point(ground_level + 84 * m).quantity_ref_from(tower_peak) == + 42 * m); -static_assert((mean_sea_level + 42 * m).point_for(mean_sea_level).quantity_from_origin() == 42 * m); -static_assert((ground_level + 42 * m).point_for(mean_sea_level).quantity_from_origin() == 84 * m); -static_assert((tower_peak + 42 * m).point_for(mean_sea_level).quantity_from_origin() == 126 * m); +static_assert((mean_sea_level + 42 * m).point_for(mean_sea_level).quantity_ref_from(mean_sea_level) == 42 * m); +static_assert((ground_level + 42 * m).point_for(mean_sea_level).quantity_ref_from(mean_sea_level) == 84 * m); +static_assert((tower_peak + 42 * m).point_for(mean_sea_level).quantity_ref_from(mean_sea_level) == 126 * m); -static_assert((ground_level + 84 * m).point_for(ground_level).quantity_from_origin() == 84 * m); -static_assert((mean_sea_level + 84 * m).point_for(ground_level).quantity_from_origin() == 42 * m); -static_assert((tower_peak + 42 * m).point_for(ground_level).quantity_from_origin() == 84 * m); +static_assert((ground_level + 84 * m).point_for(ground_level).quantity_ref_from(ground_level) == 84 * m); +static_assert((mean_sea_level + 84 * m).point_for(ground_level).quantity_ref_from(ground_level) == 42 * m); +static_assert((tower_peak + 42 * m).point_for(ground_level).quantity_ref_from(ground_level) == 84 * m); -static_assert((tower_peak + 42 * m).point_for(tower_peak).quantity_from_origin() == 42 * m); -static_assert((mean_sea_level + 42 * m).point_for(tower_peak).quantity_from_origin() == -42 * m); -static_assert((ground_level + 84 * m).point_for(tower_peak).quantity_from_origin() == 42 * m); +static_assert((tower_peak + 42 * m).point_for(tower_peak).quantity_ref_from(tower_peak) == 42 * m); +static_assert((mean_sea_level + 42 * m).point_for(tower_peak).quantity_ref_from(tower_peak) == -42 * m); +static_assert((ground_level + 84 * m).point_for(tower_peak).quantity_ref_from(tower_peak) == 42 * m); static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(mean_sea_level), quantity_point>); @@ -578,15 +591,15 @@ static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(m // converting to a different unit /////////////////////////////////// -static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); -static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.); -static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); -static_assert((ground_level + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); -static_assert((ground_level + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.); -static_assert((ground_level + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); -static_assert((tower_peak + 2. * km).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); -static_assert((tower_peak + 2. * km).in(m).quantity_from_origin().numerical_value_ref_in(m) == 2000.); -static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin().numerical_value_ref_in(km) == 2.); +static_assert((mean_sea_level + 2. * km).in(km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(km) == 2.); +static_assert((mean_sea_level + 2. * km).in(m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2000.); +static_assert((mean_sea_level + 2000. * m).in(km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(km) == 2.); +static_assert((ground_level + 2. * km).in(km).quantity_ref_from(ground_level).numerical_value_ref_in(km) == 2.); +static_assert((ground_level + 2. * km).in(m).quantity_ref_from(ground_level).numerical_value_ref_in(m) == 2000.); +static_assert((ground_level + 2000. * m).in(km).quantity_ref_from(ground_level).numerical_value_ref_in(km) == 2.); +static_assert((tower_peak + 2. * km).in(km).quantity_ref_from(tower_peak).numerical_value_ref_in(km) == 2.); +static_assert((tower_peak + 2. * km).in(m).quantity_ref_from(tower_peak).numerical_value_ref_in(m) == 2000.); +static_assert((tower_peak + 2000. * m).in(km).quantity_ref_from(tower_peak).numerical_value_ref_in(km) == 2.); #if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2 template typename QP> @@ -618,18 +631,18 @@ static_assert(([]() { quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m}; return l2 = l1; }()) - .quantity_from_origin() == 1 * m); + .quantity_ref_from(mean_sea_level) == 1 * m); static_assert(([]() { const quantity_point l1{mean_sea_level + 1 * m}; quantity_point l2{mean_sea_level + 2 * m}; return l2 = l1; }()) - .quantity_from_origin() == 1 * m); + .quantity_ref_from(mean_sea_level) == 1 * m); static_assert(([]() { quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m}; return l2 = std::move(l1); }()) - .quantity_from_origin() == 1 * m); + .quantity_ref_from(mean_sea_level) == 1 * m); //////////////////// @@ -659,14 +672,14 @@ static_assert([](auto v) { //////////////////////// // same type -static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2); -static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1); +static_assert((mean_sea_level + 1 * m += 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2); +static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1); // different types -static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin().numerical_value_ref_in(m) == 5.5); -static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1123); -static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5); -static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 123); +static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 5.5); +static_assert((mean_sea_level + 123 * m += 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1123); +static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); +static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 123); template typename QP> @@ -938,29 +951,29 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu // check for integral types promotion static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); -static_assert( - ((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m).quantity_from_origin().numerical_value_ref_in(m) == - std::uint8_t(128) + std::uint8_t(128)); -static_assert( - (std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)).quantity_from_origin().numerical_value_ref_in(m) == - std::uint8_t(128) + std::uint8_t(128)); -static_assert( - ((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin().numerical_value_ref_in(m) == - std::uint8_t(0) - std::uint8_t(1)); +static_assert(((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m) + .quantity_ref_from(mean_sea_level) + .numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); +static_assert((std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)) + .quantity_ref_from(mean_sea_level) + .numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); +static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m) + .quantity_ref_from(mean_sea_level) + .numerical_value_ref_in(m) == std::uint8_t(0) - std::uint8_t(1)); static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)) .numerical_value_ref_in(m) == std::uint8_t(0) - std::uint8_t(1)); @@ -1016,32 +1029,42 @@ static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m), static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity>); -static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2); -static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2); -static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1001); -static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1001); -static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1001); -static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1001); -static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1); -static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 999); - -static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5); -static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2.5); -static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); -static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); -static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1501); -static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1501); -static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1.5); -static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin().numerical_value_ref_in(m) == 1499); - -static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 2.5); -static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value_ref_in(m) == 2.5); -static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin().numerical_value_ref_in(m) == 1501); -static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin().numerical_value_ref_in(m) == 1501); -static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); -static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin().numerical_value_ref_in(m) == 1001.5); -static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 0.5); -static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin().numerical_value_ref_in(m) == 998.5); +static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2); +static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2); +static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); +static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); +static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); +static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); +static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1); +static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 999); + +static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); +static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); +static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1001.5); +static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1001.5); +static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1501); +static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1501); +static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1.5); +static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1499); + +static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); +static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); +static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1501); +static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1501); +static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1001.5); +static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 1001.5); +static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 0.5); +static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + 998.5); static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1); static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 999); @@ -1061,15 +1084,15 @@ static_assert((ground_level + 42 * m) - (other_ground_level + 42 * m) == -81 * m static_assert((other_ground_level + 42 * m) - (tower_peak + 42 * m) == 39 * m); static_assert((tower_peak + 42 * m) - (other_ground_level + 42 * m) == -39 * m); -static_assert((mean_sea_level + 42 * m).quantity_from_origin() == 42 * m); -static_assert((42 * m + mean_sea_level).quantity_from_origin() == 42 * m); -static_assert((mean_sea_level - 42 * m).quantity_from_origin() == -42 * m); -static_assert((ground_level + 42 * m).quantity_from_origin() == 42 * m); -static_assert((42 * m + ground_level).quantity_from_origin() == 42 * m); -static_assert((ground_level - 42 * m).quantity_from_origin() == -42 * m); -static_assert((tower_peak + 42 * m).quantity_from_origin() == 42 * m); -static_assert((42 * m + tower_peak).quantity_from_origin() == 42 * m); -static_assert((tower_peak - 42 * m).quantity_from_origin() == -42 * m); +static_assert((mean_sea_level + 42 * m).quantity_ref_from(mean_sea_level) == 42 * m); +static_assert((42 * m + mean_sea_level).quantity_ref_from(mean_sea_level) == 42 * m); +static_assert((mean_sea_level - 42 * m).quantity_ref_from(mean_sea_level) == -42 * m); +static_assert((ground_level + 42 * m).quantity_ref_from(ground_level) == 42 * m); +static_assert((42 * m + ground_level).quantity_ref_from(ground_level) == 42 * m); +static_assert((ground_level - 42 * m).quantity_ref_from(ground_level) == -42 * m); +static_assert((tower_peak + 42 * m).quantity_ref_from(tower_peak) == 42 * m); +static_assert((42 * m + tower_peak).quantity_ref_from(tower_peak) == 42 * m); +static_assert((tower_peak - 42 * m).quantity_ref_from(tower_peak) == -42 * m); static_assert((mean_sea_level + 42 * m) - ground_level == 0 * m); static_assert((ground_level + 42 * m) - mean_sea_level == 84 * m); @@ -1109,17 +1132,17 @@ inline constexpr struct zero_m_per_s : absolute_point_origin // commutativity and associativity static_assert(((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + 5 * isq::speed[m / s]) - .quantity_from_origin() == 10 * isq::speed[m / s]); + .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert((10 * isq::height[m] / (2 * isq::time[s]) + (zero_m_per_s + 5 * isq::speed[m / s])) - .quantity_from_origin() == 10 * isq::speed[m / s]); + .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert(((zero_m_per_s + 5 * isq::speed[m / s]) + 10 * isq::height[m] / (2 * isq::time[s])) - .quantity_from_origin() == 10 * isq::speed[m / s]); + .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert((5 * isq::speed[m / s] + (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s]))) - .quantity_from_origin() == 10 * isq::speed[m / s]); + .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); static_assert(((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - 5 * isq::speed[m / s]) - .quantity_from_origin() == 0 * isq::speed[m / s]); + .quantity_ref_from(zero_m_per_s) == 0 * isq::speed[m / s]); static_assert(((zero_m_per_s + 5 * isq::speed[m / s]) - 10 * isq::height[m] / (2 * isq::time[s])) - .quantity_from_origin() == 0 * isq::speed[m / s]); + .quantity_ref_from(zero_m_per_s) == 0 * isq::speed[m / s]); static_assert((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - (zero_m_per_s + 5 * isq::speed[m / s]) == 0 * isq::speed[m / s]); static_assert((zero_m_per_s + 5 * isq::speed[m / s]) - (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) == @@ -1151,17 +1174,17 @@ static_assert( inline constexpr struct zero_Hz : absolute_point_origin> { } zero_Hz; -static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_from_origin() == +static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_ref_from(zero_Hz) == 10 * isq::frequency[Hz]); -static_assert((10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz])).quantity_from_origin() == +static_assert((10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz])).quantity_ref_from(zero_Hz) == 10 * isq::frequency[Hz]); -static_assert(((zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s])).quantity_from_origin() == +static_assert(((zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s])).quantity_ref_from(zero_Hz) == 10 * isq::frequency[Hz]); -static_assert((5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s]))).quantity_from_origin() == +static_assert((5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s]))).quantity_ref_from(zero_Hz) == 10 * isq::frequency[Hz]); -static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz]).quantity_from_origin() == +static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz]).quantity_ref_from(zero_Hz) == 0 * isq::frequency[Hz]); -static_assert(((zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s])).quantity_from_origin() == +static_assert(((zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s])).quantity_ref_from(zero_Hz) == 0 * isq::frequency[Hz]); static_assert((zero_Hz + 10 / (2 * isq::period_duration[s])) - (zero_Hz + 5 * isq::frequency[Hz]) == 0 * isq::frequency[Hz]); From 40c809091dabecda6fb1860eeda4cf078214fbbd Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 11 Sep 2023 19:36:06 +0200 Subject: [PATCH 03/22] fix: `numerical_value_ref_in` name fixed for this deduction in `quantity` --- src/core/include/mp-units/quantity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 81600158b..0ea996d65 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -145,7 +145,7 @@ class quantity { #ifdef __cpp_explicit_this_parameter template requires(U{} == unit) - [[nodiscard]] constexpr auto&& value_ref_in(this Self&& self, U) noexcept + [[nodiscard]] constexpr auto&& numerical_value_ref_in(this Self&& self, U) noexcept { return std::forward(self).value_; } From 2b2f62d03839d3d9107cd0f1ff1911becdd453dc Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 12 Sep 2023 16:33:02 +0200 Subject: [PATCH 04/22] feat: `force_numerical_value_in(U)` added --- example/conversion_factor.cpp | 2 +- src/core/include/mp-units/quantity.h | 7 ++++ src/utility/include/mp-units/math.h | 36 +++++++++---------- .../unit_test/runtime/linear_algebra_test.cpp | 2 +- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/example/conversion_factor.cpp b/example/conversion_factor.cpp index cd9a4cfbc..4c2330cbc 100644 --- a/example/conversion_factor.cpp +++ b/example/conversion_factor.cpp @@ -33,7 +33,7 @@ template requires std::constructible_from inline constexpr double conversion_factor(Target, Source) { - return mp_units::value_cast(1. * Source::reference).numerical_value_ref_in(Target::unit); + return (1. * Source::reference).force_numerical_value_in(Target::unit); } } // namespace diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 0ea996d65..563cdcd78 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -183,6 +183,13 @@ class quantity { return (*this).in(U{}).numerical_value_ref_in(U{}); } + template + requires requires(quantity q) { value_cast(q); } + [[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept + { + return value_cast(*this).numerical_value_in(U{}); + } + template requires detail::QuantityConvertibleTo> [[nodiscard]] constexpr quantity in(U) const diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index 00b5aff4e..0c7c37f64 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -116,8 +116,8 @@ template auto R, typename Rep> requires { std::exp(q.numerical_value_ref_in(q.unit)); } { using std::exp; - return value_cast(make_quantity(R)>( - static_cast(exp(value_cast(q).numerical_value_ref_in(q.unit))))); + return value_cast( + make_quantity(R)>(static_cast(exp(q.force_numerical_value_in(q.unit))))); } /** @@ -178,8 +178,8 @@ template return make_quantity(R)>( static_cast(floor(q.numerical_value_ref_in(q.unit)))); } else { - return handle_signed_results(make_quantity(R)>( - static_cast(floor(value_cast(q).numerical_value_ref_in(To))))); + return handle_signed_results( + make_quantity(R)>(static_cast(floor(q.force_numerical_value_in(To))))); } } else { if constexpr (To == get_unit(R)) { @@ -218,8 +218,8 @@ template return make_quantity(R)>( static_cast(ceil(q.numerical_value_ref_in(q.unit)))); } else { - return handle_signed_results(make_quantity(R)>( - static_cast(ceil(value_cast(q).numerical_value_ref_in(To))))); + return handle_signed_results( + make_quantity(R)>(static_cast(ceil(q.force_numerical_value_in(To))))); } } else { if constexpr (To == get_unit(R)) { @@ -327,7 +327,7 @@ template auto R, typename Rep> using std::sin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(sin(value_cast(q).numerical_value_in(si::radian))); + using rep = decltype(sin(q.force_numerical_value_in(si::radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(sin(value_cast(q).numerical_value_in(si::radian))); } else @@ -342,7 +342,7 @@ template auto R, typename Rep> using std::cos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(cos(value_cast(q).numerical_value_in(si::radian))); + using rep = decltype(cos(q.force_numerical_value_in(si::radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(cos(value_cast(q).numerical_value_in(si::radian))); } else @@ -357,7 +357,7 @@ template auto R, typename Rep> using std::tan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(tan(value_cast(q).numerical_value_in(si::radian))); + using rep = decltype(tan(q.force_numerical_value_in(si::radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(tan(value_cast(q).numerical_value_in(si::radian))); } else @@ -372,7 +372,7 @@ template auto R, typename Rep> using std::asin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(asin(value_cast(q).numerical_value_in(one))); + using rep = decltype(asin(q.force_numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(asin(value_cast(q).numerical_value_in(one))); } else @@ -387,7 +387,7 @@ template auto R, typename Rep> using std::acos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(acos(value_cast(q).numerical_value())); + using rep = decltype(acos(q.force_numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(acos(value_cast(q).numerical_value_in(one))); } else @@ -402,7 +402,7 @@ template auto R, typename Rep> using std::atan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(atan(value_cast(q).numerical_value_in(one))); + using rep = decltype(atan(q.force_numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(atan(value_cast(q).numerical_value_in(one))); } else @@ -421,7 +421,7 @@ template auto R, typename Rep> using std::sin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(sin(value_cast(q).numerical_value_in(radian))); + using rep = decltype(sin(q.force_numerical_value_in(radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(sin(value_cast(q).numerical_value_in(radian))); } else @@ -436,7 +436,7 @@ template auto R, typename Rep> using std::cos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(cos(value_cast(q).numerical_value_in(radian))); + using rep = decltype(cos(q.force_numerical_value_in(radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(cos(value_cast(q).numerical_value_in(radian))); } else @@ -451,7 +451,7 @@ template auto R, typename Rep> using std::tan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(tan(value_cast(q).numerical_value_in(radian))); + using rep = decltype(tan(q.force_numerical_value_in(radian))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(tan(value_cast(q).numerical_value_in(radian))); } else @@ -466,7 +466,7 @@ template auto R, typename Rep> using std::asin; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(asin(value_cast(q).numerical_value_in(one))); + using rep = decltype(asin(q.force_numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(asin(value_cast(q).numerical_value_in(one))); } else @@ -481,7 +481,7 @@ template auto R, typename Rep> using std::acos; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(acos(value_cast(q).numerical_value_in(one))); + using rep = decltype(acos(q.force_numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(acos(value_cast(q).numerical_value_in(one))); } else @@ -496,7 +496,7 @@ template auto R, typename Rep> using std::atan; if constexpr (!treat_as_floating_point) { // check what is the return type when called with the integral value - using rep = decltype(atan(value_cast(q).numerical_value_in(one))); + using rep = decltype(atan(q.force_numerical_value_in(one))); // use this type ahead of calling the function to prevent narrowing if a unit conversion is needed return make_quantity(atan(value_cast(q).numerical_value_in(one))); } else diff --git a/test/unit_test/runtime/linear_algebra_test.cpp b/test/unit_test/runtime/linear_algebra_test.cpp index 8d2cd1e7d..b9bd1a542 100644 --- a/test/unit_test/runtime/linear_algebra_test.cpp +++ b/test/unit_test/runtime/linear_algebra_test.cpp @@ -93,7 +93,7 @@ TEST_CASE("vector quantity", "[la]") SECTION("truncating") { const auto v = vector{1001, 1002, 1003} * isq::position_vector[m]; - CHECK(value_cast(v).numerical_value_ref_in(km) == vector{1, 1, 1}); + CHECK(v.force_numerical_value_in(km) == vector{1, 1, 1}); } } From 1c7928021d75b57a738dd012a487621867609d5e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 10:18:07 +0200 Subject: [PATCH 05/22] feat: `force_in(U)` support added --- src/core/include/mp-units/quantity.h | 21 ++++++++++++++------- test/unit_test/static/quantity_test.cpp | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 563cdcd78..1e07a43ec 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -141,6 +141,20 @@ class quantity { quantity& operator=(const quantity&) = default; quantity& operator=(quantity&&) = default; + // conversions + template + requires detail::QuantityConvertibleTo> + [[nodiscard]] constexpr quantity in(U) const + { + return quantity{*this}; + } + template + requires requires(quantity q) { value_cast(q); } + [[nodiscard]] constexpr quantity force_in(U) const + { + return value_cast(*this); + } + // data access #ifdef __cpp_explicit_this_parameter template @@ -190,13 +204,6 @@ class quantity { return value_cast(*this).numerical_value_in(U{}); } - template - requires detail::QuantityConvertibleTo> - [[nodiscard]] constexpr quantity in(U) const - { - return quantity{*this}; - } - // member unary operators [[nodiscard]] constexpr Quantity auto operator+() const requires requires(rep v) { diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 83c43c969..3d04f7546 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -900,6 +900,10 @@ static_assert(value_cast(2000 * m).numerical_value_ref_in(km) == 2); static_assert(value_cast(1.23 * m).numerical_value_ref_in(m) == 1); static_assert(value_cast(2000.0 * m / (3600.0 * s)).numerical_value_ref_in(km / h) == 2); +static_assert((2 * km).force_in(m).numerical_value_ref_in(m) == 2000); +static_assert((2000 * m).force_in(km).numerical_value_ref_in(km) == 2); +static_assert((2000.0 * m / (3600.0 * s)).force_in(km / h).numerical_value_ref_in(km / h) == 2); + ////////////////// // quantity_cast ////////////////// From f7f63e8c4cf1e59ffdfcfdb4ab70a854cc00308b Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 10:41:15 +0200 Subject: [PATCH 06/22] refactor: `force_numerical_value_in` refactored to use `force_in` in the implemenation and constraints --- src/core/include/mp-units/quantity.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 1e07a43ec..de70bec6b 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -198,10 +198,10 @@ class quantity { } template - requires requires(quantity q) { value_cast(q); } + requires requires(quantity q) { q.force_in(U{}); } [[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept { - return value_cast(*this).numerical_value_in(U{}); + return (*this).force_in(U{}).numerical_value_ref_in(U{}); } // member unary operators From a6284aa2937008f16f2447db9c9c851750f98416 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 10:43:08 +0200 Subject: [PATCH 07/22] refactor: some `value_cast(q)` replaced with `q.force_in(U)` --- example/avg_speed.cpp | 10 +++++----- example/glide_computer.cpp | 4 ++-- example/total_energy.cpp | 2 +- src/utility/include/mp-units/math.h | 14 +++++++------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/example/avg_speed.cpp b/example/avg_speed.cpp index e9ef5e012..c59bacb7f 100644 --- a/example/avg_speed.cpp +++ b/example/avg_speed.cpp @@ -56,7 +56,7 @@ constexpr QuantityOf auto avg_speed(QuantityOf auto d, template D, QuantityOf T, QuantityOf V> void print_result(D distance, T duration, V speed) { - const auto result_in_kmph = value_cast / non_si::hour>(speed); + const auto result_in_kmph = speed.force_in(si::kilo / non_si::hour); std::cout << "Average speed of a car that makes " << distance << " in " << duration << " is " << result_in_kmph << ".\n"; } @@ -101,7 +101,7 @@ void example() // it is not possible to make a lossless conversion of miles to meters on an integral type // (explicit cast needed) - print_result(distance, duration, fixed_int_si_avg_speed(value_cast(distance), duration)); + print_result(distance, duration, fixed_int_si_avg_speed(distance.force_in(m), duration)); print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); print_result(distance, duration, avg_speed(distance, duration)); } @@ -119,7 +119,7 @@ void example() // also it is not possible to make a lossless conversion of miles to meters on an integral type // (explicit cast needed) print_result(distance, duration, - fixed_int_si_avg_speed(value_cast(value_cast(distance)), value_cast(duration))); + fixed_int_si_avg_speed(value_cast(distance.force_in(m)), value_cast(duration))); print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); print_result(distance, duration, avg_speed(distance, duration)); } @@ -133,7 +133,7 @@ void example() // it is not possible to make a lossless conversion of centimeters to meters on an integral type // (explicit cast needed) - print_result(distance, duration, fixed_int_si_avg_speed(value_cast(distance), duration)); + print_result(distance, duration, fixed_int_si_avg_speed(distance.force_in(m), duration)); print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); print_result(distance, duration, avg_speed(distance, duration)); } @@ -149,7 +149,7 @@ void example() // it is not possible to make a lossless conversion of centimeters to meters on an integral type // (explicit cast needed) print_result(distance, duration, - fixed_int_si_avg_speed(value_cast(value_cast(distance)), value_cast(duration))); + fixed_int_si_avg_speed(value_cast(distance.force_in(m)), value_cast(duration))); print_result(distance, duration, fixed_double_si_avg_speed(distance, duration)); print_result(distance, duration, avg_speed(distance, duration)); diff --git a/example/glide_computer.cpp b/example/glide_computer.cpp index 51486f8b6..69231828b 100644 --- a/example/glide_computer.cpp +++ b/example/glide_computer.cpp @@ -83,12 +83,12 @@ void print(const R& gliders) std::cout << "- Name: " << g.name << "\n"; std::cout << "- Polar:\n"; for (const auto& p : g.polar) { - const auto ratio = value_cast(glide_ratio(g.polar[0])); + const auto ratio = glide_ratio(g.polar[0]).force_in(one); std::cout << MP_UNITS_STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q} ({:%.1Q %q})\n", p.climb, p.v, ratio, // TODO is it possible to make ADL work below (we need another set of trig // functions for strong angle in a different namespace) - value_cast(isq::asin(1 / ratio))); + isq::asin(1 / ratio).force_in(si::degree)); } std::cout << "\n"; } diff --git a/example/total_energy.cpp b/example/total_energy.cpp index 9d6a9f8b6..fa83a6cd7 100644 --- a/example/total_energy.cpp +++ b/example/total_energy.cpp @@ -80,7 +80,7 @@ void si_example() << "E = " << E3 << "\n"; std::cout << "\n[converted from SI units back to GeV]\n" - << "E = " << value_cast(E3) << "\n"; + << "E = " << E3.force_in(GeV) << "\n"; } void natural_example() diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index 0c7c37f64..77c8afcd9 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -162,7 +162,7 @@ template requires { std::floor(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { - ::mp_units::value_cast(q); + q.force_in(To); quantity_values::one(); }) { @@ -183,9 +183,9 @@ template } } else { if constexpr (To == get_unit(R)) { - return value_cast(q); + return q.force_in(To); } else { - return handle_signed_results(value_cast(q)); + return handle_signed_results(q.force_in(To)); } } } @@ -202,7 +202,7 @@ template requires { std::ceil(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { - ::mp_units::value_cast(q); + q.force_in(To); quantity_values::one(); }) { @@ -223,9 +223,9 @@ template } } else { if constexpr (To == get_unit(R)) { - return value_cast(q); + return q.force_in(To); } else { - return handle_signed_results(value_cast(q)); + return handle_signed_results(q.force_in(To)); } } } @@ -254,7 +254,7 @@ template return make_quantity(R)>( static_cast(round(q.numerical_value_ref_in(q.unit)))); } else { - return value_cast(q); + return q.force_in(To); } } else { const auto res_low = mp_units::floor(q); From bf954cfcaff69df920f184b657ad4e2120a74327 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 10:44:50 +0200 Subject: [PATCH 08/22] docs: `q.force_in(U)` documentation added --- docs/users_guide/framework_basics/generic_interfaces.md | 4 ++-- docs/users_guide/framework_basics/text_output.md | 4 ++-- docs/users_guide/framework_basics/value_conversions.md | 8 +++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/users_guide/framework_basics/generic_interfaces.md b/docs/users_guide/framework_basics/generic_interfaces.md index 3dfbdfc39..df4cc98fc 100644 --- a/docs/users_guide/framework_basics/generic_interfaces.md +++ b/docs/users_guide/framework_basics/generic_interfaces.md @@ -65,11 +65,11 @@ some issues start to be clearly visible: Trying to use an integral type in this scenario will work only for `s1`, while `s2` and `s3` will fail to compile. Failing to compile is a good thing here as the library tries to prevent the user from doing a clearly wrong thing. To make the code compile, the user needs to use - a dedicated [`value_cast`](value_conversions.md#value-truncating-conversions) like this: + dedicated [`value_cast` or `force_in`](value_conversions.md#value-truncating-conversions) like this: ```cpp quantity s2 = avg_speed(value_cast(140 * mi), 2 * h); - quantity s3 = avg_speed(value_cast(20 * m), value_cast(2 * s)); + quantity s3 = avg_speed((20 * m).force_in(km), (2 * s).force_in(h)); ``` but the above will obviously provide an incorrect behavior (i.e. division by `0` in the evaluation diff --git a/docs/users_guide/framework_basics/text_output.md b/docs/users_guide/framework_basics/text_output.md index d78996680..3f961b4ad 100644 --- a/docs/users_guide/framework_basics/text_output.md +++ b/docs/users_guide/framework_basics/text_output.md @@ -73,8 +73,8 @@ associated with this quantity. before passing it to the text output: ```cpp - std::cout << v1.in(km / h) << '\n'; // 110 km/h - std::cout << value_cast(v1) << '\n'; // 30.5556 m/s + std::cout << v1.in(km / h) << '\n'; // 110 km/h + std::cout << v1.force_in(m / s) << '\n'; // 30.5556 m/s ``` diff --git a/docs/users_guide/framework_basics/value_conversions.md b/docs/users_guide/framework_basics/value_conversions.md index 5dd8b111b..978f7d294 100644 --- a/docs/users_guide/framework_basics/value_conversions.md +++ b/docs/users_guide/framework_basics/value_conversions.md @@ -59,12 +59,18 @@ The second solution is to force a truncating conversion: ```cpp auto q1 = 5 * m; std::cout << value_cast(q1) << '\n'; -quantity, int> q2 = value_cast(q1); +quantity, int> q2 = q1.force_in(km); ``` This explicit cast makes it clear that something unsafe is going on. It is easy to spot in code reviews or while chasing a bug in the source code. +!!! note + + `q.force_in(U)` is just a shortcut to run `value_cast(q)`. There is no difference in behavior + between those two interfaces. `q.force_in(U)` was added for consistency with `q.in(U)` and + `q.force_numerical_value_in(U)`. + Another place where this cast is useful is when a user wants to convert a quantity with a floating-point representation to the one using an integral one. Again this is a truncating conversion, so an explicit cast is needed: From 414f1d1007ebed513013affb0cc51ac60af75c5d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 11:26:55 +0200 Subject: [PATCH 09/22] style: additional whitespace removed from `conversion_factor` example --- example/conversion_factor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/example/conversion_factor.cpp b/example/conversion_factor.cpp index 4c2330cbc..5a4eaa97a 100644 --- a/example/conversion_factor.cpp +++ b/example/conversion_factor.cpp @@ -58,6 +58,5 @@ int main() << MP_UNITS_STD_FMT::format("lengthB.value( {} ) == lengthA.value( {} ) * conversion_factor( {} )\n", lengthB.numerical_value_ref_in(lengthB.unit), lengthA.numerical_value_ref_in(lengthA.unit), - conversion_factor(lengthB, lengthA)); } From 6c576d7120ab27b0d4970cd46308e5800e90f32d Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 11:27:56 +0200 Subject: [PATCH 10/22] style: another whitespace removed from the `currency` example --- example/currency.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/example/currency.cpp b/example/currency.cpp index 070ee4682..62ae32e9b 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -81,11 +81,9 @@ quantity exchange_to(quantity q) template auto To, ReferenceOf auto From, auto PO, typename Rep> quantity_point exchange_to(quantity_point q) { - return quantity_point{zero + - - static_cast(exchange_rate() * - (q - q.absolute_point_origin).numerical_value_ref_in(q.unit)) * - To}; + return quantity_point{zero + static_cast(exchange_rate() * + (q - q.absolute_point_origin).numerical_value_ref_in(q.unit)) * + To}; } int main() From 75fc3a038466963966dfd1078d3d3d25cc8a5447 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 11:56:06 +0200 Subject: [PATCH 11/22] style: more whitespace issues caused by rebase fixed --- src/core/include/mp-units/quantity.h | 1 + src/utility/include/mp-units/math.h | 4 ---- test/unit_test/runtime/distribution_test.cpp | 12 ++++-------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index de70bec6b..dd694342c 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -148,6 +148,7 @@ class quantity { { return quantity{*this}; } + template requires requires(quantity q) { value_cast(q); } [[nodiscard]] constexpr quantity force_in(U) const diff --git a/src/utility/include/mp-units/math.h b/src/utility/include/mp-units/math.h index 77c8afcd9..7bdf71893 100644 --- a/src/utility/include/mp-units/math.h +++ b/src/utility/include/mp-units/math.h @@ -159,7 +159,6 @@ template template [[nodiscard]] constexpr quantity(R), Rep> floor(const quantity& q) noexcept requires((!treat_as_floating_point) || requires { floor(q.numerical_value_ref_in(q.unit)); } || - requires { std::floor(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { q.force_in(To); @@ -199,7 +198,6 @@ template template [[nodiscard]] constexpr quantity(R), Rep> ceil(const quantity& q) noexcept requires((!treat_as_floating_point) || requires { ceil(q.numerical_value_ref_in(q.unit)); } || - requires { std::ceil(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { q.force_in(To); @@ -241,7 +239,6 @@ template template [[nodiscard]] constexpr quantity(R), Rep> round(const quantity& q) noexcept requires((!treat_as_floating_point) || requires { round(q.numerical_value_ref_in(q.unit)); } || - requires { std::round(q.numerical_value_ref_in(q.unit)); }) && (To == get_unit(R) || requires { ::mp_units::floor(q); @@ -284,7 +281,6 @@ template requires requires { common_reference(R1, R2); } && ( requires { hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit)); } || - requires { std::hypot(x.numerical_value_ref_in(x.unit), y.numerical_value_ref_in(y.unit)); }) { constexpr auto ref = common_reference(R1, R2); diff --git a/test/unit_test/runtime/distribution_test.cpp b/test/unit_test/runtime/distribution_test.cpp index bbf7c5ef9..5b14ae7f1 100644 --- a/test/unit_test/runtime/distribution_test.cpp +++ b/test/unit_test/runtime/distribution_test.cpp @@ -559,10 +559,8 @@ TEST_CASE("piecewise_constant_distribution") 3.0 * isq::length[si::metre]}; auto stl_dist = std::piecewise_constant_distribution(intervals_rep, [](rep val) { return val; }); - auto units_dist = - - mp_units::piecewise_constant_distribution(intervals_qty, - [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); + auto units_dist = mp_units::piecewise_constant_distribution( + intervals_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); @@ -629,10 +627,8 @@ TEST_CASE("piecewise_linear_distribution") 3.0 * isq::length[si::metre]}; auto stl_dist = std::piecewise_linear_distribution(intervals_rep, [](rep val) { return val; }); - auto units_dist = - - mp_units::piecewise_linear_distribution(intervals_qty, - [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); + auto units_dist = mp_units::piecewise_linear_distribution( + intervals_qty, [](q qty) { return qty.numerical_value_ref_in(qty.unit); }); CHECK(units_dist.intervals() == intervals_qty_vec); CHECK(units_dist.densities() == stl_dist.densities()); From e085beef409e19c8d417196b4c244907c13cda51 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 11:57:22 +0200 Subject: [PATCH 12/22] feat: `qp.quantity_from(PO)` added --- example/currency.cpp | 4 ++-- example/include/geographic.h | 24 +++++++++---------- example/unmanned_aerial_vehicle.cpp | 8 +++---- src/core/include/mp-units/quantity_point.h | 7 ++++++ test/unit_test/static/quantity_point_test.cpp | 11 +++++++++ 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/example/currency.cpp b/example/currency.cpp index 62ae32e9b..ae3267663 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -91,6 +91,6 @@ int main() quantity_point price_usd = zero + 100 * us_dollar; quantity_point price_euro = exchange_to(price_usd); - std::cout << price_usd.quantity_ref_from(zero) << " -> " << price_euro.quantity_ref_from(zero) << "\n"; - // std::cout << price_usd.quantity_ref_from(zero) + price_euro.quantity_ref_from(zero) << "\n"; // does not compile + std::cout << price_usd.quantity_from(zero) << " -> " << price_euro.quantity_from(zero) << "\n"; + // std::cout << price_usd.quantity_from(zero) + price_euro.quantity_from(zero) << "\n"; // does not compile } diff --git a/example/include/geographic.h b/example/include/geographic.h index 3f5d77ca3..c422fa760 100644 --- a/example/include/geographic.h +++ b/example/include/geographic.h @@ -138,7 +138,7 @@ struct MP_UNITS_STD_FMT::formatter> : auto format(geographic::latitude lat, FormatContext& ctx) { formatter::quantity_type>::format( - is_gt_zero(lat) ? lat.quantity_ref_from(geographic::equator) : -lat.quantity_ref_from(geographic::equator), ctx); + is_gt_zero(lat) ? lat.quantity_from(geographic::equator) : -lat.quantity_from(geographic::equator), ctx); MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lat) ? " N" : "S"); return ctx.out(); } @@ -151,8 +151,7 @@ struct MP_UNITS_STD_FMT::formatter> : auto format(geographic::longitude lon, FormatContext& ctx) { formatter::quantity_type>::format( - is_gt_zero(lon) ? lon.quantity_ref_from(geographic::prime_meridian) - : -lon.quantity_ref_from(geographic::prime_meridian), + is_gt_zero(lon) ? lon.quantity_from(geographic::prime_meridian) : -lon.quantity_from(geographic::prime_meridian), ctx); MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lon) ? " E" : " W"); return ctx.out(); @@ -173,28 +172,29 @@ template distance spherical_distance(position from, position to) { using namespace mp_units; - constexpr auto earth_radius = 6'371 * isq::radius[si::kilo]; + constexpr quantity earth_radius = 6'371 * isq::radius[si::kilo]; using isq::sin, isq::cos, isq::asin, isq::acos; - const auto& from_lat = from.lat.quantity_ref_from(equator); - const auto& from_lon = from.lon.quantity_ref_from(prime_meridian); - const auto& to_lat = to.lat.quantity_ref_from(equator); - const auto& to_lon = to.lon.quantity_ref_from(prime_meridian); + const quantity from_lat = from.lat.quantity_from(equator); + const quantity from_lon = from.lon.quantity_from(prime_meridian); + const quantity to_lat = to.lat.quantity_from(equator); + const quantity to_lon = to.lon.quantity_from(prime_meridian); // https://en.wikipedia.org/wiki/Great-circle_distance#Formulae if constexpr (sizeof(T) >= 8) { // spherical law of cosines - const auto central_angle = acos(sin(from_lat) * sin(to_lat) + cos(from_lat) * cos(to_lat) * cos(to_lon - from_lon)); + const quantity central_angle = + acos(sin(from_lat) * sin(to_lat) + cos(from_lat) * cos(to_lat) * cos(to_lon - from_lon)); // const auto central_angle = 2 * asin(sqrt(0.5 - cos(to_lat - from_lat) / 2 + cos(from_lat) * cos(to_lat) * (1 // - cos(lon2_rad - from_lon)) / 2)); return quantity_cast(earth_radius * central_angle); } else { // the haversine formula - const auto sin_lat = sin((to_lat - from_lat) / 2); - const auto sin_lon = sin((to_lon - from_lon) / 2); - const auto central_angle = 2 * asin(sqrt(sin_lat * sin_lat + cos(from_lat) * cos(to_lat) * sin_lon * sin_lon)); + const quantity sin_lat = sin((to_lat - from_lat) / 2); + const quantity sin_lon = sin((to_lon - from_lon) / 2); + const quantity central_angle = 2 * asin(sqrt(sin_lat * sin_lat + cos(from_lat) * cos(to_lat) * sin_lon * sin_lon)); return quantity_cast(earth_radius * central_angle); } diff --git a/example/unmanned_aerial_vehicle.cpp b/example/unmanned_aerial_vehicle.cpp index ff83668a0..f880ba567 100644 --- a/example/unmanned_aerial_vehicle.cpp +++ b/example/unmanned_aerial_vehicle.cpp @@ -97,8 +97,8 @@ template hae_altitude to_hae(msl_altitude msl, position pos) { const auto geoid_undulation = - isq::height(GeographicLibWhatsMyOffset(pos.lat.quantity_ref_from(equator).numerical_value_in(si::degree), - pos.lon.quantity_ref_from(prime_meridian).numerical_value_in(si::degree)) * + isq::height(GeographicLibWhatsMyOffset(pos.lat.quantity_from(equator).numerical_value_in(si::degree), + pos.lon.quantity_from(prime_meridian).numerical_value_in(si::degree)) * si::metre); return height_above_ellipsoid + (msl - mean_sea_level - geoid_undulation); } @@ -115,7 +115,7 @@ using hal_altitude = quantity_point std::basic_ostream& operator<<(std::basic_ostream& os, const hal_altitude& a) { - return os << a.quantity_ref_from(height_above_launch) << " HAL"; + return os << a.quantity_from(height_above_launch) << " HAL"; } template<> @@ -123,7 +123,7 @@ struct MP_UNITS_STD_FMT::formatter : formatter auto format(const hal_altitude& a, FormatContext& ctx) { - formatter::format(a.quantity_ref_from(height_above_launch), ctx); + formatter::format(a.quantity_from(height_above_launch), ctx); return MP_UNITS_STD_FMT::format_to(ctx.out(), " HAL"); } }; diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index ae046af5c..99db2d97f 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -174,6 +174,13 @@ class quantity_point { } #endif + template + requires requires { quantity_point{} - PO2{}; } + [[nodiscard]] constexpr Quantity auto quantity_from(PO2) const + { + return *this - PO2{}; + } + template requires detail::QuantityConvertibleTo{}, Rep>> [[nodiscard]] constexpr quantity_point<::mp_units::reference{}, PO, Rep> in(U) const diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 559cbd818..7805b2c1f 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -1105,6 +1105,17 @@ static_assert((ground_level + 42 * m) - other_ground_level == -39 * m); static_assert((other_ground_level + 42 * m) - tower_peak == 81 * m); static_assert((tower_peak + 42 * m) - other_ground_level == 3 * m); +static_assert((mean_sea_level + 42 * m).quantity_from(ground_level) == 0 * m); +static_assert((ground_level + 42 * m).quantity_from(mean_sea_level) == 84 * m); +static_assert((tower_peak + 42 * m).quantity_from(ground_level) == 84 * m); +static_assert((ground_level + 42 * m).quantity_from(tower_peak) == 0 * m); +static_assert((tower_peak + 42 * m).quantity_from(mean_sea_level) == 126 * m); +static_assert((mean_sea_level + 42 * m).quantity_from(tower_peak) == -42 * m); +static_assert((other_ground_level + 42 * m).quantity_from(ground_level) == 123 * m); +static_assert((ground_level + 42 * m).quantity_from(other_ground_level) == -39 * m); +static_assert((other_ground_level + 42 * m).quantity_from(tower_peak) == 81 * m); +static_assert((tower_peak + 42 * m).quantity_from(other_ground_level) == 3 * m); + static_assert(mean_sea_level - (ground_level + 42 * m) == -84 * m); static_assert(ground_level - (mean_sea_level + 42 * m) == 0 * m); static_assert(tower_peak - (ground_level + 42 * m) == 0 * m); From 0e974a7f32bdda938735f1c2d70bc8f5a75edbd5 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 12:21:17 +0200 Subject: [PATCH 13/22] fix: hacks for clang-16 compilation added --- src/core/include/mp-units/unit.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/include/mp-units/unit.h b/src/core/include/mp-units/unit.h index 98adfa068..a15b0f7ca 100644 --- a/src/core/include/mp-units/unit.h +++ b/src/core/include/mp-units/unit.h @@ -402,7 +402,7 @@ using type_list_of_unit_less = expr_less; * Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned. */ template -[[nodiscard]] consteval Unit auto operator*(M mag, const U u) +[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M mag, const U u) { if constexpr (mag == mp_units::mag<1>) return u; @@ -418,7 +418,7 @@ template * to the derived unit and the magnitude remains outside forming another scaled unit as a result of the operation. */ template -[[nodiscard]] consteval Unit auto operator*(Lhs lhs, Rhs rhs) +[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs) { if constexpr (detail::is_specialization_of_scaled_unit && detail::is_specialization_of_scaled_unit) return (Lhs::mag * Rhs::mag) * (Lhs::reference_unit * Rhs::reference_unit); @@ -436,7 +436,7 @@ template * to the derived unit and the magnitude remains outside forming another scaled unit as a result of the operation. */ template -[[nodiscard]] consteval Unit auto operator/(Lhs lhs, Rhs rhs) +[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs) { if constexpr (detail::is_specialization_of_scaled_unit && detail::is_specialization_of_scaled_unit) return (Lhs::mag / Rhs::mag) * (Lhs::reference_unit / Rhs::reference_unit); From 2e1a0173769d27ccafa9757e41dd2cd75ca4ff1b Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 16:21:57 +0200 Subject: [PATCH 14/22] refactor: `quantity::_value` data member renamed to `numerical_value_` --- src/core/include/mp-units/quantity.h | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index dd694342c..88d6a43fb 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -85,7 +85,7 @@ using common_quantity_for = quantity Rep = double> class quantity { public: - Rep value_; // needs to be public for a structural type + Rep numerical_value_; // needs to be public for a structural type // member types and values static constexpr Reference auto reference = R; @@ -126,7 +126,7 @@ class quantity { template Q> constexpr explicit(!std::convertible_to) quantity(const Q& q) : - value_(detail::sudo_cast(q).numerical_value_ref_in(unit)) + numerical_value_(detail::sudo_cast(q).numerical_value_ref_in(unit)) { } @@ -162,32 +162,32 @@ class quantity { requires(U{} == unit) [[nodiscard]] constexpr auto&& numerical_value_ref_in(this Self&& self, U) noexcept { - return std::forward(self).value_; + return std::forward(self).numerical_value_; } #else template requires(U{} == unit) [[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept { - return value_; + return numerical_value_; } template requires(U{} == unit) [[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept { - return value_; + return numerical_value_; } template requires(U{} == unit) [[nodiscard]] constexpr rep&& numerical_value_ref_in(U) && noexcept { - return std::move(value_); + return std::move(numerical_value_); } template requires(U{} == unit) [[nodiscard]] constexpr const rep&& numerical_value_ref_in(U) const&& noexcept { - return std::move(value_); + return std::move(numerical_value_); } #endif @@ -233,7 +233,7 @@ class quantity { } -> std::same_as; } { - ++value_; + ++numerical_value_; return *this; } @@ -244,7 +244,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(value_++); + return make_quantity(numerical_value_++); } constexpr quantity& operator--() @@ -254,7 +254,7 @@ class quantity { } -> std::same_as; } { - --value_; + --numerical_value_; return *this; } @@ -265,7 +265,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(value_--); + return make_quantity(numerical_value_--); } // compound assignment operators @@ -276,7 +276,7 @@ class quantity { } -> std::same_as; } { - value_ += q.numerical_value_ref_in(unit); + numerical_value_ += q.numerical_value_ref_in(unit); return *this; } @@ -287,7 +287,7 @@ class quantity { } -> std::same_as; } { - value_ -= q.numerical_value_ref_in(unit); + numerical_value_ -= q.numerical_value_ref_in(unit); return *this; } @@ -299,7 +299,7 @@ class quantity { } { gsl_ExpectsAudit(q != zero()); - value_ %= q.numerical_value_ref_in(unit); + numerical_value_ %= q.numerical_value_ref_in(unit); return *this; } @@ -311,7 +311,7 @@ class quantity { } constexpr quantity& operator*=(const Value& v) { - value_ *= v; + numerical_value_ *= v; return *this; } @@ -323,7 +323,7 @@ class quantity { } constexpr quantity& operator*=(const Q& rhs) { - value_ *= rhs.numerical_value_ref_in(::mp_units::one); + numerical_value_ *= rhs.numerical_value_ref_in(::mp_units::one); return *this; } @@ -336,7 +336,7 @@ class quantity { constexpr quantity& operator/=(const Value& v) { gsl_ExpectsAudit(v != quantity_values::zero()); - value_ /= v; + numerical_value_ /= v; return *this; } @@ -349,7 +349,7 @@ class quantity { constexpr quantity& operator/=(const Q& rhs) { gsl_ExpectsAudit(rhs != rhs.zero()); - value_ /= rhs.numerical_value_ref_in(::mp_units::one); + numerical_value_ /= rhs.numerical_value_ref_in(::mp_units::one); return *this; } @@ -363,7 +363,7 @@ class quantity { template requires std::constructible_from - constexpr explicit quantity(Value&& v) : value_(std::forward(v)) + constexpr explicit quantity(Value&& v) : numerical_value_(std::forward(v)) { } }; From f74da4335b264beadb2f3cd937ba84abc6f9cb66 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 18:28:49 +0200 Subject: [PATCH 15/22] refactor: `quantity_point::q_` renamed to `quantity_from_origin_` --- src/core/include/mp-units/quantity_point.h | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 99db2d97f..1972ea301 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -82,7 +82,7 @@ class quantity_point { using rep = Rep; using quantity_type = quantity; - quantity_type q_; // needs to be public for a structural type + quantity_type quantity_from_origin_; // needs to be public for a structural type // static member functions [[nodiscard]] static constexpr quantity_point zero() noexcept @@ -112,7 +112,7 @@ class quantity_point { requires std::constructible_from // TODO add perfect forwarding constexpr explicit(!std::convertible_to) quantity_point(const QP& qp) : - q_([&] { + quantity_from_origin_([&] { if constexpr (is_same_v, std::remove_const_t>) return qp.quantity_ref_from(point_origin); @@ -128,7 +128,8 @@ class quantity_point { std::convertible_to< quantity::reference, typename quantity_point_like_traits::rep>, quantity_type> - constexpr explicit quantity_point(const QP& qp) : q_(quantity_point_like_traits::quantity_from_origin(qp)) + constexpr explicit quantity_point(const QP& qp) : + quantity_from_origin_(quantity_point_like_traits::quantity_from_origin(qp)) { } @@ -149,28 +150,28 @@ class quantity_point { template> PO2> [[nodiscard]] constexpr auto&& quantity_ref_from(this Self&& self, PO2) noexcept { - return std::forward(self).q_; + return std::forward(self).quantity_from_origin_; } #else template> PO2> [[nodiscard]] constexpr quantity_type& quantity_ref_from(PO2) & noexcept { - return q_; + return quantity_from_origin_; } template> PO2> [[nodiscard]] constexpr const quantity_type& quantity_ref_from(PO2) const& noexcept { - return q_; + return quantity_from_origin_; } template> PO2> [[nodiscard]] constexpr quantity_type&& quantity_ref_from(PO2) && noexcept { - return std::move(q_); + return std::move(quantity_from_origin_); } template> PO2> [[nodiscard]] constexpr const quantity_type&& quantity_ref_from(PO2) const&& noexcept { - return std::move(q_); + return std::move(quantity_from_origin_); } #endif @@ -190,43 +191,43 @@ class quantity_point { // member unary operators constexpr quantity_point& operator++() - requires requires { ++q_; } + requires requires { ++quantity_from_origin_; } { - ++q_; + ++quantity_from_origin_; return *this; } [[nodiscard]] constexpr quantity_point operator++(int) - requires requires { q_++; } + requires requires { quantity_from_origin_++; } { - return quantity_point(q_++); + return quantity_point(quantity_from_origin_++); } constexpr quantity_point& operator--() - requires requires { --q_; } + requires requires { --quantity_from_origin_; } { - --q_; + --quantity_from_origin_; return *this; } [[nodiscard]] constexpr quantity_point operator--(int) - requires requires { q_--; } + requires requires { quantity_from_origin_--; } { - return quantity_point(q_--); + return quantity_point(quantity_from_origin_--); } // compound assignment operators constexpr quantity_point& operator+=(const quantity_type& q) - requires requires { q_ += q; } + requires requires { quantity_from_origin_ += q; } { - q_ += q; + quantity_from_origin_ += q; return *this; } constexpr quantity_point& operator-=(const quantity_type& q) - requires requires { q_ -= q; } + requires requires { quantity_from_origin_ -= q; } { - q_ -= q; + quantity_from_origin_ -= q; return *this; } @@ -242,7 +243,7 @@ class quantity_point { template requires std::constructible_from && ReferenceOf, PO.quantity_spec> - constexpr explicit quantity_point(Q&& q) : q_(std::forward(q)) + constexpr explicit quantity_point(Q&& q) : quantity_from_origin_(std::forward(q)) { } }; From dc2d0dfca71821693d10a073602e9f5801e44397 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 18:40:51 +0200 Subject: [PATCH 16/22] feat: `force_in(U)` added for `quantity_point` --- src/core/include/mp-units/quantity_point.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 1972ea301..1f4a4940a 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -183,12 +183,19 @@ class quantity_point { } template - requires detail::QuantityConvertibleTo{}, Rep>> - [[nodiscard]] constexpr quantity_point<::mp_units::reference{}, PO, Rep> in(U) const + requires detail::QuantityConvertibleTo> + [[nodiscard]] constexpr quantity_point in(U) const { return make_quantity_point(quantity_ref_from(PO).in(U{})); } + template + requires requires(quantity_type q) { value_cast(q); } + [[nodiscard]] constexpr quantity_point force_in(U) const + { + return make_quantity_point(quantity_ref_from(PO).force_in(U{})); + } + // member unary operators constexpr quantity_point& operator++() requires requires { ++quantity_from_origin_; } From 6d619d67efaa52013ef5f6a10878b2cb049fe705 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 19:53:32 +0200 Subject: [PATCH 17/22] refactor(example): `get_magnitude` improved for linear algebra --- .../unit_test/runtime/linear_algebra_test.cpp | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/unit_test/runtime/linear_algebra_test.cpp b/test/unit_test/runtime/linear_algebra_test.cpp index b9bd1a542..ff642e77b 100644 --- a/test/unit_test/runtime/linear_algebra_test.cpp +++ b/test/unit_test/runtime/linear_algebra_test.cpp @@ -56,11 +56,19 @@ namespace { using namespace mp_units; using namespace mp_units::si::unit_symbols; -template -[[nodiscard]] auto get_magnitude(const vector& v) +template Q> + requires(Q::quantity_spec.character == quantity_character::vector) && (QS.character == quantity_character::scalar) +[[nodiscard]] QuantityOf auto get_magnitude(const Q& q) { - using namespace std; - return hypot(v(0), v(1), v(2)); + const auto& v = q.numerical_value_ref_in(q.unit); + return hypot(v(0) * QS[q.unit], v(1) * QS[q.unit], v(2) * QS[q.unit]); +} + +template T> + requires(T::quantity_spec.character == quantity_character::vector) && (QS.character == quantity_character::scalar) +[[nodiscard]] QuantityOf auto get_magnitude(const vector& v) +{ + return hypot(QS(v(0)), QS(v(1)), QS(v(2))); } template @@ -100,8 +108,7 @@ TEST_CASE("vector quantity", "[la]") SECTION("to scalar magnitude") { const auto v = vector{2, 3, 6} * isq::velocity[km / h]; - const auto speed = - get_magnitude(v.numerical_value_ref_in(km / h)) * isq::speed[v.unit]; // TODO can we do better here? + const auto speed = get_magnitude(v); CHECK(speed.numerical_value_ref_in(km / h) == 7); } @@ -308,8 +315,7 @@ TEST_CASE("vector of quantities", "[la]") SECTION("to scalar magnitude") { const vector> v = {2 * (km / h), 3 * (km / h), 6 * (km / h)}; - const auto speed = - get_magnitude(v).numerical_value_ref_in(km / h) * isq::speed[v(0).unit]; // TODO can we do better here? + const auto speed = get_magnitude(v); CHECK(speed.numerical_value_ref_in(km / h) == 7); } From 6a1e600f65b8be1287ef6c538ee317bc74c123ae Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 19:57:05 +0200 Subject: [PATCH 18/22] feat: `quantity` compound assignment now preserves the value category --- src/core/include/mp-units/quantity.h | 115 +++++++++++++++------------ 1 file changed, 62 insertions(+), 53 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 88d6a43fb..6c3f9f1b8 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -269,88 +269,97 @@ class quantity { } // compound assignment operators - constexpr quantity& operator+=(const quantity& q) - requires requires(rep a, rep b) { + template + requires std::derived_from, quantity> && requires(rep a, rep b) { { a += b } -> std::same_as; } + friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs) { - numerical_value_ += q.numerical_value_ref_in(unit); - return *this; + lhs.numerical_value_ += rhs.numerical_value_; + return std::forward(lhs); } - constexpr quantity& operator-=(const quantity& q) - requires requires(rep a, rep b) { + template + requires std::derived_from, quantity> && requires(rep a, rep b) { { a -= b } -> std::same_as; } + friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs) { - numerical_value_ -= q.numerical_value_ref_in(unit); - return *this; + lhs.numerical_value_ -= rhs.numerical_value_; + return std::forward(lhs); } - constexpr quantity& operator%=(const quantity& q) - requires(!treat_as_floating_point) && requires(rep a, rep b) { - { - a %= b - } -> std::same_as; - } + template + requires std::derived_from, quantity> && (!treat_as_floating_point) && + requires(rep a, rep b) { + { + a %= b + } -> std::same_as; + } + friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs) + { - gsl_ExpectsAudit(q != zero()); - numerical_value_ %= q.numerical_value_ref_in(unit); - return *this; + gsl_ExpectsAudit(rhs != zero()); + lhs.numerical_value_ %= rhs.numerical_value_; + return std::forward(lhs); } - template - requires(!Quantity) && requires(rep a, const Value b) { - { - a *= b - } -> std::same_as; - } - constexpr quantity& operator*=(const Value& v) + template + requires std::derived_from, quantity> && (!Quantity) && + requires(rep a, const Value b) { + { + a *= b + } -> std::same_as; + } + friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v) { - numerical_value_ *= v; - return *this; + lhs.numerical_value_ *= v; + return std::forward(lhs); } - template Q> - requires(Q::unit == ::mp_units::one) && requires(rep a, const typename Q::rep b) { - { - a *= b - } -> std::same_as; - } - constexpr quantity& operator*=(const Q& rhs) + template Q2> + requires std::derived_from, quantity> && (Q2::unit == ::mp_units::one) && + requires(rep a, const typename Q2::rep b) { + { + a *= b + } -> std::same_as; + } + friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs) { - numerical_value_ *= rhs.numerical_value_ref_in(::mp_units::one); - return *this; + lhs.numerical_value_ *= rhs.numerical_value_; + return std::forward(lhs); } - template - requires(!Quantity) && requires(rep a, const Value b) { - { - a /= b - } -> std::same_as; - } - constexpr quantity& operator/=(const Value& v) + template + requires std::derived_from, quantity> && (!Quantity) && + requires(rep a, const Value b) { + { + a /= b + } -> std::same_as; + } + friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v) { gsl_ExpectsAudit(v != quantity_values::zero()); - numerical_value_ /= v; - return *this; + lhs.numerical_value_ /= v; + return std::forward(lhs); } - template Q> - requires(Q::unit == ::mp_units::one) && requires(rep a, const typename Q::rep b) { - { - a /= b - } -> std::same_as; - } - constexpr quantity& operator/=(const Q& rhs) + template Q2> + requires std::derived_from, quantity> && (Q2::unit == ::mp_units::one) && + requires(rep a, const typename Q2::rep b) { + { + a /= b + } -> std::same_as; + } + friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs) { gsl_ExpectsAudit(rhs != rhs.zero()); - numerical_value_ /= rhs.numerical_value_ref_in(::mp_units::one); - return *this; + lhs.numerical_value_ /= rhs.numerical_value_; + return std::forward(lhs); } private: From 2e26eed59d8afd07f3023f5341243050f556938e Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 19:59:49 +0200 Subject: [PATCH 19/22] feat: `numerical_value_ref_in` disallowed for rvalues --- example/currency.cpp | 2 +- src/core-fmt/include/mp-units/format.h | 4 +- .../include/mp-units/bits/quantity_cast.h | 4 +- src/core/include/mp-units/bits/sudo_cast.h | 13 +- src/core/include/mp-units/quantity.h | 57 ++-- src/core/include/mp-units/quantity_spec.h | 9 +- test/unit_test/runtime/almost_equals.h | 4 +- .../unit_test/runtime/linear_algebra_test.cpp | 59 ++-- test/unit_test/runtime/math_test.cpp | 5 +- test/unit_test/static/quantity_point_test.cpp | 152 +++++------ test/unit_test/static/quantity_test.cpp | 256 +++++++++--------- 11 files changed, 261 insertions(+), 304 deletions(-) diff --git a/example/currency.cpp b/example/currency.cpp index ae3267663..40892ad2a 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -82,7 +82,7 @@ template auto To, ReferenceOf auto From, auto PO quantity_point exchange_to(quantity_point q) { return quantity_point{zero + static_cast(exchange_rate() * - (q - q.absolute_point_origin).numerical_value_ref_in(q.unit)) * + (q - q.absolute_point_origin).numerical_value_in(q.unit)) * To}; } diff --git a/src/core-fmt/include/mp-units/format.h b/src/core-fmt/include/mp-units/format.h index 510584d90..7929bb2f7 100644 --- a/src/core-fmt/include/mp-units/format.h +++ b/src/core-fmt/include/mp-units/format.h @@ -224,9 +224,9 @@ struct quantity_formatter { const quantity_format_specs& specs; Locale loc; - explicit quantity_formatter(OutputIt o, quantity q, const quantity_format_specs& fspecs, + explicit quantity_formatter(OutputIt o, const quantity& q, const quantity_format_specs& fspecs, Locale lc) : - out(o), val(std::move(q).numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc)) + out(o), val(q.numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc)) { } diff --git a/src/core/include/mp-units/bits/quantity_cast.h b/src/core/include/mp-units/bits/quantity_cast.h index fe88b85a5..4fa7d08b9 100644 --- a/src/core/include/mp-units/bits/quantity_cast.h +++ b/src/core/include/mp-units/bits/quantity_cast.h @@ -51,9 +51,9 @@ template { if constexpr (detail::QuantityKindSpec> && AssociatedUnit>) - return make_quantity(std::forward(q).numerical_value_ref_in(q.unit)); + return make_quantity(std::forward(q).numerical_value_); else - return make_quantity{}>(std::forward(q).numerical_value_ref_in(q.unit)); + return make_quantity{}>(std::forward(q).numerical_value_); } } // namespace mp_units diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index 75b53dc9e..49f6dc52e 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -63,10 +63,10 @@ template if constexpr (q_unit == To::unit) { // no scaling of the number needed return make_quantity(static_cast( - std::forward(q).numerical_value_ref_in(q_unit))); // this is the only (and recommended) way to do - // a truncating conversion on a number, so we are - // using static_cast to suppress all the compiler - // warnings on conversions + std::forward(q).numerical_value_)); // this is the only (and recommended) way to do + // a truncating conversion on a number, so we are + // using static_cast to suppress all the compiler + // warnings on conversions } else { // scale the number constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag; @@ -78,9 +78,8 @@ template using multiplier_type = conditional, std::common_type_t, c_mag_type>; constexpr auto val = [](Magnitude auto m) { return get_value(m); }; - return static_cast( - static_cast(std::forward(q).numerical_value_ref_in(q_unit)) * val(num) / val(den) * - val(irr)) * + return static_cast(static_cast(std::forward(q).numerical_value_) * + val(num) / val(den) * val(irr)) * To::reference; } } diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 6c3f9f1b8..2e9fab497 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -126,7 +126,7 @@ class quantity { template Q> constexpr explicit(!std::convertible_to) quantity(const Q& q) : - numerical_value_(detail::sudo_cast(q).numerical_value_ref_in(unit)) + numerical_value_(detail::sudo_cast(q).numerical_value_) { } @@ -157,52 +157,36 @@ class quantity { } // data access -#ifdef __cpp_explicit_this_parameter - template - requires(U{} == unit) - [[nodiscard]] constexpr auto&& numerical_value_ref_in(this Self&& self, U) noexcept - { - return std::forward(self).numerical_value_; - } -#else template requires(U{} == unit) [[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept { return numerical_value_; } + template requires(U{} == unit) [[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept { return numerical_value_; } + template requires(U{} == unit) - [[nodiscard]] constexpr rep&& numerical_value_ref_in(U) && noexcept - { - return std::move(numerical_value_); - } - template - requires(U{} == unit) - [[nodiscard]] constexpr const rep&& numerical_value_ref_in(U) const&& noexcept - { - return std::move(numerical_value_); - } -#endif + constexpr const rep&& numerical_value_ref_in(U) const&& noexcept = delete; template requires requires(quantity q) { q.in(U{}); } [[nodiscard]] constexpr rep numerical_value_in(U) const noexcept { - return (*this).in(U{}).numerical_value_ref_in(U{}); + return (*this).in(U{}).numerical_value_; } template requires requires(quantity q) { q.force_in(U{}); } [[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept { - return (*this).force_in(U{}).numerical_value_ref_in(U{}); + return (*this).force_in(U{}).numerical_value_; } // member unary operators @@ -213,7 +197,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(+numerical_value_ref_in(unit)); + return make_quantity(+numerical_value_); } [[nodiscard]] constexpr Quantity auto operator-() const @@ -223,7 +207,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(-numerical_value_ref_in(unit)); + return make_quantity(-numerical_value_); } constexpr quantity& operator++() @@ -387,8 +371,7 @@ template [[nodiscard]] constexpr Quantity auto operator+(const quantity& lhs, const quantity& rhs) { using ret = detail::common_quantity_for, quantity, quantity>; - return make_quantity(ret(lhs).numerical_value_ref_in(ret::unit) + - ret(rhs).numerical_value_ref_in(ret::unit)); + return make_quantity(ret(lhs).numerical_value_ + ret(rhs).numerical_value_); } template @@ -396,8 +379,7 @@ template [[nodiscard]] constexpr Quantity auto operator-(const quantity& lhs, const quantity& rhs) { using ret = detail::common_quantity_for, quantity, quantity>; - return make_quantity(ret(lhs).numerical_value_ref_in(ret::unit) - - ret(rhs).numerical_value_ref_in(ret::unit)); + return make_quantity(ret(lhs).numerical_value_ - ret(rhs).numerical_value_); } template @@ -407,8 +389,7 @@ template { gsl_ExpectsAudit(rhs != rhs.zero()); using ret = detail::common_quantity_for, quantity, quantity>; - return make_quantity(ret(lhs).numerical_value_ref_in(ret::unit) % - ret(rhs).numerical_value_ref_in(ret::unit)); + return make_quantity(ret(lhs).numerical_value_ % ret(rhs).numerical_value_); } template @@ -416,7 +397,7 @@ template Rep2> [[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) { - return make_quantity(lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2))); + return make_quantity(lhs.numerical_value_ * rhs.numerical_value_); } template @@ -424,7 +405,7 @@ template detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] constexpr Quantity auto operator*(const quantity& q, const Value& v) { - return make_quantity(q.numerical_value_ref_in(get_unit(R)) * v); + return make_quantity(q.numerical_value_ * v); } template @@ -432,7 +413,7 @@ template detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity& q) { - return make_quantity(v * q.numerical_value_ref_in(get_unit(R))); + return make_quantity(v * q.numerical_value_); } template @@ -440,7 +421,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) { gsl_ExpectsAudit(rhs != rhs.zero()); - return make_quantity(lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2))); + return make_quantity(lhs.numerical_value_ / rhs.numerical_value_); } template @@ -449,7 +430,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& q, const Value& v) { gsl_ExpectsAudit(v != quantity_values::zero()); - return make_quantity(q.numerical_value_ref_in(get_unit(R)) / v); + return make_quantity(q.numerical_value_ / v); } template @@ -457,7 +438,7 @@ template 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.numerical_value_ref_in(get_unit(R))); + return make_quantity<::mp_units::one / R>(v / q.numerical_value_); } template @@ -466,7 +447,7 @@ template [[nodiscard]] constexpr bool operator==(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t, quantity>; - return ct(lhs).numerical_value_ref_in(ct::unit) == ct(rhs).numerical_value_ref_in(ct::unit); + return ct(lhs).numerical_value_ == ct(rhs).numerical_value_; } template @@ -475,7 +456,7 @@ template [[nodiscard]] constexpr auto operator<=>(const quantity& lhs, const quantity& rhs) { using ct = std::common_type_t, quantity>; - return ct(lhs).numerical_value_ref_in(ct::unit) <=> ct(rhs).numerical_value_ref_in(ct::unit); + return ct(lhs).numerical_value_ <=> ct(rhs).numerical_value_; } // make_quantity diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index b55adf620..b6e2e2a1a 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -111,8 +111,7 @@ struct quantity_spec_interface { requires Quantity> && (explicitly_convertible(std::remove_reference_t::quantity_spec, self)) { - return make_quantity::unit>{}>( - std::forward(q).numerical_value_ref_in(q.unit)); + return make_quantity::unit>{}>(std::forward(q).numerical_value_); } #else template U> @@ -129,8 +128,7 @@ struct quantity_spec_interface { (explicitly_convertible(std::remove_reference_t::quantity_spec, Self_{})) [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { - return make_quantity::unit>{}>( - std::forward(q).numerical_value_ref_in(q.unit)); + return make_quantity::unit>{}>(std::forward(q).numerical_value_); } #endif }; @@ -309,8 +307,7 @@ struct quantity_spec : std::remove_const_t { (explicitly_convertible(std::remove_reference_t::quantity_spec, Self_{})) [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { - return make_quantity::unit>{}>( - std::forward(q).numerical_value_ref_in(q.unit)); + return make_quantity::unit>{}>(std::forward(q).numerical_value_); } #endif }; diff --git a/test/unit_test/runtime/almost_equals.h b/test/unit_test/runtime/almost_equals.h index 038dfb6e5..b3af6689b 100644 --- a/test/unit_test/runtime/almost_equals.h +++ b/test/unit_test/runtime/almost_equals.h @@ -36,8 +36,8 @@ struct AlmostEqualsMatcher : Catch::Matchers::MatcherGenericBase { { using std::abs; using common = std::common_type_t; - const auto x = common(target_).numerical_value_ref_in(common::unit); - const auto y = common(other).numerical_value_ref_in(common::unit); + const auto x = common(target_).numerical_value_in(common::unit); + const auto y = common(other).numerical_value_in(common::unit); const auto maxXYOne = std::max({typename T::rep{1}, abs(x), abs(y)}); return abs(x - y) <= std::numeric_limits::epsilon() * maxXYOne; } diff --git a/test/unit_test/runtime/linear_algebra_test.cpp b/test/unit_test/runtime/linear_algebra_test.cpp index ff642e77b..ad9fb31f4 100644 --- a/test/unit_test/runtime/linear_algebra_test.cpp +++ b/test/unit_test/runtime/linear_algebra_test.cpp @@ -118,14 +118,14 @@ TEST_CASE("vector quantity", "[la]") SECTION("integral") { - SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_ref_in(m) == vector{2, 4, 6}); } - SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_ref_in(m) == vector{2, 4, 6}); } + SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_ == vector{2, 4, 6}); } + SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_ == vector{2, 4, 6}); } } SECTION("floating-point") { - SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_ref_in(m) == vector{0.5, 1., 1.5}); } - SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_ref_in(m) == vector{0.5, 1., 1.5}); } + SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_ == vector{0.5, 1., 1.5}); } + SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_ == vector{0.5, 1., 1.5}); } } } @@ -133,8 +133,8 @@ TEST_CASE("vector quantity", "[la]") { const auto v = vector{2, 4, 6} * isq::position_vector[m]; - SECTION("integral") { CHECK((v / 2).numerical_value_ref_in(m) == vector{1, 2, 3}); } - SECTION("floating-point") { CHECK((v / 0.5).numerical_value_ref_in(m) == vector{4., 8., 12.}); } + SECTION("integral") { CHECK((v / 2).numerical_value_ == vector{1, 2, 3}); } + SECTION("floating-point") { CHECK((v / 0.5).numerical_value_ == vector{4., 8., 12.}); } } SECTION("add") @@ -144,12 +144,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("same unit") { const auto u = vector{3, 2, 1} * isq::position_vector[m]; - CHECK((v + u).numerical_value_ref_in(m) == vector{4, 4, 4}); + CHECK((v + u).numerical_value_ == vector{4, 4, 4}); } SECTION("different units") { const auto u = vector{3, 2, 1} * isq::position_vector[km]; - CHECK((v + u).numerical_value_ref_in(m) == vector{3001, 2002, 1003}); + CHECK((v + u).numerical_value_ == vector{3001, 2002, 1003}); } } @@ -160,12 +160,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("same unit") { const auto u = vector{3, 2, 1} * isq::position_vector[m]; - CHECK((v - u).numerical_value_ref_in(m) == vector{-2, 0, 2}); + CHECK((v - u).numerical_value_ == vector{-2, 0, 2}); } SECTION("different units") { const auto u = vector{3, 2, 1} * isq::position_vector[km]; - CHECK((v - u).numerical_value_ref_in(m) == vector{-2999, -1998, -997}); + CHECK((v - u).numerical_value_ == vector{-2999, -1998, -997}); } } @@ -179,18 +179,18 @@ TEST_CASE("vector quantity", "[la]") SECTION("derived_quantity_spec") { - SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ref_in(N * s) == vector{2, 4, 6}); } - SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ref_in(N * s) == vector{2, 4, 6}); } + SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ == vector{2, 4, 6}); } + SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ == vector{2, 4, 6}); } } SECTION("quantity_cast to momentum") { SECTION("scalar on LHS") { - CHECK(quantity_cast(mass * v).numerical_value_ref_in(N * s) == vector{2, 4, 6}); + CHECK(quantity_cast(mass * v).numerical_value_ == vector{2, 4, 6}); } SECTION("scalar on RHS") { - CHECK(quantity_cast(v * mass).numerical_value_ref_in(N * s) == vector{2, 4, 6}); + CHECK(quantity_cast(v * mass).numerical_value_ == vector{2, 4, 6}); } } SECTION("quantity of momentum") @@ -198,12 +198,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("scalar on LHS") { const quantity> momentum = mass * v; - CHECK(momentum.numerical_value_ref_in(N * s) == vector{2, 4, 6}); + CHECK(momentum.numerical_value_ == vector{2, 4, 6}); } SECTION("scalar on RHS") { const quantity> momentum = v * mass; - CHECK(momentum.numerical_value_ref_in(N * s) == vector{2, 4, 6}); + CHECK(momentum.numerical_value_ == vector{2, 4, 6}); } } } @@ -214,18 +214,18 @@ TEST_CASE("vector quantity", "[la]") SECTION("derived_quantity_spec") { - SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } - SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); } + SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ == vector{0.5, 1., 1.5}); } + SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ == vector{0.5, 1., 1.5}); } } SECTION("quantity_cast to momentum") { SECTION("scalar on LHS") { - CHECK(quantity_cast(mass * v).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); + CHECK(quantity_cast(mass * v).numerical_value_ == vector{0.5, 1., 1.5}); } SECTION("scalar on RHS") { - CHECK(quantity_cast(v * mass).numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); + CHECK(quantity_cast(v * mass).numerical_value_ == vector{0.5, 1., 1.5}); } } SECTION("quantity of momentum") @@ -233,12 +233,12 @@ TEST_CASE("vector quantity", "[la]") SECTION("scalar on LHS") { const quantity> momentum = mass * v; - CHECK(momentum.numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); + CHECK(momentum.numerical_value_ == vector{0.5, 1., 1.5}); } SECTION("scalar on RHS") { const quantity> momentum = v * mass; - CHECK(momentum.numerical_value_ref_in(N * s) == vector{0.5, 1., 1.5}); + CHECK(momentum.numerical_value_ == vector{0.5, 1., 1.5}); } } } @@ -252,15 +252,15 @@ TEST_CASE("vector quantity", "[la]") { const auto dur = 2 * isq::duration[h]; - SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ref_in(km / h) == vector{15, 10, 5}); } + SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ == vector{15, 10, 5}); } SECTION("quantity_cast to velocity") { - CHECK(quantity_cast(pos / dur).numerical_value_ref_in(km / h) == vector{15, 10, 5}); + CHECK(quantity_cast(pos / dur).numerical_value_ == vector{15, 10, 5}); } SECTION("quantity of velocity") { const quantity> v = pos / dur; - CHECK(v.numerical_value_ref_in(km / h) == vector{15, 10, 5}); + CHECK(v.numerical_value_ == vector{15, 10, 5}); } } @@ -268,18 +268,15 @@ TEST_CASE("vector quantity", "[la]") { const auto dur = 0.5 * isq::duration[h]; - SECTION("derived_quantity_spec") - { - CHECK((pos / dur).numerical_value_ref_in(km / h) == vector{60, 40, 20}); - } + SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ == vector{60, 40, 20}); } SECTION("quantity_cast to velocity") { - CHECK(quantity_cast(pos / dur).numerical_value_ref_in(km / h) == vector{60, 40, 20}); + CHECK(quantity_cast(pos / dur).numerical_value_ == vector{60, 40, 20}); } SECTION("quantity of velocity") { const quantity> v = pos / dur; - CHECK(v.numerical_value_ref_in(km / h) == vector{60, 40, 20}); + CHECK(v.numerical_value_ == vector{60, 40, 20}); } } } diff --git a/test/unit_test/runtime/math_test.cpp b/test/unit_test/runtime/math_test.cpp index 3391e9007..fdf5e1dc3 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -90,13 +90,12 @@ TEST_CASE("numeric_limits functions", "[limits]") { SECTION("'epsilon' works as expected using default floating type") { - REQUIRE(epsilon(isq::length[m]).numerical_value_ref_in(m) == + REQUIRE(epsilon(isq::length[m]).numerical_value_ == std::numeric_limits::epsilon()); } SECTION("'epsilon' works as expected using integers") { - REQUIRE(epsilon(isq::length[m]).numerical_value_ref_in(m) == - + REQUIRE(epsilon(isq::length[m]).numerical_value_ == std::numeric_limits::epsilon()); } } diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index 7805b2c1f..f7c5eb316 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -242,24 +242,22 @@ static_assert( //////////////////////////// static_assert( - quantity_point::zero().quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 0); + quantity_point::zero().quantity_ref_from(mean_sea_level).numerical_value_ == 0); static_assert( - quantity_point::min().quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + quantity_point::min().quantity_ref_from(mean_sea_level).numerical_value_ == std::numeric_limits::lowest()); static_assert( - quantity_point::max().quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == + quantity_point::max().quantity_ref_from(mean_sea_level).numerical_value_ == std::numeric_limits::max()); static_assert( - quantity_point::zero().quantity_ref_from(ground_level).numerical_value_ref_in(m) == - 0); + quantity_point::zero().quantity_ref_from(ground_level).numerical_value_ == 0); static_assert( - quantity_point::min().quantity_ref_from(ground_level).numerical_value_ref_in(m) == + quantity_point::min().quantity_ref_from(ground_level).numerical_value_ == std::numeric_limits::lowest()); static_assert( - quantity_point::max().quantity_ref_from(ground_level).numerical_value_ref_in(m) == + quantity_point::max().quantity_ref_from(ground_level).numerical_value_ == std::numeric_limits::max()); @@ -591,15 +589,15 @@ static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(m // converting to a different unit /////////////////////////////////// -static_assert((mean_sea_level + 2. * km).in(km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(km) == 2.); -static_assert((mean_sea_level + 2. * km).in(m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2000.); -static_assert((mean_sea_level + 2000. * m).in(km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(km) == 2.); -static_assert((ground_level + 2. * km).in(km).quantity_ref_from(ground_level).numerical_value_ref_in(km) == 2.); -static_assert((ground_level + 2. * km).in(m).quantity_ref_from(ground_level).numerical_value_ref_in(m) == 2000.); -static_assert((ground_level + 2000. * m).in(km).quantity_ref_from(ground_level).numerical_value_ref_in(km) == 2.); -static_assert((tower_peak + 2. * km).in(km).quantity_ref_from(tower_peak).numerical_value_ref_in(km) == 2.); -static_assert((tower_peak + 2. * km).in(m).quantity_ref_from(tower_peak).numerical_value_ref_in(m) == 2000.); -static_assert((tower_peak + 2000. * m).in(km).quantity_ref_from(tower_peak).numerical_value_ref_in(km) == 2.); +static_assert((mean_sea_level + 2. * km).in(km).quantity_ref_from(mean_sea_level).numerical_value_ == 2.); +static_assert((mean_sea_level + 2. * km).in(m).quantity_ref_from(mean_sea_level).numerical_value_ == 2000.); +static_assert((mean_sea_level + 2000. * m).in(km).quantity_ref_from(mean_sea_level).numerical_value_ == 2.); +static_assert((ground_level + 2. * km).in(km).quantity_ref_from(ground_level).numerical_value_ == 2.); +static_assert((ground_level + 2. * km).in(m).quantity_ref_from(ground_level).numerical_value_ == 2000.); +static_assert((ground_level + 2000. * m).in(km).quantity_ref_from(ground_level).numerical_value_ == 2.); +static_assert((tower_peak + 2. * km).in(km).quantity_ref_from(tower_peak).numerical_value_ == 2.); +static_assert((tower_peak + 2. * km).in(m).quantity_ref_from(tower_peak).numerical_value_ == 2000.); +static_assert((tower_peak + 2000. * m).in(km).quantity_ref_from(tower_peak).numerical_value_ == 2.); #if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2 template typename QP> @@ -672,14 +670,14 @@ static_assert([](auto v) { //////////////////////// // same type -static_assert((mean_sea_level + 1 * m += 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2); -static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1); +static_assert((mean_sea_level + 1 * m += 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2); +static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1); // different types -static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 5.5); -static_assert((mean_sea_level + 123 * m += 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1123); -static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); -static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 123); +static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 5.5); +static_assert((mean_sea_level + 123 * m += 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1123); +static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); +static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 123); template typename QP> @@ -952,30 +950,30 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu // check for integral types promotion static_assert(is_same_v); + .numerical_value_), + int>); static_assert(is_same_v); + .numerical_value_), + int>); static_assert(is_same_v); -static_assert(is_same_v); + .numerical_value_), + int>); +static_assert( + is_same_v< + decltype(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(0) * m)).numerical_value_), int>); static_assert(((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m) .quantity_ref_from(mean_sea_level) - .numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); + .numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); static_assert((std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)) .quantity_ref_from(mean_sea_level) - .numerical_value_ref_in(m) == std::uint8_t(128) + std::uint8_t(128)); -static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m) - .quantity_ref_from(mean_sea_level) - .numerical_value_ref_in(m) == std::uint8_t(0) - std::uint8_t(1)); -static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)) - .numerical_value_ref_in(m) == std::uint8_t(0) - std::uint8_t(1)); + .numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); +static_assert( + ((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_ref_from(mean_sea_level).numerical_value_ == + std::uint8_t(0) - std::uint8_t(1)); +static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value_ == + std::uint8_t(0) - std::uint8_t(1)); // different representation types static_assert(is_of_type<(mean_sea_level + 1. * m) + 1 * m, quantity_point>); @@ -1029,49 +1027,39 @@ static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m), static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity>); -static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2); -static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2); -static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); -static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); -static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); -static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1001); -static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1); -static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 999); - -static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); -static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); -static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1001.5); -static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1001.5); -static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1501); -static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1501); -static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 1.5); -static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1499); - -static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); -static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 2.5); -static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1501); -static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1501); -static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1001.5); -static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 1001.5); -static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == 0.5); -static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ref_in(m) == - 998.5); - -static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1); -static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 999); -static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1.5); -static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_ref_in(m) == 1499); -static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_ref_in(m) == 0.5); -static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_ref_in(m) == 998.5); +static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2); +static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 2); +static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); +static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); +static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); +static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); +static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1); +static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 999); + +static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); +static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); +static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); +static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); +static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); +static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); +static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1.5); +static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1499); + +static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); +static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); +static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); +static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); +static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); +static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); +static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 0.5); +static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 998.5); + +static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ == 1); +static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ == 999); +static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_ == 1.5); +static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_ == 1499); +static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_ == 0.5); +static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_ == 998.5); static_assert((mean_sea_level + 42 * m) - (ground_level + 42 * m) == -42 * m); static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 3d04f7546..77091cb73 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -112,15 +112,14 @@ static_assert(is_same_v::rep, int>); // static member functions //////////////////////////// -static_assert(quantity::zero().numerical_value_ref_in(m) == 0); -static_assert(quantity::one().numerical_value_ref_in(m) == 1); -static_assert(quantity::min().numerical_value_ref_in(m) == std::numeric_limits::lowest()); -static_assert(quantity::max().numerical_value_ref_in(m) == std::numeric_limits::max()); -static_assert(quantity::zero().numerical_value_ref_in(m) == 0.0); -static_assert(quantity::one().numerical_value_ref_in(m) == 1.0); -static_assert(quantity::min().numerical_value_ref_in(m) == - std::numeric_limits::lowest()); -static_assert(quantity::max().numerical_value_ref_in(m) == std::numeric_limits::max()); +static_assert(quantity::zero().numerical_value_ == 0); +static_assert(quantity::one().numerical_value_ == 1); +static_assert(quantity::min().numerical_value_ == std::numeric_limits::lowest()); +static_assert(quantity::max().numerical_value_ == std::numeric_limits::max()); +static_assert(quantity::zero().numerical_value_ == 0.0); +static_assert(quantity::one().numerical_value_ == 1.0); +static_assert(quantity::min().numerical_value_ == std::numeric_limits::lowest()); +static_assert(quantity::max().numerical_value_ == std::numeric_limits::max()); ////////////////////////////// @@ -191,10 +190,10 @@ static_assert(std::convertible_to, quantity(123 * m).numerical_value_ref_in(m) == 123); -static_assert(quantity(2 * km).numerical_value_ref_in(m) == 2000); -static_assert(quantity(2 * km).numerical_value_ref_in(km) == 2); -static_assert(quantity(1500 * m).numerical_value_ref_in(km) == 1.5); +static_assert(quantity(123 * m).numerical_value_ == 123); +static_assert(quantity(2 * km).numerical_value_ == 2000); +static_assert(quantity(2 * km).numerical_value_ == 2); +static_assert(quantity(1500 * m).numerical_value_ == 1.5); /////////////////////////////////// @@ -205,11 +204,11 @@ static_assert(is_of_type<(2. * km).in(m), quantity>); static_assert(is_of_type>); static_assert(is_of_type>); -static_assert(quantity(2. * km).in(km).numerical_value_ref_in(km) == 2.); -static_assert(quantity(2. * km).in(m).numerical_value_ref_in(m) == 2000.); -static_assert(quantity(2000. * m).in(km).numerical_value_ref_in(km) == 2.); -static_assert(quantity(2 * km).in(km).numerical_value_ref_in(km) == 2); -static_assert(quantity(2 * km).in(m).numerical_value_ref_in(m) == 2000); +static_assert(quantity(2. * km).in(km).numerical_value_ == 2.); +static_assert(quantity(2. * km).in(m).numerical_value_ == 2000.); +static_assert(quantity(2000. * m).in(km).numerical_value_ == 2.); +static_assert(quantity(2 * km).in(km).numerical_value_ == 2); +static_assert(quantity(2 * km).in(m).numerical_value_ == 2000); #if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2 template typename Q> @@ -309,28 +308,28 @@ static_assert([] { auto l1(1 * m), l2(2 * m); return l2 = l1; }() - .numerical_value_ref_in(m) == 1); + .numerical_value_ == 1); static_assert([] { const auto l1(1 * m); auto l2(2 * m); return l2 = l1; }() - .numerical_value_ref_in(m) == 1); + .numerical_value_ == 1); static_assert([]() { auto l1(1 * m), l2(2 * m); return l2 = std::move(l1); }() - .numerical_value_ref_in(m) == 1); + .numerical_value_ == 1); //////////////////// // unary operators //////////////////// -static_assert((+123 * m).numerical_value_ref_in(m) == 123); -static_assert((-123 * m).numerical_value_ref_in(m) == -123); -static_assert((+(-123 * m)).numerical_value_ref_in(m) == -123); -static_assert((-(-123 * m)).numerical_value_ref_in(m) == 123); +static_assert((+123 * m).numerical_value_ == 123); +static_assert((-123 * m).numerical_value_ == -123); +static_assert((+(-123 * m)).numerical_value_ == -123); +static_assert((-(-123 * m)).numerical_value_ == 123); static_assert([](auto v) { auto vv = v++; @@ -349,7 +348,7 @@ static_assert([](auto v) { return std::pair(v, vv); }(123 * m) == std::pair(122 * m, 122 * m)); -static_assert(is_same_v); +static_assert(is_same_v); //////////////////////// @@ -357,30 +356,31 @@ static_assert(is_same_v typename Q> @@ -518,15 +518,14 @@ static_assert(is_of_type<1 * km % (300 * m), quantity>); static_assert(is_of_type<4 * one % (2 * one), quantity>); // check for integral types promotion -static_assert(is_same_v); -static_assert(is_same_v); -static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_ref_in(m) == +static_assert(is_same_v); +static_assert(is_same_v); +static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); -static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_ref_in(m) == - std::uint8_t(0) - std::uint8_t(1)); +static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_ == std::uint8_t(0) - std::uint8_t(1)); -static_assert(is_same_v); +static_assert( + is_same_v); // different representation types static_assert(is_of_type<1. * m + 1 * m, quantity>); @@ -599,67 +598,67 @@ static_assert(is_of_type<1 * m / (1 * s), quantity>{}, int>>); static_assert(is_of_type<1 * min / (1 * m), quantity>{}, int>>); -static_assert((1 * m + 1 * m).numerical_value_ref_in(m) == 2); -static_assert((1 * m + 1 * km).numerical_value_ref_in(m) == 1001); -static_assert((1 * km + 1 * m).numerical_value_ref_in(m) == 1001); -static_assert((2 * m - 1 * m).numerical_value_ref_in(m) == 1); -static_assert((1 * km - 1 * m).numerical_value_ref_in(m) == 999); -static_assert((2 * m * 2).numerical_value_ref_in(m) == 4); -static_assert((2 * m * (2 * one)).numerical_value_ref_in(m) == 4); -static_assert((2 * m * (2 * percent)).numerical_value_ref_in(m * percent) == 4); -static_assert((3 * 3 * m).numerical_value_ref_in(m) == 9); -static_assert(((3 * one) * (3 * m)).numerical_value_ref_in(m) == 9); -static_assert(((3 * percent) * (3 * m)).numerical_value_ref_in(m * percent) == 9); -static_assert((4 * m / 2).numerical_value_ref_in(m) == 2); -static_assert((4 * m / (2 * one)).numerical_value_ref_in(m) == 2); -static_assert((4 * m / (2 * percent)).numerical_value_ref_in(m / percent) == 2); -static_assert((4 * km / (2 * m)).numerical_value_ref_in(km / m) == 2); -static_assert((4000 * m / (2 * m)).numerical_value_ref_in(one) == 2000); - -static_assert((1.5 * m + 1 * m).numerical_value_ref_in(m) == 2.5); -static_assert((1.5 * m + 1 * km).numerical_value_ref_in(m) == 1001.5); -static_assert((1.5 * km + 1 * m).numerical_value_ref_in(m) == 1501); -static_assert((2.5 * m - 1 * m).numerical_value_ref_in(m) == 1.5); -static_assert((1.5 * km - 1 * m).numerical_value_ref_in(m) == 1499); -static_assert((2.5 * m * 2).numerical_value_ref_in(m) == 5); -static_assert((2.5 * m * (2 * one)).numerical_value_ref_in(m) == 5); -static_assert((2.5 * m * (2 * percent)).numerical_value_ref_in(m * percent) == 5); -static_assert((2.5L * (2 * m)).numerical_value_ref_in(m) == 5); -static_assert((2.5L * one * (2 * m)).numerical_value_ref_in(m) == 5); -static_assert((2.5L * percent * (2 * m)).numerical_value_ref_in(m * percent) == 5); -static_assert((5. * m / 2).numerical_value_ref_in(m) == 2.5); -static_assert((5. * m / (2 * one)).numerical_value_ref_in(m) == 2.5); -static_assert((5. * m / (2 * percent)).numerical_value_ref_in(m / percent) == 2.5); -static_assert((5. * km / (2 * m)).numerical_value_ref_in(km / m) == 2.5); -static_assert((5000. * m / (2 * m)).numerical_value_ref_in(one) == 2500); - -static_assert((1 * m + 1.5 * m).numerical_value_ref_in(m) == 2.5); -static_assert((1 * m + 1.5 * km).numerical_value_ref_in(m) == 1501); -static_assert((1 * km + 1.5 * m).numerical_value_ref_in(m) == 1001.5); -static_assert((2 * m - 1.5 * m).numerical_value_ref_in(m) == 0.5); -static_assert((1 * km - 1.5 * m).numerical_value_ref_in(m) == 998.5); -static_assert((2 * m * 2.5L).numerical_value_ref_in(m) == 5); -static_assert((2 * m * (2.5L * one)).numerical_value_ref_in(m) == 5); -static_assert((2 * m * (2.5L * percent)).numerical_value_ref_in(m * percent) == 5); -static_assert((2 * 2.5 * m).numerical_value_ref_in(m) == 5); -static_assert((2 * one * (2.5 * m)).numerical_value_ref_in(m) == 5); -static_assert((2 * percent * (2.5 * m)).numerical_value_ref_in(m * percent) == 5); -static_assert((5 * m / 2.5L).numerical_value_ref_in(m) == 2); -static_assert((5 * m / (2.5L * one)).numerical_value_ref_in(m) == 2); -static_assert((5 * m / (2.5L * percent)).numerical_value_ref_in(m / percent) == 2); -static_assert((5 * km / (2.5 * m)).numerical_value_ref_in(km / m) == 2); -static_assert((5000 * m / (2.5 * m)).numerical_value_ref_in(one) == 2000); - -static_assert((7 * m % (2 * m)).numerical_value_ref_in(m) == 1); -static_assert((7 * km % (2000 * m)).numerical_value_ref_in(m) == 1000); -static_assert((1300 * m % (1 * km)).numerical_value_ref_in(m) == 300); -static_assert((7 * one % (2 * one)).numerical_value_ref_in(one) == 1); +static_assert((1 * m + 1 * m).numerical_value_ == 2); +static_assert((1 * m + 1 * km).numerical_value_ == 1001); +static_assert((1 * km + 1 * m).numerical_value_ == 1001); +static_assert((2 * m - 1 * m).numerical_value_ == 1); +static_assert((1 * km - 1 * m).numerical_value_ == 999); +static_assert((2 * m * 2).numerical_value_ == 4); +static_assert((2 * m * (2 * one)).numerical_value_ == 4); +static_assert((2 * m * (2 * percent)).numerical_value_ == 4); +static_assert((3 * 3 * m).numerical_value_ == 9); +static_assert(((3 * one) * (3 * m)).numerical_value_ == 9); +static_assert(((3 * percent) * (3 * m)).numerical_value_ == 9); +static_assert((4 * m / 2).numerical_value_ == 2); +static_assert((4 * m / (2 * one)).numerical_value_ == 2); +static_assert((4 * m / (2 * percent)).numerical_value_ == 2); +static_assert((4 * km / (2 * m)).numerical_value_ == 2); +static_assert((4000 * m / (2 * m)).numerical_value_ == 2000); + +static_assert((1.5 * m + 1 * m).numerical_value_ == 2.5); +static_assert((1.5 * m + 1 * km).numerical_value_ == 1001.5); +static_assert((1.5 * km + 1 * m).numerical_value_ == 1501); +static_assert((2.5 * m - 1 * m).numerical_value_ == 1.5); +static_assert((1.5 * km - 1 * m).numerical_value_ == 1499); +static_assert((2.5 * m * 2).numerical_value_ == 5); +static_assert((2.5 * m * (2 * one)).numerical_value_ == 5); +static_assert((2.5 * m * (2 * percent)).numerical_value_ == 5); +static_assert((2.5L * (2 * m)).numerical_value_ == 5); +static_assert((2.5L * one * (2 * m)).numerical_value_ == 5); +static_assert((2.5L * percent * (2 * m)).numerical_value_ == 5); +static_assert((5. * m / 2).numerical_value_ == 2.5); +static_assert((5. * m / (2 * one)).numerical_value_ == 2.5); +static_assert((5. * m / (2 * percent)).numerical_value_ == 2.5); +static_assert((5. * km / (2 * m)).numerical_value_ == 2.5); +static_assert((5000. * m / (2 * m)).numerical_value_ == 2500); + +static_assert((1 * m + 1.5 * m).numerical_value_ == 2.5); +static_assert((1 * m + 1.5 * km).numerical_value_ == 1501); +static_assert((1 * km + 1.5 * m).numerical_value_ == 1001.5); +static_assert((2 * m - 1.5 * m).numerical_value_ == 0.5); +static_assert((1 * km - 1.5 * m).numerical_value_ == 998.5); +static_assert((2 * m * 2.5L).numerical_value_ == 5); +static_assert((2 * m * (2.5L * one)).numerical_value_ == 5); +static_assert((2 * m * (2.5L * percent)).numerical_value_ == 5); +static_assert((2 * 2.5 * m).numerical_value_ == 5); +static_assert((2 * one * (2.5 * m)).numerical_value_ == 5); +static_assert((2 * percent * (2.5 * m)).numerical_value_ == 5); +static_assert((5 * m / 2.5L).numerical_value_ == 2); +static_assert((5 * m / (2.5L * one)).numerical_value_ == 2); +static_assert((5 * m / (2.5L * percent)).numerical_value_ == 2); +static_assert((5 * km / (2.5 * m)).numerical_value_ == 2); +static_assert((5000 * m / (2.5 * m)).numerical_value_ == 2000); + +static_assert((7 * m % (2 * m)).numerical_value_ == 1); +static_assert((7 * km % (2000 * m)).numerical_value_ == 1000); +static_assert((1300 * m % (1 * km)).numerical_value_ == 300); +static_assert((7 * one % (2 * one)).numerical_value_ == 1); static_assert((10 * m2 * (10 * m2)) / (50 * m2) == 2 * m2); -static_assert((10 * km / (5 * m)).numerical_value_ref_in(km / m) == 2); +static_assert((10 * km / (5 * m)).numerical_value_ == 2); static_assert((10 * km / (5 * m)).numerical_value_in(one) == 2000); -static_assert((10 * s * (2 * kHz)).numerical_value_ref_in(s * kHz) == 20); +static_assert((10 * s * (2 * kHz)).numerical_value_ == 20); // commutativity and associativity static_assert(10 * isq::length[si::metre] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]); @@ -743,16 +742,13 @@ static_assert(is_same_v); static_assert(1 * one - 30 * percent == (100 - 30) * percent); static_assert(1 * one + 30 * percent == (100 + 30) * percent); -static_assert(is_same_v); -static_assert(is_same_v); -static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_ref_in(one) == - +static_assert(is_same_v); +static_assert(is_same_v); +static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); -static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_ref_in(one) == - std::uint8_t(0) - std::uint8_t(1)); - -static_assert(is_same_v); +static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_ == std::uint8_t(0) - std::uint8_t(1)); +static_assert(is_same_v); static_assert(2 * one * (1 * m) == 2 * m); static_assert(2 * one / (1 * m) == 2 / (1 * m)); @@ -895,14 +891,14 @@ static_assert((50. * percent).numerical_value_in(one) == 0.5); // value_cast ////////////////// -static_assert(value_cast(2 * km).numerical_value_ref_in(m) == 2000); -static_assert(value_cast(2000 * m).numerical_value_ref_in(km) == 2); -static_assert(value_cast(1.23 * m).numerical_value_ref_in(m) == 1); -static_assert(value_cast(2000.0 * m / (3600.0 * s)).numerical_value_ref_in(km / h) == 2); +static_assert(value_cast(2 * km).numerical_value_ == 2000); +static_assert(value_cast(2000 * m).numerical_value_ == 2); +static_assert(value_cast(1.23 * m).numerical_value_ == 1); +static_assert(value_cast(2000.0 * m / (3600.0 * s)).numerical_value_ == 2); -static_assert((2 * km).force_in(m).numerical_value_ref_in(m) == 2000); -static_assert((2000 * m).force_in(km).numerical_value_ref_in(km) == 2); -static_assert((2000.0 * m / (3600.0 * s)).force_in(km / h).numerical_value_ref_in(km / h) == 2); +static_assert((2 * km).force_in(m).numerical_value_ == 2000); +static_assert((2000 * m).force_in(km).numerical_value_ == 2); +static_assert((2000.0 * m / (3600.0 * s)).force_in(km / h).numerical_value_ == 2); ////////////////// // quantity_cast From 2b3c9a6afae5e01f099f9a479e4603c540fa7d9b Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 20:06:17 +0200 Subject: [PATCH 20/22] feat: `quantity_point` compound assignment now preserves the value category --- src/core/include/mp-units/quantity_point.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 1f4a4940a..68dc3c4f9 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -224,18 +224,22 @@ class quantity_point { } // compound assignment operators - constexpr quantity_point& operator+=(const quantity_type& q) - requires requires { quantity_from_origin_ += q; } + template + requires std::derived_from, quantity_point> && + requires(quantity_type q) { quantity_from_origin_ += q; } + friend constexpr decltype(auto) operator+=(QP&& qp, const quantity_type& q) { - quantity_from_origin_ += q; - return *this; + qp.quantity_from_origin_ += q; + return std::forward(qp); } - constexpr quantity_point& operator-=(const quantity_type& q) - requires requires { quantity_from_origin_ -= q; } + template + requires std::derived_from, quantity_point> && + requires(quantity_type q) { quantity_from_origin_ -= q; } + friend constexpr decltype(auto) operator-=(QP&& qp, const quantity_type& q) { - quantity_from_origin_ -= q; - return *this; + qp.quantity_from_origin_ -= q; + return std::forward(qp); } private: From ff4755d5e58705aab16c56096e320bf3fa4e5846 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 13 Sep 2023 20:11:59 +0200 Subject: [PATCH 21/22] feat: `quantity_ref_from` disallowed for rvalues --- src/core/include/mp-units/quantity_point.h | 20 +- test/unit_test/static/quantity_point_test.cpp | 225 ++++++++---------- 2 files changed, 107 insertions(+), 138 deletions(-) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index 68dc3c4f9..bcf48acb8 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -146,34 +146,20 @@ class quantity_point { } // data access -#ifdef __cpp_explicit_this_parameter - template> PO2> - [[nodiscard]] constexpr auto&& quantity_ref_from(this Self&& self, PO2) noexcept - { - return std::forward(self).quantity_from_origin_; - } -#else template> PO2> [[nodiscard]] constexpr quantity_type& quantity_ref_from(PO2) & noexcept { return quantity_from_origin_; } + template> PO2> [[nodiscard]] constexpr const quantity_type& quantity_ref_from(PO2) const& noexcept { return quantity_from_origin_; } + template> PO2> - [[nodiscard]] constexpr quantity_type&& quantity_ref_from(PO2) && noexcept - { - return std::move(quantity_from_origin_); - } - template> PO2> - [[nodiscard]] constexpr const quantity_type&& quantity_ref_from(PO2) const&& noexcept - { - return std::move(quantity_from_origin_); - } -#endif + constexpr const quantity_type&& quantity_ref_from(PO2) const&& noexcept = delete; template requires requires { quantity_point{} - PO2{}; } diff --git a/test/unit_test/static/quantity_point_test.cpp b/test/unit_test/static/quantity_point_test.cpp index f7c5eb316..feb633d65 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -241,24 +241,19 @@ static_assert( // static member functions //////////////////////////// -static_assert( - quantity_point::zero().quantity_ref_from(mean_sea_level).numerical_value_ == 0); -static_assert( - quantity_point::min().quantity_ref_from(mean_sea_level).numerical_value_ == - std::numeric_limits::lowest()); -static_assert( - quantity_point::max().quantity_ref_from(mean_sea_level).numerical_value_ == - std::numeric_limits::max()); +static_assert(quantity_point::zero().quantity_from_origin_.numerical_value_ == 0); +static_assert(quantity_point::min().quantity_from_origin_.numerical_value_ == + std::numeric_limits::lowest()); +static_assert(quantity_point::max().quantity_from_origin_.numerical_value_ == + std::numeric_limits::max()); static_assert( - quantity_point::zero().quantity_ref_from(ground_level).numerical_value_ == 0); -static_assert( - quantity_point::min().quantity_ref_from(ground_level).numerical_value_ == - std::numeric_limits::lowest()); -static_assert( - quantity_point::max().quantity_ref_from(ground_level).numerical_value_ == - std::numeric_limits::max()); + quantity_point::zero().quantity_from_origin_.numerical_value_ == 0); +static_assert(quantity_point::min().quantity_from_origin_.numerical_value_ == + std::numeric_limits::lowest()); +static_assert(quantity_point::max().quantity_from_origin_.numerical_value_ == + std::numeric_limits::max()); ////////////////////////////// @@ -544,42 +539,36 @@ static_assert( // obtaining a relative quantity ////////////////////////////////// -static_assert((mean_sea_level + 42 * m).quantity_ref_from(mean_sea_level) == 42 * m); -static_assert((mean_sea_level + isq::height(42 * m)).quantity_ref_from(mean_sea_level) == 42 * m); +static_assert((mean_sea_level + 42 * m).quantity_from_origin_ == 42 * m); +static_assert((mean_sea_level + isq::height(42 * m)).quantity_from_origin_ == 42 * m); -static_assert((zero + 1 * one).quantity_ref_from(zero) == 1 * one); -static_assert((zero + dimensionless(1 * one)).quantity_ref_from(zero) == 1 * one); +static_assert((zero + 1 * one).quantity_from_origin_ == 1 * one); +static_assert((zero + dimensionless(1 * one)).quantity_from_origin_ == 1 * one); -static_assert((mean_sea_level + 42 * m).quantity_ref_from(mean_sea_level) == 42 * m); -static_assert((ground_level + 42 * m).quantity_ref_from(ground_level) == 42 * m); -static_assert((tower_peak + 42 * m).quantity_ref_from(tower_peak) == 42 * m); +static_assert((mean_sea_level + 42 * m).quantity_from_origin_ == 42 * m); +static_assert((ground_level + 42 * m).quantity_from_origin_ == 42 * m); +static_assert((tower_peak + 42 * m).quantity_from_origin_ == 42 * m); -static_assert(quantity_point(ground_level + 42 * m).quantity_ref_from(mean_sea_level) == - 84 * m); -static_assert(quantity_point(tower_peak + 42 * m).quantity_ref_from(mean_sea_level) == - 126 * m); +static_assert(quantity_point(ground_level + 42 * m).quantity_from_origin_ == 84 * m); +static_assert(quantity_point(tower_peak + 42 * m).quantity_from_origin_ == 126 * m); -static_assert(quantity_point(mean_sea_level + 84 * m).quantity_ref_from(ground_level) == - 42 * m); -static_assert(quantity_point(tower_peak + 42 * m).quantity_ref_from(ground_level) == - 84 * m); +static_assert(quantity_point(mean_sea_level + 84 * m).quantity_from_origin_ == 42 * m); +static_assert(quantity_point(tower_peak + 42 * m).quantity_from_origin_ == 84 * m); -static_assert(quantity_point(mean_sea_level + 42 * m).quantity_ref_from(tower_peak) == - -42 * m); -static_assert(quantity_point(ground_level + 84 * m).quantity_ref_from(tower_peak) == - 42 * m); +static_assert(quantity_point(mean_sea_level + 42 * m).quantity_from_origin_ == -42 * m); +static_assert(quantity_point(ground_level + 84 * m).quantity_from_origin_ == 42 * m); -static_assert((mean_sea_level + 42 * m).point_for(mean_sea_level).quantity_ref_from(mean_sea_level) == 42 * m); -static_assert((ground_level + 42 * m).point_for(mean_sea_level).quantity_ref_from(mean_sea_level) == 84 * m); -static_assert((tower_peak + 42 * m).point_for(mean_sea_level).quantity_ref_from(mean_sea_level) == 126 * m); +static_assert((mean_sea_level + 42 * m).point_for(mean_sea_level).quantity_from_origin_ == 42 * m); +static_assert((ground_level + 42 * m).point_for(mean_sea_level).quantity_from_origin_ == 84 * m); +static_assert((tower_peak + 42 * m).point_for(mean_sea_level).quantity_from_origin_ == 126 * m); -static_assert((ground_level + 84 * m).point_for(ground_level).quantity_ref_from(ground_level) == 84 * m); -static_assert((mean_sea_level + 84 * m).point_for(ground_level).quantity_ref_from(ground_level) == 42 * m); -static_assert((tower_peak + 42 * m).point_for(ground_level).quantity_ref_from(ground_level) == 84 * m); +static_assert((ground_level + 84 * m).point_for(ground_level).quantity_from_origin_ == 84 * m); +static_assert((mean_sea_level + 84 * m).point_for(ground_level).quantity_from_origin_ == 42 * m); +static_assert((tower_peak + 42 * m).point_for(ground_level).quantity_from_origin_ == 84 * m); -static_assert((tower_peak + 42 * m).point_for(tower_peak).quantity_ref_from(tower_peak) == 42 * m); -static_assert((mean_sea_level + 42 * m).point_for(tower_peak).quantity_ref_from(tower_peak) == -42 * m); -static_assert((ground_level + 84 * m).point_for(tower_peak).quantity_ref_from(tower_peak) == 42 * m); +static_assert((tower_peak + 42 * m).point_for(tower_peak).quantity_from_origin_ == 42 * m); +static_assert((mean_sea_level + 42 * m).point_for(tower_peak).quantity_from_origin_ == -42 * m); +static_assert((ground_level + 84 * m).point_for(tower_peak).quantity_from_origin_ == 42 * m); static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(mean_sea_level), quantity_point>); @@ -589,15 +578,15 @@ static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(m // converting to a different unit /////////////////////////////////// -static_assert((mean_sea_level + 2. * km).in(km).quantity_ref_from(mean_sea_level).numerical_value_ == 2.); -static_assert((mean_sea_level + 2. * km).in(m).quantity_ref_from(mean_sea_level).numerical_value_ == 2000.); -static_assert((mean_sea_level + 2000. * m).in(km).quantity_ref_from(mean_sea_level).numerical_value_ == 2.); -static_assert((ground_level + 2. * km).in(km).quantity_ref_from(ground_level).numerical_value_ == 2.); -static_assert((ground_level + 2. * km).in(m).quantity_ref_from(ground_level).numerical_value_ == 2000.); -static_assert((ground_level + 2000. * m).in(km).quantity_ref_from(ground_level).numerical_value_ == 2.); -static_assert((tower_peak + 2. * km).in(km).quantity_ref_from(tower_peak).numerical_value_ == 2.); -static_assert((tower_peak + 2. * km).in(m).quantity_ref_from(tower_peak).numerical_value_ == 2000.); -static_assert((tower_peak + 2000. * m).in(km).quantity_ref_from(tower_peak).numerical_value_ == 2.); +static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin_.numerical_value_ == 2.); +static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin_.numerical_value_ == 2000.); +static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin_.numerical_value_ == 2.); +static_assert((ground_level + 2. * km).in(km).quantity_from_origin_.numerical_value_ == 2.); +static_assert((ground_level + 2. * km).in(m).quantity_from_origin_.numerical_value_ == 2000.); +static_assert((ground_level + 2000. * m).in(km).quantity_from_origin_.numerical_value_ == 2.); +static_assert((tower_peak + 2. * km).in(km).quantity_from_origin_.numerical_value_ == 2.); +static_assert((tower_peak + 2. * km).in(m).quantity_from_origin_.numerical_value_ == 2000.); +static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin_.numerical_value_ == 2.); #if MP_UNITS_COMP_GCC != 10 || MP_UNITS_COMP_GCC_MINOR > 2 template typename QP> @@ -629,18 +618,18 @@ static_assert(([]() { quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m}; return l2 = l1; }()) - .quantity_ref_from(mean_sea_level) == 1 * m); + .quantity_from_origin_ == 1 * m); static_assert(([]() { const quantity_point l1{mean_sea_level + 1 * m}; quantity_point l2{mean_sea_level + 2 * m}; return l2 = l1; }()) - .quantity_ref_from(mean_sea_level) == 1 * m); + .quantity_from_origin_ == 1 * m); static_assert(([]() { quantity_point l1{mean_sea_level + 1 * m}, l2{mean_sea_level + 2 * m}; return l2 = std::move(l1); }()) - .quantity_ref_from(mean_sea_level) == 1 * m); + .quantity_from_origin_ == 1 * m); //////////////////// @@ -670,14 +659,14 @@ static_assert([](auto v) { //////////////////////// // same type -static_assert((mean_sea_level + 1 * m += 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2); -static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1); +static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin_.numerical_value_ == 2); +static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin_.numerical_value_ == 1); // different types -static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 5.5); -static_assert((mean_sea_level + 123 * m += 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1123); -static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); -static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 123); +static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin_.numerical_value_ == 5.5); +static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin_.numerical_value_ == 1123); +static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin_.numerical_value_ == 2.5); +static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin_.numerical_value_ == 123); template typename QP> @@ -949,29 +938,23 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu // check for integral types promotion static_assert(is_same_v); static_assert(is_same_v); static_assert(is_same_v); static_assert( is_same_v< decltype(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(0) * m)).numerical_value_), int>); static_assert(((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m) - .quantity_ref_from(mean_sea_level) - .numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); + .quantity_from_origin_.numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); static_assert((std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)) - .quantity_ref_from(mean_sea_level) - .numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); -static_assert( - ((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_ref_from(mean_sea_level).numerical_value_ == - std::uint8_t(0) - std::uint8_t(1)); + .quantity_from_origin_.numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); +static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin_.numerical_value_ == + std::uint8_t(0) - std::uint8_t(1)); static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value_ == std::uint8_t(0) - std::uint8_t(1)); @@ -1027,32 +1010,32 @@ static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m), static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity>); -static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2); -static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 2); -static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); -static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); -static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); -static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001); -static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1); -static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 999); - -static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); -static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); -static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); -static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); -static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); -static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); -static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1.5); -static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1499); - -static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); -static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 2.5); -static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); -static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_ref_from(mean_sea_level).numerical_value_ == 1501); -static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); -static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_ref_from(mean_sea_level).numerical_value_ == 1001.5); -static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 0.5); -static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_ref_from(mean_sea_level).numerical_value_ == 998.5); +static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin_.numerical_value_ == 2); +static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 2); +static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin_.numerical_value_ == 1001); +static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin_.numerical_value_ == 1001); +static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin_.numerical_value_ == 1001); +static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 1001); +static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin_.numerical_value_ == 1); +static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin_.numerical_value_ == 999); + +static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin_.numerical_value_ == 2.5); +static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 2.5); +static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin_.numerical_value_ == 1001.5); +static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin_.numerical_value_ == 1001.5); +static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin_.numerical_value_ == 1501); +static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 1501); +static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin_.numerical_value_ == 1.5); +static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin_.numerical_value_ == 1499); + +static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin_.numerical_value_ == 2.5); +static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin_.numerical_value_ == 2.5); +static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin_.numerical_value_ == 1501); +static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin_.numerical_value_ == 1501); +static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin_.numerical_value_ == 1001.5); +static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin_.numerical_value_ == 1001.5); +static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin_.numerical_value_ == 0.5); +static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin_.numerical_value_ == 998.5); static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ == 1); static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ == 999); @@ -1072,15 +1055,15 @@ static_assert((ground_level + 42 * m) - (other_ground_level + 42 * m) == -81 * m static_assert((other_ground_level + 42 * m) - (tower_peak + 42 * m) == 39 * m); static_assert((tower_peak + 42 * m) - (other_ground_level + 42 * m) == -39 * m); -static_assert((mean_sea_level + 42 * m).quantity_ref_from(mean_sea_level) == 42 * m); -static_assert((42 * m + mean_sea_level).quantity_ref_from(mean_sea_level) == 42 * m); -static_assert((mean_sea_level - 42 * m).quantity_ref_from(mean_sea_level) == -42 * m); -static_assert((ground_level + 42 * m).quantity_ref_from(ground_level) == 42 * m); -static_assert((42 * m + ground_level).quantity_ref_from(ground_level) == 42 * m); -static_assert((ground_level - 42 * m).quantity_ref_from(ground_level) == -42 * m); -static_assert((tower_peak + 42 * m).quantity_ref_from(tower_peak) == 42 * m); -static_assert((42 * m + tower_peak).quantity_ref_from(tower_peak) == 42 * m); -static_assert((tower_peak - 42 * m).quantity_ref_from(tower_peak) == -42 * m); +static_assert((mean_sea_level + 42 * m).quantity_from_origin_ == 42 * m); +static_assert((42 * m + mean_sea_level).quantity_from_origin_ == 42 * m); +static_assert((mean_sea_level - 42 * m).quantity_from_origin_ == -42 * m); +static_assert((ground_level + 42 * m).quantity_from_origin_ == 42 * m); +static_assert((42 * m + ground_level).quantity_from_origin_ == 42 * m); +static_assert((ground_level - 42 * m).quantity_from_origin_ == -42 * m); +static_assert((tower_peak + 42 * m).quantity_from_origin_ == 42 * m); +static_assert((42 * m + tower_peak).quantity_from_origin_ == 42 * m); +static_assert((tower_peak - 42 * m).quantity_from_origin_ == -42 * m); static_assert((mean_sea_level + 42 * m) - ground_level == 0 * m); static_assert((ground_level + 42 * m) - mean_sea_level == 84 * m); @@ -1131,17 +1114,17 @@ inline constexpr struct zero_m_per_s : absolute_point_origin // commutativity and associativity static_assert(((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + 5 * isq::speed[m / s]) - .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); + .quantity_from_origin_ == 10 * isq::speed[m / s]); static_assert((10 * isq::height[m] / (2 * isq::time[s]) + (zero_m_per_s + 5 * isq::speed[m / s])) - .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); + .quantity_from_origin_ == 10 * isq::speed[m / s]); static_assert(((zero_m_per_s + 5 * isq::speed[m / s]) + 10 * isq::height[m] / (2 * isq::time[s])) - .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); + .quantity_from_origin_ == 10 * isq::speed[m / s]); static_assert((5 * isq::speed[m / s] + (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s]))) - .quantity_ref_from(zero_m_per_s) == 10 * isq::speed[m / s]); + .quantity_from_origin_ == 10 * isq::speed[m / s]); static_assert(((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - 5 * isq::speed[m / s]) - .quantity_ref_from(zero_m_per_s) == 0 * isq::speed[m / s]); + .quantity_from_origin_ == 0 * isq::speed[m / s]); static_assert(((zero_m_per_s + 5 * isq::speed[m / s]) - 10 * isq::height[m] / (2 * isq::time[s])) - .quantity_ref_from(zero_m_per_s) == 0 * isq::speed[m / s]); + .quantity_from_origin_ == 0 * isq::speed[m / s]); static_assert((zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) - (zero_m_per_s + 5 * isq::speed[m / s]) == 0 * isq::speed[m / s]); static_assert((zero_m_per_s + 5 * isq::speed[m / s]) - (zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) == @@ -1173,17 +1156,17 @@ static_assert( inline constexpr struct zero_Hz : absolute_point_origin> { } zero_Hz; -static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_ref_from(zero_Hz) == +static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_from_origin_ == 10 * isq::frequency[Hz]); -static_assert((10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz])).quantity_ref_from(zero_Hz) == +static_assert((10 / (2 * isq::period_duration[s]) + (zero_Hz + 5 * isq::frequency[Hz])).quantity_from_origin_ == 10 * isq::frequency[Hz]); -static_assert(((zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s])).quantity_ref_from(zero_Hz) == +static_assert(((zero_Hz + 5 * isq::frequency[Hz]) + 10 / (2 * isq::period_duration[s])).quantity_from_origin_ == 10 * isq::frequency[Hz]); -static_assert((5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s]))).quantity_ref_from(zero_Hz) == +static_assert((5 * isq::frequency[Hz] + (zero_Hz + 10 / (2 * isq::period_duration[s]))).quantity_from_origin_ == 10 * isq::frequency[Hz]); -static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz]).quantity_ref_from(zero_Hz) == +static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) - 5 * isq::frequency[Hz]).quantity_from_origin_ == 0 * isq::frequency[Hz]); -static_assert(((zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s])).quantity_ref_from(zero_Hz) == +static_assert(((zero_Hz + 5 * isq::frequency[Hz]) - 10 / (2 * isq::period_duration[s])).quantity_from_origin_ == 0 * isq::frequency[Hz]); static_assert((zero_Hz + 10 / (2 * isq::period_duration[s])) - (zero_Hz + 5 * isq::frequency[Hz]) == 0 * isq::frequency[Hz]); From b76337d5bb181c41f3a4cfb51915379587887f68 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 14 Sep 2023 12:42:45 +0200 Subject: [PATCH 22/22] feat: pre-increment and pre-decrement operators now preserve value category --- src/core/include/mp-units/quantity.h | 18 ++++++++++-------- src/core/include/mp-units/quantity_point.h | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 2e9fab497..c8d1d3196 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -210,15 +210,16 @@ class quantity { return make_quantity(-numerical_value_); } - constexpr quantity& operator++() - requires requires(rep v) { + template + friend constexpr decltype(auto) operator++(Q&& q) + requires std::derived_from, quantity> && requires(rep v) { { ++v } -> std::same_as; } { - ++numerical_value_; - return *this; + ++q.numerical_value_; + return std::forward(q); } [[nodiscard]] constexpr Quantity auto operator++(int) @@ -231,15 +232,16 @@ class quantity { return make_quantity(numerical_value_++); } - constexpr quantity& operator--() - requires requires(rep v) { + template + friend constexpr decltype(auto) operator--(Q&& q) + requires std::derived_from, quantity> && requires(rep v) { { --v } -> std::same_as; } { - --numerical_value_; - return *this; + --q.numerical_value_; + return std::forward(q); } [[nodiscard]] constexpr Quantity auto operator--(int) diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index bcf48acb8..910620233 100644 --- a/src/core/include/mp-units/quantity_point.h +++ b/src/core/include/mp-units/quantity_point.h @@ -183,11 +183,12 @@ class quantity_point { } // member unary operators - constexpr quantity_point& operator++() - requires requires { ++quantity_from_origin_; } + template + friend constexpr decltype(auto) operator++(QP&& qp) + requires std::derived_from, quantity_point> && requires { ++qp.quantity_from_origin_; } { - ++quantity_from_origin_; - return *this; + ++qp.quantity_from_origin_; + return std::forward(qp); } [[nodiscard]] constexpr quantity_point operator++(int) @@ -196,11 +197,12 @@ class quantity_point { return quantity_point(quantity_from_origin_++); } - constexpr quantity_point& operator--() - requires requires { --quantity_from_origin_; } + template + friend constexpr decltype(auto) operator--(QP&& qp) + requires std::derived_from, quantity_point> && requires { --qp.quantity_from_origin_; } { - --quantity_from_origin_; - return *this; + --qp.quantity_from_origin_; + return std::forward(qp); } [[nodiscard]] constexpr quantity_point operator--(int)