From ba8681f90b5ecc2ad586f6676d50b3a3a842d8a9 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sun, 30 Jun 2024 12:03:24 +0200 Subject: [PATCH] feat: :boom: `delta` and `absolute` construction helpers --- CHANGELOG.md | 2 +- docs/blog/posts/2.3.0-released.md | 93 +++++++++------ docs/getting_started/quick_start.md | 55 ++++++--- .../framework_basics/design_overview.md | 2 +- .../framework_basics/the_affine_space.md | 108 ++++++------------ .../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/CMakeLists.txt | 1 + src/core/include/mp-units/bits/sudo_cast.h | 10 +- src/core/include/mp-units/framework.h | 1 + .../mp-units/framework/construction_helpers.h | 67 +++++++++++ .../include/mp-units/framework/quantity.h | 77 ++++--------- .../mp-units/framework/quantity_cast.h | 2 +- .../mp-units/framework/quantity_spec.h | 6 +- .../include/mp-units/framework/reference.h | 74 ++++-------- .../mp-units/framework/reference_concepts.h | 36 ------ .../mp-units/framework/unit_concepts.h | 7 ++ src/core/include/mp-units/math.h | 25 ++-- .../include/mp-units/systems/si/units.h | 3 +- src/systems/include/mp-units/systems/usc.h | 2 +- test/static/quantity_point_test.cpp | 20 ++-- test/static/usc_test.cpp | 4 +- 24 files changed, 309 insertions(+), 330 deletions(-) create mode 100644 src/core/include/mp-units/framework/construction_helpers.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 039f8e22..1fb8214a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### 2.3.0 WIP { id="2.3.0" } -- (!) feat: Reference specifiers [#585](https://github.com/mpusz/mp-units/pull/585) +- (!) feat: `delta` and `absolute` construction helpers ### 2.2.0 June 14, 2024 { id="2.2.0" } diff --git a/docs/blog/posts/2.3.0-released.md b/docs/blog/posts/2.3.0-released.md index 6fa21140..ab1e87d7 100644 --- a/docs/blog/posts/2.3.0-released.md +++ b/docs/blog/posts/2.3.0-released.md @@ -37,7 +37,7 @@ std::cout << Pressure << "\n"; The problem is related to the accidental usage of a `quantity` rather than `quantity_point` for `Temperature`. This means that after conversion to kelvins, we will get `28 K` instead of -the expected `301.15 K`, which will corrupt all further calculations. +the expected `301.15 K`, corrupting all further calculations. A correct code should use a `quantity_point`: @@ -48,51 +48,68 @@ quantity_point Temperature(28.0 * deg_C); This might be an obvious thing for domain experts, but new users of the library may not be aware of the affine space abstractions and how they influence temperature handling. -After a lengthy discussion on handling such scenarios, we decided to aid the `quantity` and -`quantity_point` construction with `absolute` and `delta` quantity reference -specifiers. This applies to: +After a lengthy discussion on handling such scenarios, we decided to: -- the multiply syntax, -- 2-parameter `quantity` constructor. +- make the above code ill-formed, +- provide an alternative way to create a `quantity` with the `delta` quantity construction helper. Here are the main points of this new design: -1. All references/units that do not specify point origin (are not offset units) in their definition - are considered `delta` by default. This means that `42 * m` creates a `quantity` and is - the same as calling `42 * delta`. -2. Multiply syntax is extended to allow `quantity_point` creation with the `42 * absolute` - syntax. This will provide an implicit zeroth point origin. -3. For units that specify a point origin (`si::kelvin`, `si::degree_Celsius`, and -   `usc::degree_Fahrenheit`), the user always needs to specify a modifier. This means that: - - `4 * deg_C` does not compile, - - `4 * delta` creates a `quantity`. - - `4 * absolute` creates a `quantity_point`. -4. The 2-parameter `quantity` constructor requires the same: +1. All references/units that specify point origin in their definition (i.e., `si::kelvin`, +   `si::degree_Celsius`, and `usc::degree_Fahrenheit`) are excluded from the multiply syntax + (:boom: **breaking change** :boom:). +2. A new `delta` quantity construction helper is introduced: -```cpp -quantity q1(4, m); // OK -quantity q2(4, delta); // OK -quantity q3(4, absolute); // Compile-time error -quantity q4(4, deg_C); // Compile-time error -quantity q5(4, delta); // OK -quantity q6(4, absolute); // Compile-time error -``` + - `delta(42)` results with a `quantity`, + - `delta(5)` results with a `quantity`. -The `delta` and `absolute` modifiers are stripped upon construction, so the resulting `quantity` -and `quantity_point` types use the underlying unit in its type. +3. A new `absolute` quantity point construction helper is introduced: -With such changes, the offending code will not compile, forcing the user to think more about what -is written. To enable the compilation, the user has to type one of the following: + - `absolute(42)` results with a `quantity_point>{}, int>`, + - `absolute(5)` results with a `quantity`. -- `quantity_point Temperature(28.0 * delta);` -- `quantity_point Temperature = 28.0 * absolute;` +!!! info -If the user still insists on using `quantity` instead of a `quantity_point`, the code will -have to be written in the following way to compile successfully: + Please note that `si::kelvin` is also excluded from the multiply syntax to prevent the + following surprising issues: -```cpp -quantity Temperature = 28.0 * delta; -``` + === "Now" -This will yield an invalid result, but now, hopefully, it is clearly readable in the code what is -wrong here. + ```cpp + quantity q = delta(300); + quantity_point qp = absolute(300); + static_assert(q.in(deg_C) != qp.in(deg_C).quantity_from_zero()); + ``` + + === "Before" + + ```cpp + quantity q(300 * K); + quantity_point qp(300 * K); + static_assert(q.in(deg_C) != qp.in(deg_C).quantity_from_zero()); + ``` + + We believe that the code enforced with new utilities makes it much easier to understand what + happens here. + +With such changes to the interface design, the offending code will not compile as initially written. +Users will be forced to think more about what they write. To enable the compilation, the users have +to explicitly create a: + +- `quantity_point` (the intended abstraction in this example) with any of the below syntaxes: + + ```cpp + quantity_point Temperature = absolute(28.0); + auto Temperature = absolute(28.0); + quantity_point Temperature(delta(28.0)); + ``` + +- `quantity` (an incorrect abstraction in this example) with: + + ```cpp + quantity Temperature = delta(28.0); + auto Temperature = delta(28.0); + ``` + +Thanks to the new design, we can immediately see what happens here and why the result might be +incorrect in the second case. diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md index 1047b6ef..941a51d0 100644 --- a/docs/getting_started/quick_start.md +++ b/docs/getting_started/quick_start.md @@ -43,28 +43,51 @@ a number with a predefined unit: !!! info In case someone doesn't like the multiply syntax or there is an ambiguity between `operator*` - provided by this and other libraries, a quantity can also be created with a two-parameter - constructor: + provided by this and other libraries, there are two other ways to create a quantity: - === "C++ modules" + 1. `delta` construction helper: - ```cpp - import mp_units; + === "C++ modules" - using namespace mp_units; + ```cpp + import mp_units; - quantity q{42, si::metre / si::second}; - ``` + using namespace mp_units; - === "Header files" + quantity q = delta(42); + ``` - ```cpp - #include + === "Header files" - using namespace mp_units; + ```cpp + #include - quantity q{42, si::metre / si::second}; - ``` + using namespace mp_units; + + quantity q = delta(42); + ``` + + 2. A two-parameter constructor: + + === "C++ modules" + + ```cpp + import mp_units; + + using namespace mp_units; + + quantity q{42, si::metre / si::second}; + ``` + + === "Header files" + + ```cpp + #include + + using namespace mp_units; + + quantity q{42, si::metre / si::second}; + ``` The above creates an instance of `quantity>{}, int>`. The same can be obtained using optional unit symbols: @@ -238,7 +261,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; + quantity_point temp = absolute(20.); std::println("Temperature: {} ({})", temp.quantity_from_zero(), temp.in(deg_F).quantity_from_zero()); @@ -259,7 +282,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; + quantity_point temp = absolute(20.); 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 530cb7a5..4d2f9850 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); + constexpr auto room_reference_temperature = ice_point + delta(21); ``` diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index 9e71aaae..671585f6 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -68,51 +68,17 @@ difference between two things: - the difference in _speed_ (even if relative to zero). As we already know, a `quantity` type provides all operations required for a _displacement vector_ -abstraction in an affine space. +abstraction in the affine space. It can be constructed with: -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); - quantity q6(42, delta); - quantity q7(42, delta); - quantity q8(42, delta); - ``` - -- 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; - quantity q6 = 42 * delta; - quantity q7 = 42 * delta; - quantity q8 = 42 * delta; - ``` +- the multiply syntax (works for most of the units), +- `delta` construction helper (e.g., `delta(42)`, `delta(3)`), +- two-parameter constructor taking a number and a quantity reference/unit. !!! 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: + The multiply syntax support is disabled for units that provide a point origin in their + definition (i.e., units of temperature like `K`, `deg_C`, and `deg_F`). - ```cpp - 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` @@ -152,17 +118,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: +Quantity points with default point origins may be constructed with the `absolute` construction +helper or forcing an explicit conversion from the `quantity`: ```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; -quantity_point qp5 = 42 * absolute; -quantity_point qp6 = 42 * absolute; +// quantity_point qp1 = 42 * m; // Compile-time error +// quantity_point qp2 = 42 * K; // Compile-time error +// quantity_point qp3 = delta(42); // Compile-time error +quantity_point qp4(42 * m); +quantity_point qp5(42 * K); +quantity_point qp6(delta(42)); +quantity_point qp7 = absolute(42); +quantity_point qp8 = absolute(42); +quantity_point qp9 = absolute(42); ``` !!! tip @@ -180,8 +148,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; -quantity_point qp2 = 120 * absolute; +quantity_point qp1(100 * m); +quantity_point qp2 = absolute(120); assert(qp1.quantity_from_zero() == 100 * m); assert(qp2.quantity_from_zero() == 120 * m); @@ -210,7 +178,7 @@ compatible: ```cpp quantity_point qp1{isq::distance(100 * m)}; -quantity_point qp2{isq::height(120 * m)}; +quantity_point qp2 = absolute(120); assert(qp2.quantity_from(qp1) == 20 * m); assert(qp1.quantity_from(qp2) == -20 * m); @@ -230,8 +198,8 @@ origin. ```cpp inline constexpr struct origin final : absolute_point_origin {} origin; -// quantity_point qp1{100 * m}; // Compile-time error -// quantity_point qp2 = 120 * absolute; // Compile-time error +// quantity_point qp1{100 * m}; // Compile-time error +// quantity_point qp2{delta(120)}; // Compile-time error quantity_point qp1 = origin + 100 * m; quantity_point qp2 = 120 * m + origin; @@ -443,7 +411,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)}> {} ice_point; inline constexpr auto zeroth_degree_Celsius = ice_point; } @@ -451,7 +419,7 @@ inline constexpr auto zeroth_degree_Celsius = ice_point; namespace usc { inline constexpr struct zeroth_degree_Fahrenheit final : - relative_point_origin<-32 * absolute * si::degree_Celsius>> {} zeroth_degree_Fahrenheit; + relative_point_origin * si::degree_Celsius>(-32)> {} zeroth_degree_Fahrenheit; } ``` @@ -500,28 +468,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; - quantity_point q2 = {20.5 * delta, si::zeroth_degree_Celsius}; - quantity_point q3{20.5 * delta}; - quantity_point q4 = 20.5 * absolute; + quantity_point q1 = si::zeroth_degree_Celsius + delta(20.5); + quantity_point q2 = {delta(20.5), si::zeroth_degree_Celsius}; + quantity_point q3{delta(20.5)}; + quantity_point q4 = absolute(20.5); ``` - specify a unit and use its zeroth point origin implicitly: ```cpp - 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; + quantity_point q5 = si::zeroth_degree_Celsius + delta(20.5); + quantity_point q6 = {delta(20.5), si::zeroth_degree_Celsius}; + quantity_point q7{delta(20.5)}; + quantity_point q8 = absolute(20.5); ``` - benefit from CTAD: ```cpp - 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; + quantity_point q9 = si::zeroth_degree_Celsius + delta(20.5); + quantity_point q10 = {delta(20.5), si::zeroth_degree_Celsius}; + quantity_point q11{delta(20.5)}; + quantity_point q12 = absolute(20.5); ``` In all of the above cases, we end up with the `quantity_point` of the same type and value. @@ -532,10 +500,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> {} room_reference_temp; +constexpr struct room_reference_temp final : relative_point_origin(21)> {} room_reference_temp; using room_temp = quantity_point; -constexpr auto step_delta = isq::Celsius_temperature(0.5 * delta); +constexpr auto step_delta = delta>(0.5); 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 82a337ce..a5c29d8e 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(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 process_noise_variance = delta(deg_C)>(0.0001); + const estimate initial{state{qp{delta(60.)}}, delta(100.)}; + const std::array measurements = {qp{delta(49.986)}, qp{delta(49.963)}, qp{delta(50.097)}, + qp{delta(50.001)}, qp{delta(50.018)}, qp{delta(50.05)}, + qp{delta(49.938)}, qp{delta(49.858)}, qp{delta(49.965)}, + qp{delta(50.114)}}; + const quantity measurement_error = delta(0.1); 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 7fe1a9ac..23ad51d4 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(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 process_noise_variance = delta(deg_C)>(0.0001); + const estimate initial{state{qp{delta(10.)}}, delta(100.)}; + const std::array measurements = {qp{delta(50.486)}, qp{delta(50.963)}, qp{delta(51.597)}, + qp{delta(52.001)}, qp{delta(52.518)}, qp{delta(53.05)}, + qp{delta(53.438)}, qp{delta(53.858)}, qp{delta(54.465)}, + qp{delta(55.114)}}; + const quantity measurement_error = delta(0.1); 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 158f54a9..adfc56e2 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(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 process_noise_variance = delta(deg_C)>(0.15); + const estimate initial{state{qp{delta(10.)}}, delta(100.)}; + const std::array measurements = {qp{delta(50.486)}, qp{delta(50.963)}, qp{delta(51.597)}, + qp{delta(52.001)}, qp{delta(52.518)}, qp{delta(53.05)}, + qp{delta(53.438)}, qp{delta(53.858)}, qp{delta(54.465)}, + qp{delta(55.114)}}; + const quantity measurement_error = delta(0.1); 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 068ed14d..e8fa0cfb 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); + const auto q4 = delta(1.); 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/CMakeLists.txt b/src/core/CMakeLists.txt index e49a1203..ddcdf989 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -50,6 +50,7 @@ add_mp_units_module( include/mp-units/ext/type_name.h include/mp-units/ext/type_traits.h include/mp-units/framework/compare.h + include/mp-units/framework/construction_helpers.h include/mp-units/framework/customization_points.h include/mp-units/framework/dimension.h include/mp-units/framework/dimension_concepts.h diff --git a/src/core/include/mp-units/bits/sudo_cast.h b/src/core/include/mp-units/bits/sudo_cast.h index f4267d28..fd7a9973 100644 --- a/src/core/include/mp-units/bits/sudo_cast.h +++ b/src/core/include/mp-units/bits/sudo_cast.h @@ -97,10 +97,8 @@ 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_), - make_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 + 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 +106,13 @@ template // this results in great assembly auto res = static_cast( static_cast(q.numerical_value_is_an_implementation_detail_) * traits::ratio); - return {res, make_delta(To::reference)}; + return {res, 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, make_delta(To::reference)}; + return {res, To::reference}; } } } diff --git a/src/core/include/mp-units/framework.h b/src/core/include/mp-units/framework.h index 7a61d351..b20b322a 100644 --- a/src/core/include/mp-units/framework.h +++ b/src/core/include/mp-units/framework.h @@ -24,6 +24,7 @@ // IWYU pragma: begin_exports #include +#include #include #include #include diff --git a/src/core/include/mp-units/framework/construction_helpers.h b/src/core/include/mp-units/framework/construction_helpers.h new file mode 100644 index 00000000..48d1be05 --- /dev/null +++ b/src/core/include/mp-units/framework/construction_helpers.h @@ -0,0 +1,67 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include +#include + +#ifndef MP_UNITS_IN_MODULE_INTERFACE +#include +#endif + +namespace mp_units { + +template +struct delta_ { + template + requires RepresentationOf, get_quantity_spec(R{}).character> + [[nodiscard]] constexpr quantity> operator()(Rep&& lhs) const + { + return quantity{std::forward(lhs), R{}}; + } +}; + +template +struct absolute_ { + template + requires RepresentationOf, get_quantity_spec(R{}).character> + [[nodiscard]] constexpr quantity_point> operator()( + Rep&& lhs) const + { + return quantity_point{quantity{std::forward(lhs), R{}}}; + } +}; + +MP_UNITS_EXPORT_BEGIN + +template +inline constexpr delta_ delta{}; + +template +inline constexpr absolute_ absolute{}; + +MP_UNITS_EXPORT_END + +} // namespace mp_units diff --git a/src/core/include/mp-units/framework/quantity.h b/src/core/include/mp-units/framework/quantity.h index ffc38076..69949723 100644 --- a/src/core/include/mp-units/framework/quantity.h +++ b/src/core/include/mp-units/framework/quantity.h @@ -96,13 +96,8 @@ template using common_quantity_for = quantity>; -template -concept SameOriginalReferenceAs = - DeltaReference && Reference && - detail::SameReference; - template -concept SameValueAs = detail::SameOriginalReferenceAs && std::same_as; +concept SameValueAs = detail::SameReference && std::same_as; } // namespace detail @@ -133,25 +128,25 @@ public: [[nodiscard]] static constexpr quantity zero() noexcept requires requires { quantity_values::zero(); } { - return {quantity_values::zero(), detail::make_delta(R)}; + return {quantity_values::zero(), R}; } [[nodiscard]] static constexpr quantity one() noexcept requires requires { quantity_values::one(); } { - return {quantity_values::one(), detail::make_delta(R)}; + return {quantity_values::one(), R}; } [[nodiscard]] static constexpr quantity min() noexcept requires requires { quantity_values::min(); } { - return {quantity_values::min(), detail::make_delta(R)}; + return {quantity_values::min(), R}; } [[nodiscard]] static constexpr quantity max() noexcept requires requires { quantity_values::max(); } { - return {quantity_values::max(), detail::make_delta(R)}; + return {quantity_values::max(), R}; } // construction, assignment, destruction @@ -160,7 +155,7 @@ 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)) { @@ -173,24 +168,6 @@ public: { } - template - requires(!Reference) && (!detail::SameValueAs, Rep>) && - detail::QuantityConvertibleTo< - quantity>, quantity> - constexpr quantity(Value&& v, R2) : - quantity( - quantity>{std::forward(v), R2{}}) - { - } - - template - requires(!DeltaReference) - constexpr quantity(Value&&, R2) - { - static_assert(DeltaReference, - "References using offset units (e.g., temperatures) must be explicitly qualified with `delta`"); - } - template Q> // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) constexpr explicit(!std::convertible_to) quantity(const Q& q) : @@ -206,8 +183,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, - detail::make_delta(quantity_like_traits::reference)}) + quantity( + ::mp_units::quantity{quantity_like_traits::to_numerical_value(q).value, quantity_like_traits::reference}) { } @@ -306,7 +283,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, detail::make_delta(reference)}; + return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, reference}; } [[nodiscard]] constexpr QuantityOf auto operator-() const @@ -316,7 +293,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, detail::make_delta(reference)}; + return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference}; } template @@ -338,7 +315,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, detail::make_delta(reference)}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference}; } template @@ -360,7 +337,7 @@ public: } -> std::common_with; } { - return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, detail::make_delta(reference)}; + return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, reference}; } // compound assignment operators @@ -463,16 +440,6 @@ template requires RepresentationOf quantity(Value v, R) -> quantity; -template - requires(!Reference) && - RepresentationOf -quantity(Value v, R) -> quantity; - -// the below is needed only to fire static_asserts in the constructor -template - requires(!DeltaReference) && RepresentationOf -quantity(Value v, R) -> quantity; - template explicit( is_specialization_of::to_numerical_value(std::declval())), convert_explicitly>) @@ -487,7 +454,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), - detail::make_delta(ret::reference)}; + ret::reference}; } template @@ -498,7 +465,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), - detail::make_delta(ret::reference)}; + ret::reference}; } template @@ -511,15 +478,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), - detail::make_delta(ret::reference)}; + 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)), - detail::make_delta(R1 * R2)}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), R1 * R2}; } template @@ -527,7 +493,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, detail::make_delta(R)}; + return quantity{q.numerical_value_ref_in(get_unit(R)) * v, R}; } template @@ -535,7 +501,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)), detail::make_delta(R)}; + return quantity{v * q.numerical_value_ref_in(get_unit(R)), R}; } template @@ -543,8 +509,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)), - detail::make_delta(R1 / R2)}; + return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2}; } template @@ -553,7 +518,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, detail::make_delta(R)}; + return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R}; } template @@ -562,7 +527,7 @@ template [[nodiscard]] constexpr QuantityOf auto operator/(const Value& v, const quantity& q) { - return quantity{v / q.numerical_value_ref_in(get_unit(R)), detail::make_delta(::mp_units::one / R)}; + return quantity{v / q.numerical_value_ref_in(get_unit(R)), ::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 6599df67..fca664b7 100644 --- a/src/core/include/mp-units/framework/quantity_cast.h +++ b/src/core/include/mp-units/framework/quantity_cast.h @@ -58,7 +58,7 @@ template [[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_delta(make_reference(ToQS, std::remove_reference_t::unit))}; + 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 bc6f9b12..88920fce 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 { [[nodiscard]] constexpr Quantity auto operator()(this Self self, Q&& q) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_delta(detail::make_reference(self, std::remove_cvref_t::unit))}; + 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_delta(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; + 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_delta(detail::make_reference(Self{}, std::remove_cvref_t::unit))}; + 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 71b4e574..9fe0599e 100644 --- a/src/core/include/mp-units/framework/reference.h +++ b/src/core/include/mp-units/framework/reference.h @@ -41,16 +41,6 @@ namespace detail { template using reference_t = reference; -template - requires DeltaReference || AbsoluteReference -[[nodiscard]] consteval Reference auto remove_reference_specifier(R r) -{ - if constexpr (requires { R::_original_reference_; }) - return R::_original_reference_; - else - return r; -} - } // namespace detail MP_UNITS_EXPORT_BEGIN @@ -184,62 +174,40 @@ struct reference { }; -template - requires RepresentationOf, - get_quantity_spec(detail::remove_reference_specifier(R{})).character> -[[nodiscard]] constexpr quantity> operator*(Rep&& lhs, - R) +template + requires(!detail::OffsetUnit) && + RepresentationOf, get_quantity_spec(R{}).character> +[[nodiscard]] constexpr quantity> operator*(Rep&& lhs, R) { return quantity{std::forward(lhs), R{}}; } -template - requires RepresentationOf, - get_quantity_spec(detail::remove_reference_specifier(R{})).character> -[[nodiscard]] constexpr quantity> operator/( - Rep&& lhs, R) +template + requires(!detail::OffsetUnit) && + RepresentationOf, get_quantity_spec(R{}).character> +[[nodiscard]] constexpr quantity> operator/(Rep&& lhs, R) { - return quantity{std::forward(lhs), detail::make_delta(inverse(detail::remove_reference_specifier(R{})))}; -} - -template - requires RepresentationOf, - get_quantity_spec(detail::remove_reference_specifier(R{})).character> -[[nodiscard]] constexpr quantity_point> -operator*(Rep&& lhs, R) -{ - return quantity_point{std::forward(lhs) * detail::make_delta(detail::remove_reference_specifier(R{}))}; -} - -template - requires RepresentationOf, - get_quantity_spec(detail::remove_reference_specifier(R{})).character> -[[nodiscard]] constexpr quantity_point> -operator/(Rep&& lhs, R) -{ - return quantity_point{std::forward(lhs) * detail::make_delta(inverse(detail::remove_reference_specifier(R{})))}; + return quantity{std::forward(lhs), inverse(R{})}; } template - requires(!DeltaReference) && RepresentationOf, get_quantity_spec(R{}).character> + requires detail::OffsetUnit && + RepresentationOf, get_quantity_spec(R{}).character> [[noreturn]] constexpr auto operator*(Rep&&, R) { - static_assert( - DeltaReference, - "References using offset units (e.g., temperatures) must be explicitly qualified with `delta` or `absolute`"); + static_assert(!detail::OffsetUnit, + "References using offset units (e.g., temperatures) may be constructed only with the `delta` or " + "`absolute` helpers"); } template - requires(!DeltaReference) && RepresentationOf, get_quantity_spec(R{}).character> + requires detail::OffsetUnit && + RepresentationOf, get_quantity_spec(R{}).character> [[noreturn]] constexpr auto operator/(Rep&&, R) { - static_assert( - DeltaReference, - "References using offset units (e.g., temperatures) must be explicitly qualified with `delta` or `absolute`"); + static_assert(!detail::OffsetUnit, + "References using offset units (e.g., temperatures) may be constructed only with the `delta` or " + "`absolute` helpers"); } template @@ -267,7 +235,7 @@ template [[nodiscard]] constexpr Quantity auto operator*(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_delta(std::remove_cvref_t::reference * R{})}; + std::remove_cvref_t::reference * R{}}; } template @@ -275,7 +243,7 @@ template [[nodiscard]] constexpr Quantity auto operator/(Q&& q, R) { return quantity{std::forward(q).numerical_value_is_an_implementation_detail_, - detail::make_delta(std::remove_cvref_t::reference / R{})}; + 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 c0facb57..826dfb44 100644 --- a/src/core/include/mp-units/framework/reference_concepts.h +++ b/src/core/include/mp-units/framework/reference_concepts.h @@ -80,44 +80,8 @@ concept ReferenceOf = Reference && QuantitySpecOf -struct delta_ final { - static constexpr Reference auto _original_reference_ = R{}; -}; - -template -struct absolute_ final { - static constexpr Reference auto _original_reference_ = R{}; -}; - -MP_UNITS_EXPORT_BEGIN - -template -inline constexpr delta_ delta{}; - -template -inline constexpr absolute_ absolute{}; - -template -concept DeltaReference = (Reference && !requires { get_unit(T{}).point_origin; }) || is_specialization_of; - -template -concept AbsoluteReference = is_specialization_of; - -MP_UNITS_EXPORT_END - namespace detail { -template -[[nodiscard]] consteval DeltaReference auto make_delta(R r) -{ - if constexpr (requires { get_unit(R{}).point_origin; }) - return delta; - else - return r; -} - template concept SameReference = Reference && Reference && (R1 == R2); diff --git a/src/core/include/mp-units/framework/unit_concepts.h b/src/core/include/mp-units/framework/unit_concepts.h index 2d838351..3a271e90 100644 --- a/src/core/include/mp-units/framework/unit_concepts.h +++ b/src/core/include/mp-units/framework/unit_concepts.h @@ -210,4 +210,11 @@ concept UnitCompatibleWith = Unit && Unit && QuantitySpec && (!AssociatedUnit || UnitOf)&&detail::UnitConvertibleTo; +namespace detail { + +template +concept OffsetUnit = Unit && requires { T::point_origin; }; + +} + } // namespace mp_units diff --git a/src/core/include/mp-units/math.h b/src/core/include/mp-units/math.h index a144f2b4..50dd222a 100644 --- a/src/core/include/mp-units/math.h +++ b/src/core/include/mp-units/math.h @@ -114,8 +114,8 @@ template auto R, typename Rep> [[nodiscard]] constexpr quantity exp(const quantity& q) { using std::exp; - return value_cast(quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), - detail::make_delta(detail::clone_reference_with(R))}); + return value_cast( + quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), 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)), - detail::make_delta(common_reference(R * S, T))}; + 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)), detail::make_delta(ref)}; + return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), 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)), detail::make_delta(ref)}; + return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; } @@ -338,8 +338,8 @@ template if constexpr (To == get_unit(R)) { 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::make_delta(detail::clone_reference_with(R))}); + return handle_signed_results( + quantity{static_cast(floor(q.force_numerical_value_in(To))), detail::clone_reference_with(R)}); } } else { if constexpr (To == get_unit(R)) { @@ -375,8 +375,8 @@ template if constexpr (To == get_unit(R)) { 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::make_delta(detail::clone_reference_with(R))}); + return handle_signed_results( + quantity{static_cast(ceil(q.force_numerical_value_in(To))), 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)), detail::make_delta(ref)}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; } /** @@ -474,8 +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)), - detail::make_delta(ref)}; + return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), 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 cb5371a6..8bb41b86 100644 --- a/src/systems/include/mp-units/systems/si/units.h +++ b/src/systems/include/mp-units/systems/si/units.h @@ -27,6 +27,7 @@ #include #ifndef MP_UNITS_IN_MODULE_INTERFACE +#include #include #include #endif @@ -77,7 +78,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>> {} ice_point; +inline constexpr struct ice_point final : relative_point_origin>(273'150)> {} 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 6192d63b..49537f74 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 * si::degree_Celsius>> {} zeroth_degree_Fahrenheit; +inline constexpr struct zeroth_degree_Fahrenheit final : relative_point_origin * si::degree_Celsius>(-32)> {} 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 aa91ab8e..55ce3d2b 100644 --- a/test/static/quantity_point_test.cpp +++ b/test/static/quantity_point_test.cpp @@ -801,12 +801,11 @@ static_assert( ////////////////////////////////// static_assert(quantity_point{42 * 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}.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(quantity_point{delta(20)}.quantity_from_zero() == delta(20)); +static_assert(quantity_point{delta(20.)}.in(deg_F).quantity_from_zero() == delta(68)); +static_assert(absolute(20).quantity_from_zero() == delta(20)); +static_assert(absolute(20.).in(deg_F).quantity_from_zero() == delta(68)); 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 +891,13 @@ 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)>, +static_assert(std::is_same_v(20)})::rep, int>); +static_assert( + std::is_same_v(20)}.point_origin)>, struct si::ice_point>); +static_assert(std::is_same_v(20)}.absolute_point_origin)>, struct si::absolute_zero>); -static_assert((20 * absolute).unit == si::degree_Celsius); -static_assert((20 * absolute).quantity_spec == kind_of); +static_assert(quantity_point{delta(20)}.unit == si::degree_Celsius); +static_assert(quantity_point{delta(20)}.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 a91f5a10..10273d5b 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) == - isq::thermodynamic_temperature(5 * delta)); +static_assert(delta(9) == + delta(5)); } // namespace