diff --git a/example/conversion_factor.cpp b/example/conversion_factor.cpp index a3b81051..cd9a4cfb 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 587f1f7d..bb5d9b39 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 4b0a3ec4..510584d9 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 @@ private: 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 5fc8489c..c648a810 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 fea62a49..fe88b85a 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 e8a2c1f0..75b53dc9 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 674f44c7..81600158 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -126,7 +126,7 @@ public: 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 @@ public: // 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 @@ public: } -> 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 @@ public: } -> std::common_with; } { - return make_quantity(-numerical_value()); + return make_quantity(-numerical_value_ref_in(unit)); } constexpr quantity& operator++() @@ -240,7 +261,7 @@ public: } -> std::same_as; } { - value_ += q.numerical_value(); + value_ += q.numerical_value_ref_in(unit); return *this; } @@ -251,7 +272,7 @@ public: } -> std::same_as; } { - value_ -= q.numerical_value(); + value_ -= q.numerical_value_ref_in(unit); return *this; } @@ -263,7 +284,7 @@ public: } { gsl_ExpectsAudit(q != zero()); - value_ %= q.numerical_value(); + value_ %= q.numerical_value_ref_in(unit); return *this; } @@ -287,7 +308,7 @@ public: } 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 @@ public: 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 0bd2fe95..b55adf62 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 aca9ad48..f868d84b 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 e367ce4b..00b5aff4 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 2c26b97a..fd2ceda9 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 @@ public: 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 @@ public: 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 69b972c1..038dfb6e 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 b7f45971..bbf7c5ef 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 818031f4..8d2cd1e7 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 4e838273..3391e900 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 e93ebf09..b86478c3 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 * 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() == 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.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() == 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 + 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() == 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 + 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 0fdc13b3..83c43c96 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((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() != [] { std::uint8_t ui(255); return ui %= 256; +// 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 * 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() == 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.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() == 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((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() == 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((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() == - 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(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(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