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: 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/conversion_factor.cpp b/example/conversion_factor.cpp index a3b810512..5a4eaa97a 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 (1. * Source::reference).force_numerical_value_in(Target::unit); } } // namespace @@ -56,6 +56,7 @@ 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..40892ad2a 100644 --- a/example/currency.cpp +++ b/example/currency.cpp @@ -81,9 +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()) * To}; + return quantity_point{zero + static_cast(exchange_rate() * + (q - q.absolute_point_origin).numerical_value_in(q.unit)) * + To}; } int main() @@ -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_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_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/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/include/geographic.h b/example/include/geographic.h index e24a0aaba..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_from_origin() : -lat.quantity_from_origin(), 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,7 +151,8 @@ 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_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(); } @@ -171,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_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 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/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/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/example/unmanned_aerial_vehicle.cpp b/example/unmanned_aerial_vehicle.cpp index 0aca9c832..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_from_origin().numerical_value_in(si::degree), - pos.lon.quantity_from_origin().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_from_origin() << " 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_from_origin(), 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-fmt/include/mp-units/format.h b/src/core-fmt/include/mp-units/format.h index 4b0a3ec4c..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()), specs(fspecs), loc(std::move(lc)) + out(o), val(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..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()); + return make_quantity(std::forward(q).numerical_value_); else - return make_quantity{}>(std::forward(q).numerical_value()); + 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 e8a2c1f02..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())); // 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,7 +78,7 @@ 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()) * + 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 674f44c77..c8d1d3196 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()) + numerical_value_(detail::sudo_cast(q).numerical_value_) { } @@ -141,32 +141,52 @@ 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 - [[nodiscard]] constexpr auto&& value(this Self&& self) noexcept + template + requires(U{} == unit) + [[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept { - return std::forward(self).value_; + return numerical_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_); } -#endif + + template + requires(U{} == unit) + [[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept + { + return numerical_value_; + } + + template + requires(U{} == unit) + 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(); + return (*this).in(U{}).numerical_value_; } template - requires detail::QuantityConvertibleTo> - [[nodiscard]] constexpr quantity in(U) const + requires requires(quantity q) { q.force_in(U{}); } + [[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept { - return quantity{*this}; + return (*this).force_in(U{}).numerical_value_; } // member unary operators @@ -177,7 +197,7 @@ class quantity { } -> std::common_with; } { - return make_quantity(+numerical_value()); + return make_quantity(+numerical_value_); } [[nodiscard]] constexpr Quantity auto operator-() const @@ -187,18 +207,19 @@ class quantity { } -> std::common_with; } { - return make_quantity(-numerical_value()); + 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; } { - ++value_; - return *this; + ++q.numerical_value_; + return std::forward(q); } [[nodiscard]] constexpr Quantity auto operator++(int) @@ -208,18 +229,19 @@ class quantity { } -> std::common_with; } { - return make_quantity(value_++); + 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; } { - --value_; - return *this; + --q.numerical_value_; + return std::forward(q); } [[nodiscard]] constexpr Quantity auto operator--(int) @@ -229,92 +251,101 @@ class quantity { } -> std::common_with; } { - return make_quantity(value_--); + return make_quantity(numerical_value_--); } // 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) { - value_ += q.numerical_value(); - 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) { - value_ -= q.numerical_value(); - 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()); - value_ %= q.numerical_value(); - 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) { - 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) { - value_ *= rhs.numerical_value(); - 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()); - 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()); - value_ /= rhs.numerical_value(); - return *this; + lhs.numerical_value_ /= rhs.numerical_value_; + return std::forward(lhs); } private: @@ -327,7 +358,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)) { } }; @@ -342,7 +373,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() + ret(rhs).numerical_value()); + return make_quantity(ret(lhs).numerical_value_ + ret(rhs).numerical_value_); } template @@ -350,7 +381,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() - ret(rhs).numerical_value()); + return make_quantity(ret(lhs).numerical_value_ - ret(rhs).numerical_value_); } template @@ -360,7 +391,7 @@ 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_ % ret(rhs).numerical_value_); } template @@ -368,7 +399,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_ * rhs.numerical_value_); } template @@ -376,7 +407,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_ * v); } template @@ -384,7 +415,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_); } template @@ -392,7 +423,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_ / rhs.numerical_value_); } template @@ -401,7 +432,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_ / v); } template @@ -409,7 +440,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_); } template @@ -418,7 +449,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_ == ct(rhs).numerical_value_; } template @@ -427,7 +458,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_ <=> ct(rhs).numerical_value_; } // make_quantity diff --git a/src/core/include/mp-units/quantity_point.h b/src/core/include/mp-units/quantity_point.h index d736d2790..910620233 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,10 +112,10 @@ 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_from_origin(); + return qp.quantity_ref_from(point_origin); else return qp - 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)) { } @@ -145,66 +146,88 @@ 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 quantity_type& quantity_ref_from(PO2) & noexcept { - return std::forward(self).q_; + return quantity_from_origin_; + } + + template> PO2> + [[nodiscard]] constexpr const quantity_type& quantity_ref_from(PO2) const& noexcept + { + return quantity_from_origin_; + } + + template> PO2> + constexpr const quantity_type&& quantity_ref_from(PO2) const&& noexcept = delete; + + template + requires requires { quantity_point{} - PO2{}; } + [[nodiscard]] constexpr Quantity auto quantity_from(PO2) const + { + return *this - PO2{}; + } + + template + requires detail::QuantityConvertibleTo> + [[nodiscard]] constexpr quantity_point in(U) const + { + return make_quantity_point(quantity_ref_from(PO).in(U{})); } -#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_); } -#endif template - requires detail::QuantityConvertibleTo{}, Rep>> - [[nodiscard]] constexpr quantity_point<::mp_units::reference{}, PO, Rep> in(U) const + requires requires(quantity_type q) { value_cast(q); } + [[nodiscard]] constexpr quantity_point force_in(U) const { - return make_quantity_point(quantity_from_origin().in(U{})); + return make_quantity_point(quantity_ref_from(PO).force_in(U{})); } // member unary operators - constexpr quantity_point& operator++() - requires requires { ++q_; } + template + friend constexpr decltype(auto) operator++(QP&& qp) + requires std::derived_from, quantity_point> && requires { ++qp.quantity_from_origin_; } { - ++q_; - return *this; + ++qp.quantity_from_origin_; + return std::forward(qp); } [[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_; } + template + friend constexpr decltype(auto) operator--(QP&& qp) + requires std::derived_from, quantity_point> && requires { --qp.quantity_from_origin_; } { - --q_; - return *this; + --qp.quantity_from_origin_; + return std::forward(qp); } [[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; } + 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) { - q_ += q; - return *this; + qp.quantity_from_origin_ += q; + return std::forward(qp); } - constexpr quantity_point& operator-=(const quantity_type& q) - requires requires { q_ -= 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) { - q_ -= q; - return *this; + qp.quantity_from_origin_ -= q; + return std::forward(qp); } private: @@ -219,7 +242,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)) { } }; @@ -235,9 +258,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 +268,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 +292,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 +308,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 +323,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 +370,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 +381,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/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index 0bd2fe95e..b6e2e2a1a 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -111,7 +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()); + return make_quantity::unit>{}>(std::forward(q).numerical_value_); } #else template U> @@ -128,7 +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()); + return make_quantity::unit>{}>(std::forward(q).numerical_value_); } #endif }; @@ -307,7 +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()); + return make_quantity::unit>{}>(std::forward(q).numerical_value_); } #endif }; 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); 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..7bdf71893 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())))); + make_quantity(R)>(static_cast(exp(q.force_numerical_value_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,10 +158,10 @@ 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); + q.force_in(To); quantity_values::one(); }) { @@ -169,16 +174,17 @@ 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())))); + return handle_signed_results( + make_quantity(R)>(static_cast(floor(q.force_numerical_value_in(To))))); } } 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)); } } } @@ -191,10 +197,10 @@ 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); + q.force_in(To); quantity_values::one(); }) { @@ -207,16 +213,17 @@ 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())))); + return handle_signed_results( + make_quantity(R)>(static_cast(ceil(q.force_numerical_value_in(To))))); } } 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)); } } } @@ -231,8 +238,8 @@ 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,9 +248,10 @@ 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); + return q.force_in(To); } } else { const auto res_low = mp_units::floor(q); @@ -251,7 +259,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 +280,8 @@ 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 +298,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 +317,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(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 @@ -317,12 +332,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(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 @@ -331,12 +347,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(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 @@ -345,12 +362,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(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 @@ -359,12 +377,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(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 @@ -373,12 +392,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(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 @@ -391,12 +411,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(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 @@ -405,12 +426,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(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 @@ -419,12 +441,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(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 @@ -433,12 +456,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(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 @@ -447,12 +471,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(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 @@ -461,12 +486,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(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/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..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(); - const auto y = common(other).numerical_value(); + 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/distribution_test.cpp b/test/unit_test/runtime/distribution_test.cpp index b7f459713..5b14ae7f1 100644 --- a/test/unit_test/runtime/distribution_test.cpp +++ b/test/unit_test/runtime/distribution_test.cpp @@ -559,8 +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(); }); + 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()); @@ -573,8 +573,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()); @@ -627,8 +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(); }); + 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()); @@ -641,8 +641,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..ad9fb31f4 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 @@ -74,7 +82,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 +95,21 @@ 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(v.force_numerical_value_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); + CHECK(speed.numerical_value_ref_in(km / h) == 7); } SECTION("multiply by scalar value") @@ -109,14 +118,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_ == 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() == 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_ == vector{0.5, 1., 1.5}); } + SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_ == vector{0.5, 1., 1.5}); } } } @@ -124,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() == vector{1, 2, 3}); } - SECTION("floating-point") { CHECK((v / 0.5).numerical_value() == 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") @@ -135,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() == 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() == vector{3001, 2002, 1003}); + CHECK((v + u).numerical_value_ == vector{3001, 2002, 1003}); } } @@ -151,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() == 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() == vector{-2999, -1998, -997}); + CHECK((v - u).numerical_value_ == vector{-2999, -1998, -997}); } } @@ -170,18 +179,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_ == 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() == 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() == vector{2, 4, 6}); + CHECK(quantity_cast(v * mass).numerical_value_ == vector{2, 4, 6}); } } SECTION("quantity of momentum") @@ -189,12 +198,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_ == 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_ == vector{2, 4, 6}); } } } @@ -205,18 +214,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_ == 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() == 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() == vector{0.5, 1., 1.5}); + CHECK(quantity_cast(v * mass).numerical_value_ == vector{0.5, 1., 1.5}); } } SECTION("quantity of momentum") @@ -224,12 +233,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_ == 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_ == vector{0.5, 1., 1.5}); } } } @@ -243,15 +252,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_ == 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_ == 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_ == vector{15, 10, 5}); } } @@ -259,15 +268,15 @@ 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_ == 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_ == 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_ == vector{60, 40, 20}); } } } @@ -303,8 +312,8 @@ 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); + 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..fdf5e1dc3 100644 --- a/test/unit_test/runtime/math_test.cpp +++ b/test/unit_test/runtime/math_test.cpp @@ -90,12 +90,12 @@ 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_ == 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_ == 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..feb633d65 100644 --- a/test/unit_test/static/quantity_point_test.cpp +++ b/test/unit_test/static/quantity_point_test.cpp @@ -241,16 +241,18 @@ 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_ == 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() == +static_assert(quantity_point::max().quantity_from_origin_.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() == +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() == +static_assert(quantity_point::max().quantity_from_origin_.numerical_value_ == std::numeric_limits::max()); @@ -537,36 +539,36 @@ 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_from_origin_ == 42 * m); +static_assert((mean_sea_level + isq::height(42 * m)).quantity_from_origin_ == 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_from_origin_ == 1 * one); +static_assert((zero + dimensionless(1 * one)).quantity_from_origin_ == 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_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_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_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_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_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_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_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_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_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_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_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_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_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>); @@ -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_ == 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> @@ -616,18 +618,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_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_from_origin() == 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_from_origin() == 1 * m); + .quantity_from_origin_ == 1 * m); //////////////////// @@ -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_ == 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_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_ == 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> @@ -935,30 +937,25 @@ 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) + 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( - ((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m).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_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() == + 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_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_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() == +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 @@ -1013,39 +1010,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_ == 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 + 42 * m) - (ground_level + 42 * m) == -42 * m); static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m); @@ -1058,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_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_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); @@ -1079,6 +1076,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); @@ -1106,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_from_origin() == 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_from_origin() == 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_from_origin() == 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_from_origin() == 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_from_origin() == 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_from_origin() == 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])) == @@ -1148,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_from_origin() == +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_from_origin() == +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_from_origin() == +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_from_origin() == +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_from_origin() == +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_from_origin() == +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]); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 0fdc13b3f..77091cb73 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -112,14 +112,14 @@ 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_ == 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()); ////////////////////////////// @@ -190,10 +190,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_ == 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); /////////////////////////////////// @@ -204,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() == 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_ == 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> @@ -308,28 +308,28 @@ static_assert([] { auto l1(1 * m), l2(2 * m); return l2 = l1; }() - .numerical_value() == 1); + .numerical_value_ == 1); static_assert([] { const auto l1(1 * m); auto l2(2 * m); return l2 = l1; }() - .numerical_value() == 1); + .numerical_value_ == 1); static_assert([]() { auto l1(1 * m), l2(2 * m); return l2 = std::move(l1); }() - .numerical_value() == 1); + .numerical_value_ == 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_ == 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++; @@ -348,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); //////////////////////// @@ -356,29 +356,31 @@ 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_ == 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); // 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_ == 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; // }()); // 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_ != [] { 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_ == 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); #endif template typename Q> @@ -516,14 +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_ == 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_ == 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>); @@ -596,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() == 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_ == 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() == 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_ == 2); +static_assert((10 * km / (5 * m)).numerical_value_in(one) == 2000); +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]); @@ -740,14 +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() == +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((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)); @@ -880,20 +881,24 @@ 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_ == 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_ == 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