From b8002d1940d83091abf6dfa5ad1940e305244b55 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Thu, 3 Aug 2023 13:08:09 +0200 Subject: [PATCH] docs: "The Affine Space" chapter updated to reflect the latest changes --- .../framework_basics/the_affine_space.md | 105 +++++++++++++----- 1 file changed, 75 insertions(+), 30 deletions(-) diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index 1d5a70ec..085227d1 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -79,8 +79,8 @@ the **mp-units** library, a `quantity_point` gets a `quantity` in its constructo - can be obtained with the `relative()` member function. ```cpp -constexpr quantity_point everest_base_camp{5364 * m}; -static_assert(everest_base_camp.relative() == 5364 * m); +constexpr quantity_point everest_base_camp_alt{5364 * m}; +static_assert(everest_base_camp_alt.relative() == 5364 * m); ``` !!! note @@ -89,7 +89,7 @@ static_assert(everest_base_camp.relative() == 5364 * m); direct initialization. This is why the code below that uses copy initialization does not compile: ```cpp - quantity_point everest_base_camp = 5364 * m; // ERROR + quantity_point everest_base_camp_alt = 5364 * m; // ERROR ``` In the **mp-units** library, the origin is either provided implicitly (as above) or can be predefined @@ -98,22 +98,56 @@ by the user and then provided explicitly as the `quantity_point` class template ```cpp constexpr struct mean_sea_level : absolute_point_origin {} mean_sea_level; -constexpr quantity_point everest_base_camp{5364 * m}; -static_assert(everest_base_camp.relative() == 5364 * m); +constexpr quantity_point everest_base_camp_alt{5364 * m}; +static_assert(everest_base_camp_alt.relative() == 5364 * m); ``` +!!! note -### Stacking _point_ origins + The `mean_sea_level` and the default `absolute_point_origin` origins are distinct from + each other, which means that _points_ defined with them are not compatible (can't be subtracted or + compared). -We often do not have one ultimate "zero" point when we measure things. + +### Class Template Argument Deduction (CTAD) + +Typing the entire `quantity_point` type may sometimes be quite verbose. Also, please note that we +"accidentally" used `double` as a representation type in the above examples, even though we operated +only on integral values. This was done for the convenience of saving typing. + +To improve the developer's experience, the `quantity_point` class template comes with the user-defined +class template argument deduction guides. Thanks to them, the above definitions can be rewritten as +follows: + +- implicit default origin + + ```cpp + constexpr quantity_point everest_base_camp_alt{isq::altitude(5364 * m)}; + ``` + +- explicit origin + + ```cpp + constexpr quantity_point everest_base_camp_alt{isq::altitude(5364 * m), mean_sea_level}; + ``` + + +### Relative _point_ origins + +We often do not have only one ultimate "zero" point when we measure things. Continuing the Mount Everest trip example above, measuring all daily hikes from the `mean_sea_level` might not be efficient. Maybe we know that we are not good climbers, so all our climbs can be represented with an 8-bit integer type which will allow us to save memory in our database of climbs? -Why not use `everest_base_camp` as our reference point? +Why not use `everest_base_camp_alt` as our reference point? -It turns out that in the **mp-units** library, you can use a predefined at compile-time `quantity_point` -as an origin as well: +For this purpose, we can define a `relative_point_origin` in the following way: + +```cpp +constexpr struct everest_base_camp : relative_point_origin {} everest_base_camp; +``` + +The above can be used as an origin for subsequent _points_: ```cpp constexpr quantity_point first_climb_alt{42 * m}; @@ -127,13 +161,7 @@ we can either: - add the two relative heights from both points ```cpp - static_assert(first_climb_alt.relative() + everest_base_camp.relative() == 5406 * m); - ``` - -- do the same but in a slightly different way: - - ```cpp - static_assert(first_climb_alt.relative() + first_climb_alt.point_origin.relative() == 5406 * m); + static_assert(first_climb_alt.relative() + everest_base_camp_alt.relative() == 5406 * m); ``` - call `absolute()` member function @@ -143,6 +171,27 @@ we can either: ``` +### Converting between different representations of the same _point_ + +As we might represent the same _point_ with _vectors_ from various origins, the **mp-units** library +provides facilities to convert the _point_ to the `quantity_point` class templates expressed in terms +of different origins. + +For this purpose, we can either use: + +- a converting constructor: + + ```cpp + static_assert(quantity_point{first_climb_alt}.relative() == 5406 * m); + ``` + +- a dedicated conversion interface: + + ```cpp + constexpr QuantityPoint auto qp = first_climb_alt.point_from(mean_sea_level); + static_assert(qp.relative() == 5406 * m); + ``` + ### _Point_ arithmetics Let's assume we are going to attend the CppCon conference that is hosted in Aurora, CO, and we @@ -178,7 +227,7 @@ quantity taxi2 = cppcon_venue - den_airport; quantity taxi = taxi1 + taxi2; ``` -Now it will print the results: +Now if we will print the results: ```cpp std::cout << "Total distance: " << total << "\n"; @@ -197,28 +246,28 @@ Taxi distance: 31.2544 km ### Temperature support -Another important example of [stacking point origins](#stacking-point-origins) is support +Another important example of [relative point origins](#relative-point-origins) is support of temperature quantity points in units different than kelvin [`K`]. For example, the degree Celsius scale can be implemented as follows: ```cpp -constexpr auto ice_point = quantity_point{273.15 * K}; -using Celsius_point = quantity_point; +constexpr struct ice_point : relative_point_origin{273.15 * K}> {} ice_point; +using Celsius_point = quantity_point; ``` !!! note - While [stacking point origins](#stacking-point-origins) we can use not only different - representation types but also different units for an origin and a _point_. + Notice that while stacking point origins we can use not only different representation types but + also different units for an origin and a _point_. With the above, for example, if we want to implement a room temperature controller, we can type: ```cpp -constexpr Celsius_point room_reference_temperature{21 * deg_C}; -using room_temperature = quantity_point; +constexpr struct room_reference_temperature : relative_point_origin {} room_reference_temperature; +using room_temperature = quantity_point; -constexpr auto step_delta = isq::Celsius_temperature(0.5 * deg_C); +constexpr auto step_delta = isq::thermodynamic_temperature(0.5 * deg_C); constexpr int number_of_steps = 6; room_temperature room_default{}; @@ -261,7 +310,3 @@ The following operations are not allowed in the affine space: The usage of `quantity_point`, and affine space types in general, improves expressiveness and type-safety of the code we write. - - -## Handling temperature points -