From d03482fa1bb87a93ef1692b45ea81ba39144a533 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 19 Jun 2024 21:10:16 +0200 Subject: [PATCH 01/11] feat: `absolute` and `relative` reference modifiers support added --- .../kalman_filter/kalman_filter-example_6.cpp | 14 ++-- .../kalman_filter/kalman_filter-example_7.cpp | 14 ++-- .../kalman_filter/kalman_filter-example_8.cpp | 14 ++-- example/spectroscopy_units.cpp | 2 +- src/core/include/mp-units/bits/sudo_cast.h | 13 ++-- .../include/mp-units/framework/quantity.h | 64 +++++++++++-------- .../mp-units/framework/quantity_cast.h | 2 +- .../mp-units/framework/quantity_spec.h | 6 +- .../include/mp-units/framework/reference.h | 29 ++++++--- .../mp-units/framework/reference_concepts.h | 29 +++++++++ src/core/include/mp-units/math.h | 18 +++--- .../include/mp-units/systems/si/units.h | 2 +- src/systems/include/mp-units/systems/usc.h | 2 +- test/static/quantity_point_test.cpp | 16 ++--- test/static/usc_test.cpp | 3 +- 15 files changed, 142 insertions(+), 86 deletions(-) diff --git a/example/kalman_filter/kalman_filter-example_6.cpp b/example/kalman_filter/kalman_filter-example_6.cpp index 2dc55ba1..d70b974a 100644 --- a/example/kalman_filter/kalman_filter-example_6.cpp +++ b/example/kalman_filter/kalman_filter-example_6.cpp @@ -62,12 +62,14 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.0001 * pow<2>(deg_C); - const estimate initial{state{qp{60. * deg_C}}, 100. * deg_C}; - const std::array measurements = {qp{49.986 * deg_C}, qp{49.963 * deg_C}, qp{50.097 * deg_C}, qp{50.001 * deg_C}, - qp{50.018 * deg_C}, qp{50.05 * deg_C}, qp{49.938 * deg_C}, qp{49.858 * deg_C}, - qp{49.965 * deg_C}, qp{50.114 * deg_C}}; - const quantity measurement_error = 0.1 * deg_C; + const quantity process_noise_variance = 0.0001 * relative(pow<2>(deg_C)); + const estimate initial{state{qp{60. * relative(deg_C)}}, 100. * relative(deg_C)}; + const std::array measurements = {qp{49.986 * relative(deg_C)}, qp{49.963 * relative(deg_C)}, + qp{50.097 * relative(deg_C)}, qp{50.001 * relative(deg_C)}, + qp{50.018 * relative(deg_C)}, qp{50.05 * relative(deg_C)}, + qp{49.938 * relative(deg_C)}, qp{49.858 * relative(deg_C)}, + qp{49.965 * relative(deg_C)}, qp{50.114 * relative(deg_C)}}; + const quantity measurement_error = 0.1 * relative(deg_C); const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/kalman_filter/kalman_filter-example_7.cpp b/example/kalman_filter/kalman_filter-example_7.cpp index 62ce652b..104d08f6 100644 --- a/example/kalman_filter/kalman_filter-example_7.cpp +++ b/example/kalman_filter/kalman_filter-example_7.cpp @@ -62,12 +62,14 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.0001 * pow<2>(deg_C); - const estimate initial{state{qp{10. * deg_C}}, 100. * deg_C}; - const std::array measurements = {qp{50.486 * deg_C}, qp{50.963 * deg_C}, qp{51.597 * deg_C}, qp{52.001 * deg_C}, - qp{52.518 * deg_C}, qp{53.05 * deg_C}, qp{53.438 * deg_C}, qp{53.858 * deg_C}, - qp{54.465 * deg_C}, qp{55.114 * deg_C}}; - const quantity measurement_error = 0.1 * deg_C; + const quantity process_noise_variance = 0.0001 * relative(pow<2>(deg_C)); + const estimate initial{state{qp{10. * relative(deg_C)}}, 100. * relative(deg_C)}; + const std::array measurements = {qp{50.486 * relative(deg_C)}, qp{50.963 * relative(deg_C)}, + qp{51.597 * relative(deg_C)}, qp{52.001 * relative(deg_C)}, + qp{52.518 * relative(deg_C)}, qp{53.05 * relative(deg_C)}, + qp{53.438 * relative(deg_C)}, qp{53.858 * relative(deg_C)}, + qp{54.465 * relative(deg_C)}, qp{55.114 * relative(deg_C)}}; + const quantity measurement_error = 0.1 * relative(deg_C); const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/kalman_filter/kalman_filter-example_8.cpp b/example/kalman_filter/kalman_filter-example_8.cpp index 760212ec..d818140e 100644 --- a/example/kalman_filter/kalman_filter-example_8.cpp +++ b/example/kalman_filter/kalman_filter-example_8.cpp @@ -62,12 +62,14 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.15 * pow<2>(deg_C); - const estimate initial{state{qp{10. * deg_C}}, 100. * deg_C}; - const std::array measurements = {qp{50.486 * deg_C}, qp{50.963 * deg_C}, qp{51.597 * deg_C}, qp{52.001 * deg_C}, - qp{52.518 * deg_C}, qp{53.05 * deg_C}, qp{53.438 * deg_C}, qp{53.858 * deg_C}, - qp{54.465 * deg_C}, qp{55.114 * deg_C}}; - const quantity measurement_error = 0.1 * deg_C; + const quantity process_noise_variance = 0.15 * relative(pow<2>(deg_C)); + const estimate initial{state{qp{10. * relative(deg_C)}}, 100. * relative(deg_C)}; + const std::array measurements = {qp{50.486 * relative(deg_C)}, qp{50.963 * relative(deg_C)}, + qp{51.597 * relative(deg_C)}, qp{52.001 * relative(deg_C)}, + qp{52.518 * relative(deg_C)}, qp{53.05 * relative(deg_C)}, + qp{53.438 * relative(deg_C)}, qp{53.858 * relative(deg_C)}, + qp{54.465 * relative(deg_C)}, qp{55.114 * relative(deg_C)}}; + const quantity measurement_error = 0.1 * relative(deg_C); const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/spectroscopy_units.cpp b/example/spectroscopy_units.cpp index e64eee8f..85fe8344 100644 --- a/example/spectroscopy_units.cpp +++ b/example/spectroscopy_units.cpp @@ -84,7 +84,7 @@ int main() const auto t3 = std::make_tuple(isq::energy(q3 * h), isq::wavenumber(q3 / c), q3, isq::thermodynamic_temperature(q3 * h / kb), isq::wavelength(c / q3)); - const auto q4 = isq::thermodynamic_temperature(1. * K); + const auto q4 = isq::thermodynamic_temperature(1. * relative(K)); const auto t4 = std::make_tuple(isq::energy(q4 * kb), isq::wavenumber(q4 * kb / (h * c)), isq::frequency(q4 * kb / h), q4, isq::wavelength(h * c / (q4 * kb))); diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index 0444f93e..768a5dc5 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -97,10 +97,10 @@ template if constexpr (q_unit == To::unit) { // no scaling of the number needed return {static_cast(std::forward(q).numerical_value_is_an_implementation_detail_), - To::reference}; // 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 + relative(To::reference)}; // 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 using traits = magnitude_conversion_traits>; @@ -108,13 +108,13 @@ template // this results in great assembly auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::ratio); - return {res, To::reference}; + return {res, relative(To::reference)}; } else { // this is slower but allows conversions like 2000 m -> 2 km without loosing data auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::num_mult / traits::den_mult * traits::irr_mult); - return {res, To::reference}; + return {res, relative(To::reference)}; } } } @@ -175,5 +175,4 @@ template } } - } // namespace mp_units::detail diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 587ab2a2..44dd8742 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -88,6 +88,12 @@ template using common_quantity_for = quantity>; +template +concept SameOriginalReferenceAs = RelativeReference && Reference && (get_original_reference(T{}) == R{}); + +template +concept SameValueAs = detail::SameOriginalReferenceAs && std::same_as; + } // namespace detail MP_UNITS_EXPORT_BEGIN @@ -117,25 +123,25 @@ public: [[nodiscard]] static constexpr quantity zero() noexcept requires requires { quantity_values::zero(); } { - return {quantity_values::zero(), R}; + return {quantity_values::zero(), relative(R)}; } [[nodiscard]] static constexpr quantity one() noexcept requires requires { quantity_values::one(); } { - return {quantity_values::one(), R}; + return {quantity_values::one(), relative(R)}; } [[nodiscard]] static constexpr quantity min() noexcept requires requires { quantity_values::min(); } { - return {quantity_values::min(), R}; + return {quantity_values::min(), relative(R)}; } [[nodiscard]] static constexpr quantity max() noexcept requires requires { quantity_values::max(); } { - return {quantity_values::max(), R}; + return {quantity_values::max(), relative(R)}; } // construction, assignment, destruction @@ -144,15 +150,17 @@ public: quantity(quantity&&) = default; ~quantity() = default; - template - requires std::same_as, Rep> - constexpr quantity(Value&& v, decltype(R)) : numerical_value_is_an_implementation_detail_(std::forward(v)) + template + requires detail::SameValueAs, Rep> + constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward(v)) { } - template - requires detail::QuantityConvertibleTo>, quantity> - constexpr quantity(Value&& v, R2) : quantity(quantity>{std::forward(v), R2{}}) + template + requires(!detail::SameValueAs, Rep>) && + detail::QuantityConvertibleTo>, quantity> + constexpr quantity(Value&& v, R2) : + quantity(quantity>{std::forward(v), R2{}}) { } @@ -172,7 +180,7 @@ public: // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) !std::convertible_to::rep, Rep>) quantity(const Q& q) : quantity( - ::mp_units::quantity{quantity_like_traits::to_numerical_value(q).value, quantity_like_traits::reference}) + ::mp_units::quantity{quantity_like_traits::to_numerical_value(q).value, relative(quantity_like_traits::reference)}) { } @@ -266,7 +274,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, reference}; + return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, relative(reference)}; } [[nodiscard]] constexpr QuantityOf auto operator-() const @@ -276,7 +284,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference}; + return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, relative(reference)}; } template @@ -298,7 +306,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, relative(reference)}; } template @@ -320,7 +328,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, reference}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, relative(reference)}; } // compound assignment operators @@ -419,9 +427,9 @@ public: }; // CTAD -template - requires RepresentationOf -quantity(Value v, R) -> quantity; +template + requires RepresentationOf +quantity(Value v, R) -> quantity; template explicit( @@ -437,7 +445,7 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit), - ret::reference}; + relative(ret::reference)}; } template @@ -448,7 +456,7 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit), - ret::reference}; + relative(ret::reference)}; } template @@ -461,14 +469,15 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit), - ret::reference}; + relative(ret::reference)}; } template requires detail::InvocableQuantities, quantity, quantity> [[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) { - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), R1 * R2}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), + relative(R1 * R2)}; } template @@ -476,7 +485,7 @@ template detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] constexpr QuantityOf auto operator*(const quantity& q, const Value& v) { - return quantity{q.numerical_value_ref_in(get_unit(R)) * v, R}; + return quantity{q.numerical_value_ref_in(get_unit(R)) * v, relative(R)}; } template @@ -484,7 +493,7 @@ template detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] constexpr QuantityOf auto operator*(const Value& v, const quantity& q) { - return quantity{v * q.numerical_value_ref_in(get_unit(R)), R}; + return quantity{v * q.numerical_value_ref_in(get_unit(R)), relative(R)}; } template @@ -492,7 +501,8 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) { MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), + relative(R1 / R2)}; } template @@ -501,7 +511,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const quantity& q, const Value& v) { MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); - return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R}; + return quantity{q.numerical_value_ref_in(get_unit(R)) / v, relative(R)}; } template @@ -510,7 +520,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const Value& v, const quantity& q) { - return quantity{v / q.numerical_value_ref_in(get_unit(R)), ::mp_units::one / R}; + return quantity{v / q.numerical_value_ref_in(get_unit(R)), relative(::mp_units::one / R)}; } template diff --git a/src/core/include/mp-units/framework/quantity_cast.h b/src/core/include/mp-units/framework/quantity_cast.h index 53b14815..a915325a 100644 --- a/src/core/include/mp-units/framework/quantity_cast.h +++ b/src/core/include/mp-units/framework/quantity_cast.h @@ -57,7 +57,7 @@ template [[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - make_reference(ToQS, std::remove_reference_t::unit)}; + relative(make_reference(ToQS, std::remove_reference_t::unit))}; } /** diff --git a/src/core/include/mp-units/framework/quantity_spec.h b/src/core/include/mp-units/framework/quantity_spec.h index 855dd25c..3979f3e5 100644 --- a/src/core/include/mp-units/framework/quantity_spec.h +++ b/src/core/include/mp-units/framework/quantity_spec.h @@ -129,7 +129,7 @@ struct quantity_spec_interface { (explicitly_convertible(std::remove_reference_t::quantity_spec, self)) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_reference(self, std::remove_cvref_t::unit)}; + relative(detail::make_reference(self, std::remove_cvref_t::unit))}; } #else template U> @@ -144,7 +144,7 @@ struct quantity_spec_interface { [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_reference(Self{}, std::remove_cvref_t::unit)}; + relative(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; } #endif }; @@ -341,7 +341,7 @@ struct quantity_spec : detail::propagate_equation, detail [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_reference(Self{}, std::remove_cvref_t::unit)}; + relative(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; } #endif }; diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index 746abb44..9cb269ac 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -40,8 +40,18 @@ namespace detail { template using reference_t = reference; +template + requires RelativeReference || AbsoluteReference +[[nodiscard]] consteval Reference auto get_original_reference(R r) +{ + if constexpr (requires { typename R::_type_; }) + return typename R::_type_{}; + else + return r; } +} // namespace detail + MP_UNITS_EXPORT_BEGIN [[nodiscard]] consteval QuantitySpec auto get_quantity_spec(AssociatedUnit auto u) @@ -173,18 +183,19 @@ struct reference { }; -template - requires RepresentationOf, get_quantity_spec(R{}).character> -[[nodiscard]] constexpr quantity> operator*(Rep&& lhs, R) +template + requires RepresentationOf, get_quantity_spec(detail::get_original_reference(R{})).character> +[[nodiscard]] constexpr quantity> operator*(Rep&& lhs, R) { return quantity{std::forward(lhs), R{}}; } -template - requires RepresentationOf, get_quantity_spec(R{}).character> -[[nodiscard]] constexpr quantity> operator/(Rep&& lhs, R) +template + requires RepresentationOf, get_quantity_spec(detail::get_original_reference(R{})).character> +[[nodiscard]] constexpr quantity> operator/( + Rep&& lhs, R) { - return quantity{std::forward(lhs), inverse(R{})}; + return quantity{std::forward(lhs), relative(inverse(detail::get_original_reference(R{})))}; } template @@ -202,7 +213,7 @@ template [[nodiscard]] constexpr Quantity auto operator*(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - std::remove_cvref_t::reference * R{}}; + relative(std::remove_cvref_t::reference * R{})}; } template @@ -210,7 +221,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - std::remove_cvref_t::reference / R{}}; + relative(std::remove_cvref_t::reference / R{})}; } template diff --git a/src/core/include/mp-units/framework/reference_concepts.h b/src/core/include/mp-units/framework/reference_concepts.h index a2c78365..857dbd0b 100644 --- a/src/core/include/mp-units/framework/reference_concepts.h +++ b/src/core/include/mp-units/framework/reference_concepts.h @@ -80,4 +80,33 @@ concept ReferenceOf = Reference && QuantitySpecOf +struct relative_ final { + using _type_ = R; +}; + +template +struct absolute_ final { + using _type_ = R; +}; + +template +MP_UNITS_EXPORT [[nodiscard]] consteval relative_ relative(R) +{ + return {}; +} + +template +MP_UNITS_EXPORT [[nodiscard]] consteval absolute_ absolute(R) +{ + return {}; +} + +template +MP_UNITS_EXPORT concept RelativeReference = + (Reference && !requires { get_unit(T{}).point_origin; }) || is_specialization_of; + +template +MP_UNITS_EXPORT concept AbsoluteReference = is_specialization_of; + } // namespace mp_units diff --git a/src/core/include/mp-units/math.h b/src/core/include/mp-units/math.h index 50dd222a..b2859dfd 100644 --- a/src/core/include/mp-units/math.h +++ b/src/core/include/mp-units/math.h @@ -115,7 +115,7 @@ template auto R, typename Rep> { using std::exp; return value_cast( - quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), detail::clone_reference_with(R)}); + quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), relative(detail::clone_reference_with(R))}); } /** @@ -236,7 +236,7 @@ template using std::fma; return quantity{ fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)), - common_reference(R * S, T)}; + relative(common_reference(R * S, T))}; } /** @@ -260,7 +260,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::fmod; - return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; + return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), relative(ref)}; } /** @@ -294,7 +294,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::remainder; - return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; + return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), relative(ref)}; } @@ -339,7 +339,7 @@ template return {static_cast(floor(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with(R)}; } else { return handle_signed_results( - quantity{static_cast(floor(q.force_numerical_value_in(To))), detail::clone_reference_with(R)}); + quantity{static_cast(floor(q.force_numerical_value_in(To))), relative(detail::clone_reference_with(R))}); } } else { if constexpr (To == get_unit(R)) { @@ -376,7 +376,7 @@ template return {static_cast(ceil(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with(R)}; } else { return handle_signed_results( - quantity{static_cast(ceil(q.force_numerical_value_in(To))), detail::clone_reference_with(R)}); + quantity{static_cast(ceil(q.force_numerical_value_in(To))), relative(detail::clone_reference_with(R))}); } } else { if constexpr (To == get_unit(R)) { @@ -456,7 +456,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::hypot; - return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), relative(ref)}; } /** @@ -474,7 +474,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::hypot; - return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), ref}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), relative(ref)}; } } // namespace mp_units diff --git a/src/systems/include/mp-units/systems/si/units.h b/src/systems/include/mp-units/systems/si/units.h index bbcf0166..f358083e 100644 --- a/src/systems/include/mp-units/systems/si/units.h +++ b/src/systems/include/mp-units/systems/si/units.h @@ -77,7 +77,7 @@ inline constexpr struct weber final : named_unit<"Wb", volt * second> {} weber; inline constexpr struct tesla final : named_unit<"T", weber / square(metre)> {} tesla; inline constexpr struct henry final : named_unit<"H", weber / ampere> {} henry; -inline constexpr struct ice_point final : relative_point_origin}> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin)}> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; inline constexpr struct degree_Celsius final : named_unit {} degree_Celsius; diff --git a/src/systems/include/mp-units/systems/usc.h b/src/systems/include/mp-units/systems/usc.h index 3cde7c36..3b1e6bea 100644 --- a/src/systems/include/mp-units/systems/usc.h +++ b/src/systems/include/mp-units/systems/usc.h @@ -118,7 +118,7 @@ inline constexpr struct troy_pound final : named_unit<"lb t", mag<12> * troy_onc inline constexpr struct inch_of_mercury final : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury; // https://en.wikipedia.org/wiki/United_States_customary_units#Temperature -inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit; +inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit; inline constexpr struct degree_Fahrenheit final : named_unit * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit; // clang-format on diff --git a/test/static/quantity_point_test.cpp b/test/static/quantity_point_test.cpp index a335ccac..758f81b9 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -802,8 +802,8 @@ static_assert( static_assert(quantity_point{42 * m}.quantity_from_zero() == 42 * m); static_assert(quantity_point{isq::height(42 * m)}.quantity_from_zero() == 42 * m); -static_assert(quantity_point{20 * deg_C}.quantity_from_zero() == 20 * deg_C); -static_assert(quantity_point{20. * deg_C}.in(deg_F).quantity_from_zero() == 68 * deg_F); +static_assert(quantity_point{20 * relative(deg_C)}.quantity_from_zero() == 20 * relative(deg_C)); +static_assert(quantity_point{20. * relative(deg_C)}.in(deg_F).quantity_from_zero() == 68 * relative(deg_F)); static_assert((mean_sea_level + 42 * m).quantity_from_zero() == 42 * m); static_assert((ground_level + 42 * m).quantity_from_zero() == 84 * m); @@ -889,13 +889,13 @@ static_assert(std::is_same_v); -static_assert( - std::is_same_v, struct si::ice_point>); -static_assert(std::is_same_v, +static_assert(std::is_same_v); +static_assert(std::is_same_v, + struct si::ice_point>); +static_assert(std::is_same_v, struct si::absolute_zero>); -static_assert(quantity_point{20 * deg_C}.unit == si::degree_Celsius); -static_assert(quantity_point{20 * deg_C}.quantity_spec == kind_of); +static_assert(quantity_point{20 * relative(deg_C)}.unit == si::degree_Celsius); +static_assert(quantity_point{20 * relative(deg_C)}.quantity_spec == kind_of); #if MP_UNITS_HOSTED using namespace std::chrono_literals; diff --git a/test/static/usc_test.cpp b/test/static/usc_test.cpp index 099a710f..480c5c57 100644 --- a/test/static/usc_test.cpp +++ b/test/static/usc_test.cpp @@ -126,6 +126,7 @@ static_assert(isq::mass(1 * lb_t) == isq::mass(12 * oz_t)); static_assert(isq::pressure(1'000 * inHg) == isq::pressure(3'386'389 * si::pascal)); // Temperature -static_assert(isq::thermodynamic_temperature(9 * deg_F) == isq::thermodynamic_temperature(5 * si::degree_Celsius)); +static_assert(isq::thermodynamic_temperature(9 * relative(deg_F)) == + isq::thermodynamic_temperature(5 * relative(si::degree_Celsius))); } // namespace From dfac87c631763d073260b0ea2bd8f2b571beaa84 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Wed, 19 Jun 2024 21:11:16 +0200 Subject: [PATCH 02/11] feat: multiply syntax support to create `quantity_point` --- .../include/mp-units/framework/reference.h | 20 +++++++++++++++++++ test/static/quantity_point_test.cpp | 14 +++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index 9cb269ac..f0721d84 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -198,6 +198,26 @@ template return quantity{std::forward(lhs), relative(inverse(detail::get_original_reference(R{})))}; } +template + requires RepresentationOf, get_quantity_spec(detail::get_original_reference(R{})).character> +[[nodiscard]] constexpr quantity_point> +operator*(Rep&& lhs, R) +{ + return quantity_point{std::forward(lhs) * relative(detail::get_original_reference(R{}))}; +} + +template + requires RepresentationOf, get_quantity_spec(detail::get_original_reference(R{})).character> +[[nodiscard]] constexpr quantity_point> +operator/(Rep&& lhs, R) +{ + return quantity_point{std::forward(lhs) * relative(inverse(detail::get_original_reference(R{})))}; +} + template requires RepresentationOf, get_quantity_spec(R{}).character> // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) diff --git a/test/static/quantity_point_test.cpp b/test/static/quantity_point_test.cpp index 758f81b9..671f3527 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -801,9 +801,12 @@ static_assert( ////////////////////////////////// static_assert(quantity_point{42 * m}.quantity_from_zero() == 42 * m); +static_assert((42 * absolute(m)).quantity_from_zero() == 42 * m); static_assert(quantity_point{isq::height(42 * m)}.quantity_from_zero() == 42 * m); static_assert(quantity_point{20 * relative(deg_C)}.quantity_from_zero() == 20 * relative(deg_C)); +static_assert((20 * absolute(deg_C)).quantity_from_zero() == 20 * relative(deg_C)); static_assert(quantity_point{20. * relative(deg_C)}.in(deg_F).quantity_from_zero() == 68 * relative(deg_F)); +static_assert((20. * absolute(deg_C)).in(deg_F).quantity_from_zero() == 68 * relative(deg_F)); static_assert((mean_sea_level + 42 * m).quantity_from_zero() == 42 * m); static_assert((ground_level + 42 * m).quantity_from_zero() == 84 * m); @@ -889,13 +892,12 @@ static_assert(std::is_same_v); -static_assert(std::is_same_v, - struct si::ice_point>); -static_assert(std::is_same_v, +static_assert(std::is_same_v); +static_assert(std::is_same_v, struct si::ice_point>); +static_assert(std::is_same_v, struct si::absolute_zero>); -static_assert(quantity_point{20 * relative(deg_C)}.unit == si::degree_Celsius); -static_assert(quantity_point{20 * relative(deg_C)}.quantity_spec == kind_of); +static_assert((20 * absolute(deg_C)).unit == si::degree_Celsius); +static_assert((20 * absolute(deg_C)).quantity_spec == kind_of); #if MP_UNITS_HOSTED using namespace std::chrono_literals; From b38b23ece2af413b699f53504da6db4ed55787fc Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 07:31:22 +0200 Subject: [PATCH 03/11] refactor: `relative()` renamed to `delta()` --- .../kalman_filter/kalman_filter-example_6.cpp | 15 +++--- .../kalman_filter/kalman_filter-example_7.cpp | 15 +++--- .../kalman_filter/kalman_filter-example_8.cpp | 15 +++--- example/spectroscopy_units.cpp | 2 +- src/core/include/mp-units/bits/sudo_cast.h | 12 ++--- .../include/mp-units/framework/quantity.h | 48 +++++++++---------- .../mp-units/framework/quantity_cast.h | 2 +- .../mp-units/framework/quantity_spec.h | 6 +-- .../include/mp-units/framework/reference.h | 16 +++---- .../mp-units/framework/reference_concepts.h | 4 +- src/core/include/mp-units/math.h | 19 ++++---- .../include/mp-units/systems/si/units.h | 2 +- src/systems/include/mp-units/systems/usc.h | 2 +- test/static/quantity_point_test.cpp | 8 ++-- test/static/usc_test.cpp | 4 +- 15 files changed, 83 insertions(+), 87 deletions(-) diff --git a/example/kalman_filter/kalman_filter-example_6.cpp b/example/kalman_filter/kalman_filter-example_6.cpp index d70b974a..20e96137 100644 --- a/example/kalman_filter/kalman_filter-example_6.cpp +++ b/example/kalman_filter/kalman_filter-example_6.cpp @@ -62,14 +62,13 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.0001 * relative(pow<2>(deg_C)); - const estimate initial{state{qp{60. * relative(deg_C)}}, 100. * relative(deg_C)}; - const std::array measurements = {qp{49.986 * relative(deg_C)}, qp{49.963 * relative(deg_C)}, - qp{50.097 * relative(deg_C)}, qp{50.001 * relative(deg_C)}, - qp{50.018 * relative(deg_C)}, qp{50.05 * relative(deg_C)}, - qp{49.938 * relative(deg_C)}, qp{49.858 * relative(deg_C)}, - qp{49.965 * relative(deg_C)}, qp{50.114 * relative(deg_C)}}; - const quantity measurement_error = 0.1 * relative(deg_C); + const quantity process_noise_variance = 0.0001 * delta(pow<2>(deg_C)); + const estimate initial{state{qp{60. * delta(deg_C)}}, 100. * delta(deg_C)}; + const std::array measurements = {qp{49.986 * delta(deg_C)}, qp{49.963 * delta(deg_C)}, qp{50.097 * delta(deg_C)}, + qp{50.001 * delta(deg_C)}, qp{50.018 * delta(deg_C)}, qp{50.05 * delta(deg_C)}, + qp{49.938 * delta(deg_C)}, qp{49.858 * delta(deg_C)}, qp{49.965 * delta(deg_C)}, + qp{50.114 * delta(deg_C)}}; + const quantity measurement_error = 0.1 * delta(deg_C); const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/kalman_filter/kalman_filter-example_7.cpp b/example/kalman_filter/kalman_filter-example_7.cpp index 104d08f6..0fe7889f 100644 --- a/example/kalman_filter/kalman_filter-example_7.cpp +++ b/example/kalman_filter/kalman_filter-example_7.cpp @@ -62,14 +62,13 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.0001 * relative(pow<2>(deg_C)); - const estimate initial{state{qp{10. * relative(deg_C)}}, 100. * relative(deg_C)}; - const std::array measurements = {qp{50.486 * relative(deg_C)}, qp{50.963 * relative(deg_C)}, - qp{51.597 * relative(deg_C)}, qp{52.001 * relative(deg_C)}, - qp{52.518 * relative(deg_C)}, qp{53.05 * relative(deg_C)}, - qp{53.438 * relative(deg_C)}, qp{53.858 * relative(deg_C)}, - qp{54.465 * relative(deg_C)}, qp{55.114 * relative(deg_C)}}; - const quantity measurement_error = 0.1 * relative(deg_C); + const quantity process_noise_variance = 0.0001 * delta(pow<2>(deg_C)); + const estimate initial{state{qp{10. * delta(deg_C)}}, 100. * delta(deg_C)}; + const std::array measurements = {qp{50.486 * delta(deg_C)}, qp{50.963 * delta(deg_C)}, qp{51.597 * delta(deg_C)}, + qp{52.001 * delta(deg_C)}, qp{52.518 * delta(deg_C)}, qp{53.05 * delta(deg_C)}, + qp{53.438 * delta(deg_C)}, qp{53.858 * delta(deg_C)}, qp{54.465 * delta(deg_C)}, + qp{55.114 * delta(deg_C)}}; + const quantity measurement_error = 0.1 * delta(deg_C); const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/kalman_filter/kalman_filter-example_8.cpp b/example/kalman_filter/kalman_filter-example_8.cpp index d818140e..3f27a467 100644 --- a/example/kalman_filter/kalman_filter-example_8.cpp +++ b/example/kalman_filter/kalman_filter-example_8.cpp @@ -62,14 +62,13 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.15 * relative(pow<2>(deg_C)); - const estimate initial{state{qp{10. * relative(deg_C)}}, 100. * relative(deg_C)}; - const std::array measurements = {qp{50.486 * relative(deg_C)}, qp{50.963 * relative(deg_C)}, - qp{51.597 * relative(deg_C)}, qp{52.001 * relative(deg_C)}, - qp{52.518 * relative(deg_C)}, qp{53.05 * relative(deg_C)}, - qp{53.438 * relative(deg_C)}, qp{53.858 * relative(deg_C)}, - qp{54.465 * relative(deg_C)}, qp{55.114 * relative(deg_C)}}; - const quantity measurement_error = 0.1 * relative(deg_C); + const quantity process_noise_variance = 0.15 * delta(pow<2>(deg_C)); + const estimate initial{state{qp{10. * delta(deg_C)}}, 100. * delta(deg_C)}; + const std::array measurements = {qp{50.486 * delta(deg_C)}, qp{50.963 * delta(deg_C)}, qp{51.597 * delta(deg_C)}, + qp{52.001 * delta(deg_C)}, qp{52.518 * delta(deg_C)}, qp{53.05 * delta(deg_C)}, + qp{53.438 * delta(deg_C)}, qp{53.858 * delta(deg_C)}, qp{54.465 * delta(deg_C)}, + qp{55.114 * delta(deg_C)}}; + const quantity measurement_error = 0.1 * delta(deg_C); const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/spectroscopy_units.cpp b/example/spectroscopy_units.cpp index 85fe8344..d134e698 100644 --- a/example/spectroscopy_units.cpp +++ b/example/spectroscopy_units.cpp @@ -84,7 +84,7 @@ int main() const auto t3 = std::make_tuple(isq::energy(q3 * h), isq::wavenumber(q3 / c), q3, isq::thermodynamic_temperature(q3 * h / kb), isq::wavelength(c / q3)); - const auto q4 = isq::thermodynamic_temperature(1. * relative(K)); + const auto q4 = isq::thermodynamic_temperature(1. * delta(K)); const auto t4 = std::make_tuple(isq::energy(q4 * kb), isq::wavenumber(q4 * kb / (h * c)), isq::frequency(q4 * kb / h), q4, isq::wavelength(h * c / (q4 * kb))); diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index 768a5dc5..aefb2b13 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -97,10 +97,10 @@ template if constexpr (q_unit == To::unit) { // no scaling of the number needed return {static_cast(std::forward(q).numerical_value_is_an_implementation_detail_), - relative(To::reference)}; // 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 + delta(To::reference)}; // 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 using traits = magnitude_conversion_traits>; @@ -108,13 +108,13 @@ template // this results in great assembly auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::ratio); - return {res, relative(To::reference)}; + return {res, delta(To::reference)}; } else { // this is slower but allows conversions like 2000 m -> 2 km without loosing data auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::num_mult / traits::den_mult * traits::irr_mult); - return {res, relative(To::reference)}; + return {res, delta(To::reference)}; } } } diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 44dd8742..28cdbafe 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -89,7 +89,7 @@ using common_quantity_for = quantity>; template -concept SameOriginalReferenceAs = RelativeReference && Reference && (get_original_reference(T{}) == R{}); +concept SameOriginalReferenceAs = DeltaReference && Reference && (get_original_reference(T{}) == R{}); template concept SameValueAs = detail::SameOriginalReferenceAs && std::same_as; @@ -123,25 +123,25 @@ public: [[nodiscard]] static constexpr quantity zero() noexcept requires requires { quantity_values::zero(); } { - return {quantity_values::zero(), relative(R)}; + return {quantity_values::zero(), delta(R)}; } [[nodiscard]] static constexpr quantity one() noexcept requires requires { quantity_values::one(); } { - return {quantity_values::one(), relative(R)}; + return {quantity_values::one(), delta(R)}; } [[nodiscard]] static constexpr quantity min() noexcept requires requires { quantity_values::min(); } { - return {quantity_values::min(), relative(R)}; + return {quantity_values::min(), delta(R)}; } [[nodiscard]] static constexpr quantity max() noexcept requires requires { quantity_values::max(); } { - return {quantity_values::max(), relative(R)}; + return {quantity_values::max(), delta(R)}; } // construction, assignment, destruction @@ -150,13 +150,13 @@ public: quantity(quantity&&) = default; ~quantity() = default; - template + template requires detail::SameValueAs, Rep> constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward(v)) { } - template + template requires(!detail::SameValueAs, Rep>) && detail::QuantityConvertibleTo>, quantity> constexpr quantity(Value&& v, R2) : @@ -179,8 +179,8 @@ public: convert_explicitly> || // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) !std::convertible_to::rep, Rep>) quantity(const Q& q) : - quantity( - ::mp_units::quantity{quantity_like_traits::to_numerical_value(q).value, relative(quantity_like_traits::reference)}) + quantity(::mp_units::quantity{quantity_like_traits::to_numerical_value(q).value, + delta(quantity_like_traits::reference)}) { } @@ -274,7 +274,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, relative(reference)}; + return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, delta(reference)}; } [[nodiscard]] constexpr QuantityOf auto operator-() const @@ -284,7 +284,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, relative(reference)}; + return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, delta(reference)}; } template @@ -306,7 +306,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, relative(reference)}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, delta(reference)}; } template @@ -328,7 +328,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, relative(reference)}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, delta(reference)}; } // compound assignment operators @@ -427,7 +427,7 @@ public: }; // CTAD -template +template requires RepresentationOf quantity(Value v, R) -> quantity; @@ -445,7 +445,7 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit), - relative(ret::reference)}; + delta(ret::reference)}; } template @@ -456,7 +456,7 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit), - relative(ret::reference)}; + delta(ret::reference)}; } template @@ -469,15 +469,14 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit), - relative(ret::reference)}; + delta(ret::reference)}; } template requires detail::InvocableQuantities, quantity, quantity> [[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) { - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), - relative(R1 * R2)}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), delta(R1 * R2)}; } template @@ -485,7 +484,7 @@ template detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] constexpr QuantityOf auto operator*(const quantity& q, const Value& v) { - return quantity{q.numerical_value_ref_in(get_unit(R)) * v, relative(R)}; + return quantity{q.numerical_value_ref_in(get_unit(R)) * v, delta(R)}; } template @@ -493,7 +492,7 @@ template detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] constexpr QuantityOf auto operator*(const Value& v, const quantity& q) { - return quantity{v * q.numerical_value_ref_in(get_unit(R)), relative(R)}; + return quantity{v * q.numerical_value_ref_in(get_unit(R)), delta(R)}; } template @@ -501,8 +500,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) { MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), - relative(R1 / R2)}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), delta(R1 / R2)}; } template @@ -511,7 +509,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const quantity& q, const Value& v) { MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); - return quantity{q.numerical_value_ref_in(get_unit(R)) / v, relative(R)}; + return quantity{q.numerical_value_ref_in(get_unit(R)) / v, delta(R)}; } template @@ -520,7 +518,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const Value& v, const quantity& q) { - return quantity{v / q.numerical_value_ref_in(get_unit(R)), relative(::mp_units::one / R)}; + return quantity{v / q.numerical_value_ref_in(get_unit(R)), delta(::mp_units::one / R)}; } template diff --git a/src/core/include/mp-units/framework/quantity_cast.h b/src/core/include/mp-units/framework/quantity_cast.h index a915325a..081955d9 100644 --- a/src/core/include/mp-units/framework/quantity_cast.h +++ b/src/core/include/mp-units/framework/quantity_cast.h @@ -57,7 +57,7 @@ template [[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - relative(make_reference(ToQS, std::remove_reference_t::unit))}; + delta(make_reference(ToQS, std::remove_reference_t::unit))}; } /** diff --git a/src/core/include/mp-units/framework/quantity_spec.h b/src/core/include/mp-units/framework/quantity_spec.h index 3979f3e5..565ee049 100644 --- a/src/core/include/mp-units/framework/quantity_spec.h +++ b/src/core/include/mp-units/framework/quantity_spec.h @@ -129,7 +129,7 @@ struct quantity_spec_interface { (explicitly_convertible(std::remove_reference_t::quantity_spec, self)) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - relative(detail::make_reference(self, std::remove_cvref_t::unit))}; + delta(detail::make_reference(self, std::remove_cvref_t::unit))}; } #else template U> @@ -144,7 +144,7 @@ struct quantity_spec_interface { [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - relative(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; + delta(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; } #endif }; @@ -341,7 +341,7 @@ struct quantity_spec : detail::propagate_equation, detail [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - relative(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; + delta(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; } #endif }; diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index f0721d84..a9223f2e 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -41,7 +41,7 @@ template using reference_t = reference; template - requires RelativeReference || AbsoluteReference + requires DeltaReference || AbsoluteReference [[nodiscard]] consteval Reference auto get_original_reference(R r) { if constexpr (requires { typename R::_type_; }) @@ -183,19 +183,19 @@ struct reference { }; -template +template requires RepresentationOf, get_quantity_spec(detail::get_original_reference(R{})).character> [[nodiscard]] constexpr quantity> operator*(Rep&& lhs, R) { return quantity{std::forward(lhs), R{}}; } -template +template requires RepresentationOf, get_quantity_spec(detail::get_original_reference(R{})).character> [[nodiscard]] constexpr quantity> operator/( Rep&& lhs, R) { - return quantity{std::forward(lhs), relative(inverse(detail::get_original_reference(R{})))}; + return quantity{std::forward(lhs), delta(inverse(detail::get_original_reference(R{})))}; } template @@ -205,7 +205,7 @@ template std::remove_cvref_t> operator*(Rep&& lhs, R) { - return quantity_point{std::forward(lhs) * relative(detail::get_original_reference(R{}))}; + return quantity_point{std::forward(lhs) * delta(detail::get_original_reference(R{}))}; } template @@ -215,7 +215,7 @@ template std::remove_cvref_t> operator/(Rep&& lhs, R) { - return quantity_point{std::forward(lhs) * relative(inverse(detail::get_original_reference(R{})))}; + return quantity_point{std::forward(lhs) * delta(inverse(detail::get_original_reference(R{})))}; } template @@ -233,7 +233,7 @@ template [[nodiscard]] constexpr Quantity auto operator*(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - relative(std::remove_cvref_t::reference * R{})}; + delta(std::remove_cvref_t::reference * R{})}; } template @@ -241,7 +241,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - relative(std::remove_cvref_t::reference / R{})}; + delta(std::remove_cvref_t::reference / R{})}; } template diff --git a/src/core/include/mp-units/framework/reference_concepts.h b/src/core/include/mp-units/framework/reference_concepts.h index 857dbd0b..91bd1a73 100644 --- a/src/core/include/mp-units/framework/reference_concepts.h +++ b/src/core/include/mp-units/framework/reference_concepts.h @@ -91,7 +91,7 @@ struct absolute_ final { }; template -MP_UNITS_EXPORT [[nodiscard]] consteval relative_ relative(R) +MP_UNITS_EXPORT [[nodiscard]] consteval relative_ delta(R) { return {}; } @@ -103,7 +103,7 @@ MP_UNITS_EXPORT [[nodiscard]] consteval absolute_ absolute(R) } template -MP_UNITS_EXPORT concept RelativeReference = +MP_UNITS_EXPORT concept DeltaReference = (Reference && !requires { get_unit(T{}).point_origin; }) || is_specialization_of; template diff --git a/src/core/include/mp-units/math.h b/src/core/include/mp-units/math.h index b2859dfd..c357a7d9 100644 --- a/src/core/include/mp-units/math.h +++ b/src/core/include/mp-units/math.h @@ -115,7 +115,7 @@ template auto R, typename Rep> { using std::exp; return value_cast( - quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), relative(detail::clone_reference_with(R))}); + quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), delta(detail::clone_reference_with(R))}); } /** @@ -236,7 +236,7 @@ template using std::fma; return quantity{ fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)), - relative(common_reference(R * S, T))}; + delta(common_reference(R * S, T))}; } /** @@ -260,7 +260,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::fmod; - return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), relative(ref)}; + return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta(ref)}; } /** @@ -294,7 +294,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::remainder; - return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), relative(ref)}; + return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta(ref)}; } @@ -339,7 +339,7 @@ template return {static_cast(floor(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with(R)}; } else { return handle_signed_results( - quantity{static_cast(floor(q.force_numerical_value_in(To))), relative(detail::clone_reference_with(R))}); + quantity{static_cast(floor(q.force_numerical_value_in(To))), delta(detail::clone_reference_with(R))}); } } else { if constexpr (To == get_unit(R)) { @@ -376,7 +376,7 @@ template return {static_cast(ceil(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with(R)}; } else { return handle_signed_results( - quantity{static_cast(ceil(q.force_numerical_value_in(To))), relative(detail::clone_reference_with(R))}); + quantity{static_cast(ceil(q.force_numerical_value_in(To))), delta(detail::clone_reference_with(R))}); } } else { if constexpr (To == get_unit(R)) { @@ -456,7 +456,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::hypot; - return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), relative(ref)}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta(ref)}; } /** @@ -474,7 +474,8 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::hypot; - return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), relative(ref)}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), + delta(ref)}; } } // namespace mp_units diff --git a/src/systems/include/mp-units/systems/si/units.h b/src/systems/include/mp-units/systems/si/units.h index f358083e..21813bb0 100644 --- a/src/systems/include/mp-units/systems/si/units.h +++ b/src/systems/include/mp-units/systems/si/units.h @@ -77,7 +77,7 @@ inline constexpr struct weber final : named_unit<"Wb", volt * second> {} weber; inline constexpr struct tesla final : named_unit<"T", weber / square(metre)> {} tesla; inline constexpr struct henry final : named_unit<"H", weber / ampere> {} henry; -inline constexpr struct ice_point final : relative_point_origin)}> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin)}> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; inline constexpr struct degree_Celsius final : named_unit {} degree_Celsius; diff --git a/src/systems/include/mp-units/systems/usc.h b/src/systems/include/mp-units/systems/usc.h index 3b1e6bea..691f18d4 100644 --- a/src/systems/include/mp-units/systems/usc.h +++ b/src/systems/include/mp-units/systems/usc.h @@ -118,7 +118,7 @@ inline constexpr struct troy_pound final : named_unit<"lb t", mag<12> * troy_onc inline constexpr struct inch_of_mercury final : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury; // https://en.wikipedia.org/wiki/United_States_customary_units#Temperature -inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit; +inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit; inline constexpr struct degree_Fahrenheit final : named_unit * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit; // clang-format on diff --git a/test/static/quantity_point_test.cpp b/test/static/quantity_point_test.cpp index 671f3527..ccf1c479 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -803,10 +803,10 @@ static_assert( static_assert(quantity_point{42 * m}.quantity_from_zero() == 42 * m); static_assert((42 * absolute(m)).quantity_from_zero() == 42 * m); static_assert(quantity_point{isq::height(42 * m)}.quantity_from_zero() == 42 * m); -static_assert(quantity_point{20 * relative(deg_C)}.quantity_from_zero() == 20 * relative(deg_C)); -static_assert((20 * absolute(deg_C)).quantity_from_zero() == 20 * relative(deg_C)); -static_assert(quantity_point{20. * relative(deg_C)}.in(deg_F).quantity_from_zero() == 68 * relative(deg_F)); -static_assert((20. * absolute(deg_C)).in(deg_F).quantity_from_zero() == 68 * relative(deg_F)); +static_assert(quantity_point{20 * delta(deg_C)}.quantity_from_zero() == 20 * delta(deg_C)); +static_assert((20 * absolute(deg_C)).quantity_from_zero() == 20 * delta(deg_C)); +static_assert(quantity_point{20. * delta(deg_C)}.in(deg_F).quantity_from_zero() == 68 * delta(deg_F)); +static_assert((20. * absolute(deg_C)).in(deg_F).quantity_from_zero() == 68 * delta(deg_F)); static_assert((mean_sea_level + 42 * m).quantity_from_zero() == 42 * m); static_assert((ground_level + 42 * m).quantity_from_zero() == 84 * m); diff --git a/test/static/usc_test.cpp b/test/static/usc_test.cpp index 480c5c57..f6b9228b 100644 --- a/test/static/usc_test.cpp +++ b/test/static/usc_test.cpp @@ -126,7 +126,7 @@ static_assert(isq::mass(1 * lb_t) == isq::mass(12 * oz_t)); static_assert(isq::pressure(1'000 * inHg) == isq::pressure(3'386'389 * si::pascal)); // Temperature -static_assert(isq::thermodynamic_temperature(9 * relative(deg_F)) == - isq::thermodynamic_temperature(5 * relative(si::degree_Celsius))); +static_assert(isq::thermodynamic_temperature(9 * delta(deg_F)) == + isq::thermodynamic_temperature(5 * delta(si::degree_Celsius))); } // namespace From 5761deb1ba178f9c88589a4184c5d4d00168603b Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 08:52:33 +0200 Subject: [PATCH 04/11] refactor: `ice_point` and `zeroth_degree_Fahrenheit` now use `absolute` reference specifier --- src/systems/include/mp-units/systems/si/units.h | 2 +- src/systems/include/mp-units/systems/usc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/systems/include/mp-units/systems/si/units.h b/src/systems/include/mp-units/systems/si/units.h index 21813bb0..2730ab32 100644 --- a/src/systems/include/mp-units/systems/si/units.h +++ b/src/systems/include/mp-units/systems/si/units.h @@ -77,7 +77,7 @@ inline constexpr struct weber final : named_unit<"Wb", volt * second> {} weber; inline constexpr struct tesla final : named_unit<"T", weber / square(metre)> {} tesla; inline constexpr struct henry final : named_unit<"H", weber / ampere> {} henry; -inline constexpr struct ice_point final : relative_point_origin)}> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute(milli)> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; inline constexpr struct degree_Celsius final : named_unit {} degree_Celsius; diff --git a/src/systems/include/mp-units/systems/usc.h b/src/systems/include/mp-units/systems/usc.h index 691f18d4..f9c1b3ba 100644 --- a/src/systems/include/mp-units/systems/usc.h +++ b/src/systems/include/mp-units/systems/usc.h @@ -118,7 +118,7 @@ inline constexpr struct troy_pound final : named_unit<"lb t", mag<12> * troy_onc inline constexpr struct inch_of_mercury final : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury; // https://en.wikipedia.org/wiki/United_States_customary_units#Temperature -inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit; +inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin<-32 * absolute(mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit; inline constexpr struct degree_Fahrenheit final : named_unit * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit; // clang-format on From 1eac5a923b359b1f7964af49ada8a1218157d4d4 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 08:54:58 +0200 Subject: [PATCH 05/11] docs: documentation updated for reference specifiers --- docs/getting_started/quick_start.md | 4 +- .../framework_basics/design_overview.md | 2 +- .../framework_basics/the_affine_space.md | 95 +++++++++++++++---- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md index 4a76744f..0c833fa8 100644 --- a/docs/getting_started/quick_start.md +++ b/docs/getting_started/quick_start.md @@ -238,7 +238,7 @@ This introduces an additional type-safety. using namespace mp_units::si::unit_symbols; using namespace mp_units::usc::unit_symbols; - quantity_point temp{20. * deg_C}; + quantity_point temp = 20. * absolute(deg_C); std::println("Temperature: {} ({})", temp.quantity_from_zero(), temp.in(deg_F).quantity_from_zero()); @@ -259,7 +259,7 @@ This introduces an additional type-safety. using namespace mp_units::si::unit_symbols; using namespace mp_units::usc::unit_symbols; - quantity_point temp{20. * deg_C}; + quantity_point temp = 20. * absolute(deg_C); std::println("Temperature: {} ({})", temp.quantity_from_zero(), temp.in(deg_F).quantity_from_zero()); diff --git a/docs/users_guide/framework_basics/design_overview.md b/docs/users_guide/framework_basics/design_overview.md index 04857726..72ac7a71 100644 --- a/docs/users_guide/framework_basics/design_overview.md +++ b/docs/users_guide/framework_basics/design_overview.md @@ -378,5 +378,5 @@ For example: the previous example: ```cpp - constexpr auto room_reference_temperature = ice_point + isq::Celsius_temperature(21 * deg_C); + constexpr auto room_reference_temperature = ice_point + isq::Celsius_temperature(21 * delta(deg_C)); ``` diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index 54fe7cf2..ffba731f 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -3,7 +3,7 @@ The affine space has two types of entities: - **_Point_** - a position specified with coordinate values (e.g., location, address, etc.) -- **_Displacement vectors_** - the difference between two points (e.g., shift, offset, +- **_Displacement vector_** - the difference between two points (e.g., shift, offset, displacement, duration, etc.) In the following subchapters, we will often refer to _displacement vectors_ simply as _vectors_ for @@ -70,6 +70,49 @@ difference between two things: As we already know, a `quantity` type provides all operations required for a _displacement vector_ abstraction in an affine space. +Quantities are constructed from a delta quantity reference. Most of units are considered to be +delta references by default. The ones that need a special qualification are the units that +get a point origin in their definition (i.e., units of temperature). + +We can create a `quantity` by passing a delta quantity reference to either: + +- two-parameter constructor: + + ```cpp + quantity q1(42, si::metre); + // quantity q2(42, si::kelvin); // Compile-time error + // quantity q3(42, si::degree_Celsius); // Compile-time error + // quantity q4(42, usc::degree_Fahrenheit); // Compile-time error + quantity q5(42, delta(si::metre)); + quantity q6(42, delta(si::kelvin)); + quantity q7(42, delta(si::degree_Celsius)); + quantity q8(42, delta(usc::degree_Fahrenheit)); + ``` + +- multiply syntax: + + ```cpp + quantity q1 = 42 * m; + // quantity q2 = 42 * K; // Compile-time error + // quantity q3 = 42 * deg_C; // Compile-time error + // quantity q4 = 42 * deg_F; // Compile-time error + quantity q5 = 42 * delta(m); + quantity q6 = 42 * delta(K); + quantity q7 = 42 * delta(deg_C); + quantity q8 = 42 * delta(deg_F); + ``` + +!!! note + + `delta` specifier is used to qualify the entire reference upon `quantity` construction. + It does not satisfy the [`Reference`](concepts.md#Reference) concept. This means that, + for example, the below are ill-formed: + + ```cpp + void foo(quantity temp); // ill-formed + quantity specific_heat_capacity; // ill-formed + quantity R = 8.314 * N * m / (delta(deg_C) * mol); // ill-formed + ``` ## _Point_ is modeled by `quantity_point` and `PointOrigin` @@ -109,6 +152,19 @@ scale zeroth point using the following rules: - otherwise, an instantiation of `zeroth_point_origin` is being used which provides a well-established zeroth point for a specific quantity type. +Quantity points with default point origins may be constructed using multiply syntax from an +absolute quantity reference. None of units are considered to be absolute references by default, +so they need a special qualification: + +```cpp +// quantity_point qp1 = 42 * m; // Compile-time error +// quantity_point qp2 = 42 * K; // Compile-time error +// quantity_point qp3 = 42 * deg_C; // Compile-time error +quantity_point qp4 = 42 * absolute(m); +quantity_point qp5 = 42 * absolute(K); +quantity_point qp6 = 42 * absolute(deg_C); +``` + !!! tip The `quantity_point` definition can be found in the `mp-units/quantity_point.h` header file. @@ -124,8 +180,8 @@ for this domain. ![affine_space_1](affine_space_1.svg){style="width:80%;display: block;margin: 0 auto;"} ```cpp -quantity_point qp1{100 * m}; -quantity_point qp2{120 * m}; +quantity_point qp1 = 100 * absolute(m); +quantity_point qp2 = 120 * absolute(m); assert(qp1.quantity_from_zero() == 100 * m); assert(qp2.quantity_from_zero() == 120 * m); @@ -174,8 +230,8 @@ origin. ```cpp inline constexpr struct origin final : absolute_point_origin {} origin; -// quantity_point qp1{100 * m}; // Compile-time error -// quantity_point qp2{120 * m}; // Compile-time error +// quantity_point qp1{100 * m}; // Compile-time error +// quantity_point qp2 = 120 * absolute(m); // Compile-time error quantity_point qp1 = origin + 100 * m; quantity_point qp2 = 120 * m + origin; @@ -387,7 +443,7 @@ namespace si { inline constexpr struct absolute_zero final : absolute_point_origin {} absolute_zero; inline constexpr auto zeroth_kelvin = absolute_zero; -inline constexpr struct ice_point final : relative_point_origin}> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute(milli)}> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; } @@ -395,7 +451,7 @@ inline constexpr auto zeroth_degree_Celsius = ice_point; namespace usc { inline constexpr struct zeroth_degree_Fahrenheit final : - relative_point_origin * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit; + relative_point_origin<-32 * absolute(mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit; } ``` @@ -444,25 +500,28 @@ choose from here. Depending on our needs or tastes, we can: - be explicit about the unit and origin: ```cpp - quantity_point q1 = si::zeroth_degree_Celsius + 20.5 * deg_C; - quantity_point q2 = {20.5 * deg_C, si::zeroth_degree_Celsius}; - quantity_point q3{20.5 * deg_C}; + quantity_point q1 = si::zeroth_degree_Celsius + 20.5 * delta(deg_C); + quantity_point q2 = {20.5 * delta(deg_C), si::zeroth_degree_Celsius}; + quantity_point q3{20.5 * delta(deg_C)}; + quantity_point q4 = 20.5 * absolute(deg_C); ``` - specify a unit and use its zeroth point origin implicitly: ```cpp - quantity_point q4 = si::zeroth_degree_Celsius + 20.5 * deg_C; - quantity_point q5 = {20.5 * deg_C, si::zeroth_degree_Celsius}; - quantity_point q6{20.5 * deg_C}; + quantity_point q5 = si::zeroth_degree_Celsius + 20.5 * delta(deg_C); + quantity_point q6 = {20.5 * delta(deg_C), si::zeroth_degree_Celsius}; + quantity_point q7{20.5 * delta(deg_C)}; + quantity_point q8 = 20.5 * absolute(deg_C); ``` - benefit from CTAD: ```cpp - quantity_point q7 = si::zeroth_degree_Celsius + 20.5 * deg_C; - quantity_point q8 = {20.5 * deg_C, si::zeroth_degree_Celsius}; - quantity_point q9{20.5 * deg_C}; + quantity_point q9 = si::zeroth_degree_Celsius + 20.5 * delta(deg_C); + quantity_point q10 = {20.5 * delta(deg_C), si::zeroth_degree_Celsius}; + quantity_point q11{20.5 * delta(deg_C)}; + quantity_point q12 = 20.5 * absolute(deg_C); ``` In all of the above cases, we end up with the `quantity_point` of the same type and value. @@ -473,10 +532,10 @@ the following way: ![affine_space_6](affine_space_6.svg){style="width:80%;display: block;margin: 0 auto;"} ```cpp -constexpr struct room_reference_temp final : relative_point_origin {} room_reference_temp; +constexpr struct room_reference_temp final : relative_point_origin<21 * absolute(deg_C)> {} room_reference_temp; using room_temp = quantity_point; -constexpr auto step_delta = isq::Celsius_temperature(0.5 * deg_C); +constexpr auto step_delta = isq::Celsius_temperature(0.5 * delta(deg_C)); constexpr int number_of_steps = 6; room_temp room_ref{}; From 4b46be76047f8cb0d76684db723c854712834d56 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 09:20:33 +0200 Subject: [PATCH 06/11] refactor: reference specifiers are now variable templates --- docs/getting_started/quick_start.md | 4 +- .../framework_basics/design_overview.md | 2 +- .../framework_basics/the_affine_space.md | 66 +++++++++---------- .../kalman_filter/kalman_filter-example_6.cpp | 14 ++-- .../kalman_filter/kalman_filter-example_7.cpp | 14 ++-- .../kalman_filter/kalman_filter-example_8.cpp | 14 ++-- example/spectroscopy_units.cpp | 2 +- src/core/include/mp-units/bits/sudo_cast.h | 6 +- .../include/mp-units/framework/quantity.h | 36 +++++----- .../mp-units/framework/quantity_cast.h | 2 +- .../mp-units/framework/quantity_spec.h | 6 +- .../include/mp-units/framework/reference.h | 14 ++-- .../mp-units/framework/reference_concepts.h | 19 ++---- src/core/include/mp-units/math.h | 18 ++--- .../include/mp-units/systems/si/units.h | 2 +- src/systems/include/mp-units/systems/usc.h | 2 +- test/static/quantity_point_test.cpp | 20 +++--- test/static/usc_test.cpp | 4 +- 18 files changed, 120 insertions(+), 125 deletions(-) diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md index 0c833fa8..1047b6ef 100644 --- a/docs/getting_started/quick_start.md +++ b/docs/getting_started/quick_start.md @@ -238,7 +238,7 @@ This introduces an additional type-safety. using namespace mp_units::si::unit_symbols; using namespace mp_units::usc::unit_symbols; - quantity_point temp = 20. * absolute(deg_C); + quantity_point temp = 20. * absolute; std::println("Temperature: {} ({})", temp.quantity_from_zero(), temp.in(deg_F).quantity_from_zero()); @@ -259,7 +259,7 @@ This introduces an additional type-safety. using namespace mp_units::si::unit_symbols; using namespace mp_units::usc::unit_symbols; - quantity_point temp = 20. * absolute(deg_C); + quantity_point temp = 20. * absolute; std::println("Temperature: {} ({})", temp.quantity_from_zero(), temp.in(deg_F).quantity_from_zero()); diff --git a/docs/users_guide/framework_basics/design_overview.md b/docs/users_guide/framework_basics/design_overview.md index 72ac7a71..530cb7a5 100644 --- a/docs/users_guide/framework_basics/design_overview.md +++ b/docs/users_guide/framework_basics/design_overview.md @@ -378,5 +378,5 @@ For example: the previous example: ```cpp - constexpr auto room_reference_temperature = ice_point + isq::Celsius_temperature(21 * delta(deg_C)); + constexpr auto room_reference_temperature = ice_point + isq::Celsius_temperature(21 * delta); ``` diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index ffba731f..67dc799e 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -83,10 +83,10 @@ We can create a `quantity` by passing a delta quantity reference to either: // quantity q2(42, si::kelvin); // Compile-time error // quantity q3(42, si::degree_Celsius); // Compile-time error // quantity q4(42, usc::degree_Fahrenheit); // Compile-time error - quantity q5(42, delta(si::metre)); - quantity q6(42, delta(si::kelvin)); - quantity q7(42, delta(si::degree_Celsius)); - quantity q8(42, delta(usc::degree_Fahrenheit)); + quantity q5(42, delta); + quantity q6(42, delta); + quantity q7(42, delta); + quantity q8(42, delta); ``` - multiply syntax: @@ -96,10 +96,10 @@ We can create a `quantity` by passing a delta quantity reference to either: // quantity q2 = 42 * K; // Compile-time error // quantity q3 = 42 * deg_C; // Compile-time error // quantity q4 = 42 * deg_F; // Compile-time error - quantity q5 = 42 * delta(m); - quantity q6 = 42 * delta(K); - quantity q7 = 42 * delta(deg_C); - quantity q8 = 42 * delta(deg_F); + quantity q5 = 42 * delta; + quantity q6 = 42 * delta; + quantity q7 = 42 * delta; + quantity q8 = 42 * delta; ``` !!! note @@ -109,9 +109,9 @@ We can create a `quantity` by passing a delta quantity reference to either: for example, the below are ill-formed: ```cpp - void foo(quantity temp); // ill-formed - quantity specific_heat_capacity; // ill-formed - quantity R = 8.314 * N * m / (delta(deg_C) * mol); // ill-formed + void foo(quantity> temp); // ill-formed + quantity * mol)> specific_heat_capacity; // ill-formed + quantity R = 8.314 * N * m / (delta * mol); // ill-formed ``` ## _Point_ is modeled by `quantity_point` and `PointOrigin` @@ -160,9 +160,9 @@ so they need a special qualification: // quantity_point qp1 = 42 * m; // Compile-time error // quantity_point qp2 = 42 * K; // Compile-time error // quantity_point qp3 = 42 * deg_C; // Compile-time error -quantity_point qp4 = 42 * absolute(m); -quantity_point qp5 = 42 * absolute(K); -quantity_point qp6 = 42 * absolute(deg_C); +quantity_point qp4 = 42 * absolute; +quantity_point qp5 = 42 * absolute; +quantity_point qp6 = 42 * absolute; ``` !!! tip @@ -180,8 +180,8 @@ for this domain. ![affine_space_1](affine_space_1.svg){style="width:80%;display: block;margin: 0 auto;"} ```cpp -quantity_point qp1 = 100 * absolute(m); -quantity_point qp2 = 120 * absolute(m); +quantity_point qp1 = 100 * absolute; +quantity_point qp2 = 120 * absolute; assert(qp1.quantity_from_zero() == 100 * m); assert(qp2.quantity_from_zero() == 120 * m); @@ -231,7 +231,7 @@ origin. inline constexpr struct origin final : absolute_point_origin {} origin; // quantity_point qp1{100 * m}; // Compile-time error -// quantity_point qp2 = 120 * absolute(m); // Compile-time error +// quantity_point qp2 = 120 * absolute; // Compile-time error quantity_point qp1 = origin + 100 * m; quantity_point qp2 = 120 * m + origin; @@ -443,7 +443,7 @@ namespace si { inline constexpr struct absolute_zero final : absolute_point_origin {} absolute_zero; inline constexpr auto zeroth_kelvin = absolute_zero; -inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute(milli)}> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute>}> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; } @@ -451,7 +451,7 @@ inline constexpr auto zeroth_degree_Celsius = ice_point; namespace usc { inline constexpr struct zeroth_degree_Fahrenheit final : - relative_point_origin<-32 * absolute(mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit; + relative_point_origin<-32 * absolute * si::degree_Celsius>> {} zeroth_degree_Fahrenheit; } ``` @@ -500,28 +500,28 @@ choose from here. Depending on our needs or tastes, we can: - be explicit about the unit and origin: ```cpp - quantity_point q1 = si::zeroth_degree_Celsius + 20.5 * delta(deg_C); - quantity_point q2 = {20.5 * delta(deg_C), si::zeroth_degree_Celsius}; - quantity_point q3{20.5 * delta(deg_C)}; - quantity_point q4 = 20.5 * absolute(deg_C); + quantity_point q1 = si::zeroth_degree_Celsius + 20.5 * delta; + quantity_point q2 = {20.5 * delta, si::zeroth_degree_Celsius}; + quantity_point q3{20.5 * delta}; + quantity_point q4 = 20.5 * absolute; ``` - specify a unit and use its zeroth point origin implicitly: ```cpp - quantity_point q5 = si::zeroth_degree_Celsius + 20.5 * delta(deg_C); - quantity_point q6 = {20.5 * delta(deg_C), si::zeroth_degree_Celsius}; - quantity_point q7{20.5 * delta(deg_C)}; - quantity_point q8 = 20.5 * absolute(deg_C); + quantity_point q5 = si::zeroth_degree_Celsius + 20.5 * delta; + quantity_point q6 = {20.5 * delta, si::zeroth_degree_Celsius}; + quantity_point q7{20.5 * delta}; + quantity_point q8 = 20.5 * absolute; ``` - benefit from CTAD: ```cpp - quantity_point q9 = si::zeroth_degree_Celsius + 20.5 * delta(deg_C); - quantity_point q10 = {20.5 * delta(deg_C), si::zeroth_degree_Celsius}; - quantity_point q11{20.5 * delta(deg_C)}; - quantity_point q12 = 20.5 * absolute(deg_C); + quantity_point q9 = si::zeroth_degree_Celsius + 20.5 * delta; + quantity_point q10 = {20.5 * delta, si::zeroth_degree_Celsius}; + quantity_point q11{20.5 * delta}; + quantity_point q12 = 20.5 * absolute; ``` In all of the above cases, we end up with the `quantity_point` of the same type and value. @@ -532,10 +532,10 @@ the following way: ![affine_space_6](affine_space_6.svg){style="width:80%;display: block;margin: 0 auto;"} ```cpp -constexpr struct room_reference_temp final : relative_point_origin<21 * absolute(deg_C)> {} room_reference_temp; +constexpr struct room_reference_temp final : relative_point_origin<21 * absolute> {} room_reference_temp; using room_temp = quantity_point; -constexpr auto step_delta = isq::Celsius_temperature(0.5 * delta(deg_C)); +constexpr auto step_delta = isq::Celsius_temperature(0.5 * delta); constexpr int number_of_steps = 6; room_temp room_ref{}; diff --git a/example/kalman_filter/kalman_filter-example_6.cpp b/example/kalman_filter/kalman_filter-example_6.cpp index 20e96137..82a337ce 100644 --- a/example/kalman_filter/kalman_filter-example_6.cpp +++ b/example/kalman_filter/kalman_filter-example_6.cpp @@ -62,13 +62,13 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.0001 * delta(pow<2>(deg_C)); - const estimate initial{state{qp{60. * delta(deg_C)}}, 100. * delta(deg_C)}; - const std::array measurements = {qp{49.986 * delta(deg_C)}, qp{49.963 * delta(deg_C)}, qp{50.097 * delta(deg_C)}, - qp{50.001 * delta(deg_C)}, qp{50.018 * delta(deg_C)}, qp{50.05 * delta(deg_C)}, - qp{49.938 * delta(deg_C)}, qp{49.858 * delta(deg_C)}, qp{49.965 * delta(deg_C)}, - qp{50.114 * delta(deg_C)}}; - const quantity measurement_error = 0.1 * delta(deg_C); + const quantity process_noise_variance = 0.0001 * delta(deg_C)>; + const estimate initial{state{qp{60. * delta}}, 100. * delta}; + const std::array measurements = {qp{49.986 * delta}, qp{49.963 * delta}, qp{50.097 * delta}, + qp{50.001 * delta}, qp{50.018 * delta}, qp{50.05 * delta}, + qp{49.938 * delta}, qp{49.858 * delta}, qp{49.965 * delta}, + qp{50.114 * delta}}; + const quantity measurement_error = 0.1 * delta; const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/kalman_filter/kalman_filter-example_7.cpp b/example/kalman_filter/kalman_filter-example_7.cpp index 0fe7889f..7fe1a9ac 100644 --- a/example/kalman_filter/kalman_filter-example_7.cpp +++ b/example/kalman_filter/kalman_filter-example_7.cpp @@ -62,13 +62,13 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.0001 * delta(pow<2>(deg_C)); - const estimate initial{state{qp{10. * delta(deg_C)}}, 100. * delta(deg_C)}; - const std::array measurements = {qp{50.486 * delta(deg_C)}, qp{50.963 * delta(deg_C)}, qp{51.597 * delta(deg_C)}, - qp{52.001 * delta(deg_C)}, qp{52.518 * delta(deg_C)}, qp{53.05 * delta(deg_C)}, - qp{53.438 * delta(deg_C)}, qp{53.858 * delta(deg_C)}, qp{54.465 * delta(deg_C)}, - qp{55.114 * delta(deg_C)}}; - const quantity measurement_error = 0.1 * delta(deg_C); + const quantity process_noise_variance = 0.0001 * delta(deg_C)>; + const estimate initial{state{qp{10. * delta}}, 100. * delta}; + const std::array measurements = {qp{50.486 * delta}, qp{50.963 * delta}, qp{51.597 * delta}, + qp{52.001 * delta}, qp{52.518 * delta}, qp{53.05 * delta}, + qp{53.438 * delta}, qp{53.858 * delta}, qp{54.465 * delta}, + qp{55.114 * delta}}; + const quantity measurement_error = 0.1 * delta; const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/kalman_filter/kalman_filter-example_8.cpp b/example/kalman_filter/kalman_filter-example_8.cpp index 3f27a467..158f54a9 100644 --- a/example/kalman_filter/kalman_filter-example_8.cpp +++ b/example/kalman_filter/kalman_filter-example_8.cpp @@ -62,13 +62,13 @@ int main() using estimate = kalman::system_state_estimate; using state = estimate::state_type; - const quantity process_noise_variance = 0.15 * delta(pow<2>(deg_C)); - const estimate initial{state{qp{10. * delta(deg_C)}}, 100. * delta(deg_C)}; - const std::array measurements = {qp{50.486 * delta(deg_C)}, qp{50.963 * delta(deg_C)}, qp{51.597 * delta(deg_C)}, - qp{52.001 * delta(deg_C)}, qp{52.518 * delta(deg_C)}, qp{53.05 * delta(deg_C)}, - qp{53.438 * delta(deg_C)}, qp{53.858 * delta(deg_C)}, qp{54.465 * delta(deg_C)}, - qp{55.114 * delta(deg_C)}}; - const quantity measurement_error = 0.1 * delta(deg_C); + const quantity process_noise_variance = 0.15 * delta(deg_C)>; + const estimate initial{state{qp{10. * delta}}, 100. * delta}; + const std::array measurements = {qp{50.486 * delta}, qp{50.963 * delta}, qp{51.597 * delta}, + qp{52.001 * delta}, qp{52.518 * delta}, qp{53.05 * delta}, + qp{53.438 * delta}, qp{53.858 * delta}, qp{54.465 * delta}, + qp{55.114 * delta}}; + const quantity measurement_error = 0.1 * delta; const quantity measurement_variance = pow<2>(measurement_error); auto predict = [=](const estimate& current) { diff --git a/example/spectroscopy_units.cpp b/example/spectroscopy_units.cpp index d134e698..068ed14d 100644 --- a/example/spectroscopy_units.cpp +++ b/example/spectroscopy_units.cpp @@ -84,7 +84,7 @@ int main() const auto t3 = std::make_tuple(isq::energy(q3 * h), isq::wavenumber(q3 / c), q3, isq::thermodynamic_temperature(q3 * h / kb), isq::wavelength(c / q3)); - const auto q4 = isq::thermodynamic_temperature(1. * delta(K)); + const auto q4 = isq::thermodynamic_temperature(1. * delta); const auto t4 = std::make_tuple(isq::energy(q4 * kb), isq::wavenumber(q4 * kb / (h * c)), isq::frequency(q4 * kb / h), q4, isq::wavelength(h * c / (q4 * kb))); diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index aefb2b13..5a79f2e6 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -97,7 +97,7 @@ template if constexpr (q_unit == To::unit) { // no scaling of the number needed return {static_cast(std::forward(q).numerical_value_is_an_implementation_detail_), - delta(To::reference)}; // this is the only (and recommended) way to do + delta}; // 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 @@ -108,13 +108,13 @@ template // this results in great assembly auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::ratio); - return {res, delta(To::reference)}; + return {res, delta}; } else { // this is slower but allows conversions like 2000 m -> 2 km without loosing data auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::num_mult / traits::den_mult * traits::irr_mult); - return {res, delta(To::reference)}; + return {res, delta}; } } } diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 28cdbafe..1e69e053 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -123,25 +123,25 @@ public: [[nodiscard]] static constexpr quantity zero() noexcept requires requires { quantity_values::zero(); } { - return {quantity_values::zero(), delta(R)}; + return {quantity_values::zero(), delta}; } [[nodiscard]] static constexpr quantity one() noexcept requires requires { quantity_values::one(); } { - return {quantity_values::one(), delta(R)}; + return {quantity_values::one(), delta}; } [[nodiscard]] static constexpr quantity min() noexcept requires requires { quantity_values::min(); } { - return {quantity_values::min(), delta(R)}; + return {quantity_values::min(), delta}; } [[nodiscard]] static constexpr quantity max() noexcept requires requires { quantity_values::max(); } { - return {quantity_values::max(), delta(R)}; + return {quantity_values::max(), delta}; } // construction, assignment, destruction @@ -180,7 +180,7 @@ public: // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) !std::convertible_to::rep, Rep>) quantity(const Q& q) : quantity(::mp_units::quantity{quantity_like_traits::to_numerical_value(q).value, - delta(quantity_like_traits::reference)}) + delta::reference>}) { } @@ -274,7 +274,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, delta(reference)}; + return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, delta}; } [[nodiscard]] constexpr QuantityOf auto operator-() const @@ -284,7 +284,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, delta(reference)}; + return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, delta}; } template @@ -306,7 +306,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, delta(reference)}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, delta}; } template @@ -328,7 +328,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, delta(reference)}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, delta}; } // compound assignment operators @@ -445,7 +445,7 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit), - delta(ret::reference)}; + delta}; } template @@ -456,7 +456,7 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit), - delta(ret::reference)}; + delta}; } template @@ -469,14 +469,14 @@ template const ret ret_lhs(lhs); const ret ret_rhs(rhs); return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit), - delta(ret::reference)}; + delta}; } template requires detail::InvocableQuantities, quantity, quantity> [[nodiscard]] constexpr Quantity auto operator*(const quantity& lhs, const quantity& rhs) { - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), delta(R1 * R2)}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), delta}; } template @@ -484,7 +484,7 @@ template detail::InvokeResultOf, Rep, const Value&> [[nodiscard]] constexpr QuantityOf auto operator*(const quantity& q, const Value& v) { - return quantity{q.numerical_value_ref_in(get_unit(R)) * v, delta(R)}; + return quantity{q.numerical_value_ref_in(get_unit(R)) * v, delta}; } template @@ -492,7 +492,7 @@ template detail::InvokeResultOf, const Value&, Rep> [[nodiscard]] constexpr QuantityOf auto operator*(const Value& v, const quantity& q) { - return quantity{v * q.numerical_value_ref_in(get_unit(R)), delta(R)}; + return quantity{v * q.numerical_value_ref_in(get_unit(R)), delta}; } template @@ -500,7 +500,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(const quantity& lhs, const quantity& rhs) { MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); - return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), delta(R1 / R2)}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), delta}; } template @@ -509,7 +509,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const quantity& q, const Value& v) { MP_UNITS_EXPECTS_DEBUG(v != quantity_values::zero()); - return quantity{q.numerical_value_ref_in(get_unit(R)) / v, delta(R)}; + return quantity{q.numerical_value_ref_in(get_unit(R)) / v, delta}; } template @@ -518,7 +518,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const Value& v, const quantity& q) { - return quantity{v / q.numerical_value_ref_in(get_unit(R)), delta(::mp_units::one / R)}; + return quantity{v / q.numerical_value_ref_in(get_unit(R)), delta<::mp_units::one / R>}; } template diff --git a/src/core/include/mp-units/framework/quantity_cast.h b/src/core/include/mp-units/framework/quantity_cast.h index 081955d9..b1e4e6fc 100644 --- a/src/core/include/mp-units/framework/quantity_cast.h +++ b/src/core/include/mp-units/framework/quantity_cast.h @@ -57,7 +57,7 @@ template [[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - delta(make_reference(ToQS, std::remove_reference_t::unit))}; + delta::unit)>}; } /** diff --git a/src/core/include/mp-units/framework/quantity_spec.h b/src/core/include/mp-units/framework/quantity_spec.h index 565ee049..9b4a3131 100644 --- a/src/core/include/mp-units/framework/quantity_spec.h +++ b/src/core/include/mp-units/framework/quantity_spec.h @@ -129,7 +129,7 @@ struct quantity_spec_interface { (explicitly_convertible(std::remove_reference_t::quantity_spec, self)) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - delta(detail::make_reference(self, std::remove_cvref_t::unit))}; + delta::unit)>}; } #else template U> @@ -144,7 +144,7 @@ struct quantity_spec_interface { [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - delta(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; + delta::unit)>}; } #endif }; @@ -341,7 +341,7 @@ struct quantity_spec : detail::propagate_equation, detail [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - delta(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; + delta::unit)>}; } #endif }; diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index a9223f2e..4d46a26d 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -44,8 +44,8 @@ template requires DeltaReference || AbsoluteReference [[nodiscard]] consteval Reference auto get_original_reference(R r) { - if constexpr (requires { typename R::_type_; }) - return typename R::_type_{}; + if constexpr (requires { R::_original_reference_; }) + return R::_original_reference_; else return r; } @@ -195,7 +195,7 @@ template [[nodiscard]] constexpr quantity> operator/( Rep&& lhs, R) { - return quantity{std::forward(lhs), delta(inverse(detail::get_original_reference(R{})))}; + return quantity{std::forward(lhs), delta}; } template @@ -205,7 +205,7 @@ template std::remove_cvref_t> operator*(Rep&& lhs, R) { - return quantity_point{std::forward(lhs) * delta(detail::get_original_reference(R{}))}; + return quantity_point{std::forward(lhs) * delta}; } template @@ -215,7 +215,7 @@ template std::remove_cvref_t> operator/(Rep&& lhs, R) { - return quantity_point{std::forward(lhs) * delta(inverse(detail::get_original_reference(R{})))}; + return quantity_point{std::forward(lhs) * delta}; } template @@ -233,7 +233,7 @@ template [[nodiscard]] constexpr Quantity auto operator*(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - delta(std::remove_cvref_t::reference * R{})}; + delta::reference * R{}>}; } template @@ -241,7 +241,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - delta(std::remove_cvref_t::reference / R{})}; + delta::reference / R{}>}; } template diff --git a/src/core/include/mp-units/framework/reference_concepts.h b/src/core/include/mp-units/framework/reference_concepts.h index 91bd1a73..798e9411 100644 --- a/src/core/include/mp-units/framework/reference_concepts.h +++ b/src/core/include/mp-units/framework/reference_concepts.h @@ -80,27 +80,22 @@ concept ReferenceOf = Reference && QuantitySpecOf struct relative_ final { - using _type_ = R; + static constexpr Reference auto _original_reference_ = R{}; }; template struct absolute_ final { - using _type_ = R; + static constexpr Reference auto _original_reference_ = R{}; }; -template -MP_UNITS_EXPORT [[nodiscard]] consteval relative_ delta(R) -{ - return {}; -} +template +MP_UNITS_EXPORT inline constexpr relative_ delta{}; -template -MP_UNITS_EXPORT [[nodiscard]] consteval absolute_ absolute(R) -{ - return {}; -} +template +MP_UNITS_EXPORT inline constexpr absolute_ absolute{}; template MP_UNITS_EXPORT concept DeltaReference = diff --git a/src/core/include/mp-units/math.h b/src/core/include/mp-units/math.h index c357a7d9..96fb2ffa 100644 --- a/src/core/include/mp-units/math.h +++ b/src/core/include/mp-units/math.h @@ -115,7 +115,7 @@ template auto R, typename Rep> { using std::exp; return value_cast( - quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), delta(detail::clone_reference_with(R))}); + quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), delta(R)>}); } /** @@ -236,7 +236,7 @@ template using std::fma; return quantity{ fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)), - delta(common_reference(R * S, T))}; + delta}; } /** @@ -260,7 +260,7 @@ template}; } /** @@ -277,7 +277,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::fmod; - return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta(ref)}; + return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta}; } /** @@ -294,7 +294,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::remainder; - return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta(ref)}; + return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta}; } @@ -339,7 +339,7 @@ template return {static_cast(floor(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with(R)}; } else { return handle_signed_results( - quantity{static_cast(floor(q.force_numerical_value_in(To))), delta(detail::clone_reference_with(R))}); + quantity{static_cast(floor(q.force_numerical_value_in(To))), delta(R)>}); } } else { if constexpr (To == get_unit(R)) { @@ -376,7 +376,7 @@ template return {static_cast(ceil(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with(R)}; } else { return handle_signed_results( - quantity{static_cast(ceil(q.force_numerical_value_in(To))), delta(detail::clone_reference_with(R))}); + quantity{static_cast(ceil(q.force_numerical_value_in(To))), delta(R)>}); } } else { if constexpr (To == get_unit(R)) { @@ -456,7 +456,7 @@ template constexpr auto ref = common_reference(R1, R2); constexpr auto unit = get_unit(ref); using std::hypot; - return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta(ref)}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta}; } /** @@ -475,7 +475,7 @@ template constexpr auto unit = get_unit(ref); using std::hypot; return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), - delta(ref)}; + delta}; } } // namespace mp_units diff --git a/src/systems/include/mp-units/systems/si/units.h b/src/systems/include/mp-units/systems/si/units.h index 2730ab32..cb5371a6 100644 --- a/src/systems/include/mp-units/systems/si/units.h +++ b/src/systems/include/mp-units/systems/si/units.h @@ -77,7 +77,7 @@ inline constexpr struct weber final : named_unit<"Wb", volt * second> {} weber; inline constexpr struct tesla final : named_unit<"T", weber / square(metre)> {} tesla; inline constexpr struct henry final : named_unit<"H", weber / ampere> {} henry; -inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute(milli)> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute>> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; inline constexpr struct degree_Celsius final : named_unit {} degree_Celsius; diff --git a/src/systems/include/mp-units/systems/usc.h b/src/systems/include/mp-units/systems/usc.h index f9c1b3ba..6192d63b 100644 --- a/src/systems/include/mp-units/systems/usc.h +++ b/src/systems/include/mp-units/systems/usc.h @@ -118,7 +118,7 @@ inline constexpr struct troy_pound final : named_unit<"lb t", mag<12> * troy_onc inline constexpr struct inch_of_mercury final : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury; // https://en.wikipedia.org/wiki/United_States_customary_units#Temperature -inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin<-32 * absolute(mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit; +inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin<-32 * absolute * si::degree_Celsius>> {} zeroth_degree_Fahrenheit; inline constexpr struct degree_Fahrenheit final : named_unit * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit; // clang-format on diff --git a/test/static/quantity_point_test.cpp b/test/static/quantity_point_test.cpp index ccf1c479..b3ff307f 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -801,12 +801,12 @@ static_assert( ////////////////////////////////// static_assert(quantity_point{42 * m}.quantity_from_zero() == 42 * m); -static_assert((42 * absolute(m)).quantity_from_zero() == 42 * m); +static_assert((42 * absolute).quantity_from_zero() == 42 * m); static_assert(quantity_point{isq::height(42 * m)}.quantity_from_zero() == 42 * m); -static_assert(quantity_point{20 * delta(deg_C)}.quantity_from_zero() == 20 * delta(deg_C)); -static_assert((20 * absolute(deg_C)).quantity_from_zero() == 20 * delta(deg_C)); -static_assert(quantity_point{20. * delta(deg_C)}.in(deg_F).quantity_from_zero() == 68 * delta(deg_F)); -static_assert((20. * absolute(deg_C)).in(deg_F).quantity_from_zero() == 68 * delta(deg_F)); +static_assert(quantity_point{20 * delta}.quantity_from_zero() == 20 * delta); +static_assert((20 * absolute).quantity_from_zero() == 20 * delta); +static_assert(quantity_point{20. * delta}.in(deg_F).quantity_from_zero() == 68 * delta); +static_assert((20. * absolute).in(deg_F).quantity_from_zero() == 68 * delta); static_assert((mean_sea_level + 42 * m).quantity_from_zero() == 42 * m); static_assert((ground_level + 42 * m).quantity_from_zero() == 84 * m); @@ -892,12 +892,12 @@ static_assert(std::is_same_v); -static_assert(std::is_same_v, struct si::ice_point>); -static_assert(std::is_same_v, +static_assert(std::is_same_v)::rep, int>); +static_assert(std::is_same_v).point_origin)>, struct si::ice_point>); +static_assert(std::is_same_v).absolute_point_origin)>, struct si::absolute_zero>); -static_assert((20 * absolute(deg_C)).unit == si::degree_Celsius); -static_assert((20 * absolute(deg_C)).quantity_spec == kind_of); +static_assert((20 * absolute).unit == si::degree_Celsius); +static_assert((20 * absolute).quantity_spec == kind_of); #if MP_UNITS_HOSTED using namespace std::chrono_literals; diff --git a/test/static/usc_test.cpp b/test/static/usc_test.cpp index f6b9228b..a91f5a10 100644 --- a/test/static/usc_test.cpp +++ b/test/static/usc_test.cpp @@ -126,7 +126,7 @@ static_assert(isq::mass(1 * lb_t) == isq::mass(12 * oz_t)); static_assert(isq::pressure(1'000 * inHg) == isq::pressure(3'386'389 * si::pascal)); // Temperature -static_assert(isq::thermodynamic_temperature(9 * delta(deg_F)) == - isq::thermodynamic_temperature(5 * delta(si::degree_Celsius))); +static_assert(isq::thermodynamic_temperature(9 * delta) == + isq::thermodynamic_temperature(5 * delta)); } // namespace From eb6c48afae069d76a85ee12aa6672318f09e9a9f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 09:20:56 +0200 Subject: [PATCH 07/11] docs: CHANGELOG updated --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7013ee..039f8e22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### 2.3.0 WIP { id="2.3.0" } +- (!) feat: Reference specifiers [#585](https://github.com/mpusz/mp-units/pull/585) + ### 2.2.0 June 14, 2024 { id="2.2.0" } - (!) feat: C++ modules support added by [@JohelEGP](https://github.com/JohelEGP) From e08a0ace248b0e6b33d77aa542dda0240f159a2c Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 10:19:22 +0200 Subject: [PATCH 08/11] fix: missing header file include added --- src/core/include/mp-units/framework/reference.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/include/mp-units/framework/reference.h b/src/core/include/mp-units/framework/reference.h index 4d46a26d..d5b980d7 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include From cdd345c9ec20c55c0040015cbca5315d9ba7722f Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 12:43:08 +0200 Subject: [PATCH 09/11] docs: typo in the affine space chapter fixed --- docs/users_guide/framework_basics/the_affine_space.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index 67dc799e..9e71aaae 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -443,7 +443,7 @@ namespace si { inline constexpr struct absolute_zero final : absolute_point_origin {} absolute_zero; inline constexpr auto zeroth_kelvin = absolute_zero; -inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute>}> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute>>> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; } From 960417a34615dcaf43c6a72d37b2ef233b569947 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 12:43:59 +0200 Subject: [PATCH 10/11] fix: reference specifiers export fixed --- .../mp-units/framework/reference_concepts.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/core/include/mp-units/framework/reference_concepts.h b/src/core/include/mp-units/framework/reference_concepts.h index 798e9411..0bd2a49d 100644 --- a/src/core/include/mp-units/framework/reference_concepts.h +++ b/src/core/include/mp-units/framework/reference_concepts.h @@ -91,17 +91,21 @@ struct absolute_ final { static constexpr Reference auto _original_reference_ = R{}; }; -template -MP_UNITS_EXPORT inline constexpr relative_ delta{}; +MP_UNITS_EXPORT_BEGIN template -MP_UNITS_EXPORT inline constexpr absolute_ absolute{}; +inline constexpr relative_ delta{}; + +template +inline constexpr absolute_ absolute{}; template -MP_UNITS_EXPORT concept DeltaReference = +concept DeltaReference = (Reference && !requires { get_unit(T{}).point_origin; }) || is_specialization_of; template -MP_UNITS_EXPORT concept AbsoluteReference = is_specialization_of; +concept AbsoluteReference = is_specialization_of; + +MP_UNITS_EXPORT_END } // namespace mp_units From e43426438f5abe74bc05c881b39b2a49715e4fc2 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 20 Jun 2024 20:29:21 +0200 Subject: [PATCH 11/11] fix: `quantity` constraints fixed --- src/core/include/mp-units/framework/quantity.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index 1e69e053..014e9e8e 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -88,10 +88,11 @@ template using common_quantity_for = quantity>; -template -concept SameOriginalReferenceAs = DeltaReference && Reference && (get_original_reference(T{}) == R{}); +template +concept SameOriginalReferenceAs = DeltaReference && + Reference && (get_original_reference(T) == R); -template +template concept SameValueAs = detail::SameOriginalReferenceAs && std::same_as; } // namespace detail @@ -151,14 +152,15 @@ public: ~quantity() = default; template - requires detail::SameValueAs, Rep> + requires detail::SameValueAs, Rep> constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward(v)) { } template - requires(!detail::SameValueAs, Rep>) && - detail::QuantityConvertibleTo>, quantity> + requires(!detail::SameValueAs, Rep>) && + detail::QuantityConvertibleTo>, + quantity> constexpr quantity(Value&& v, R2) : quantity(quantity>{std::forward(v), R2{}}) {