Merge pull request #585 from mpusz/reference_modifiers

Reference specifiers
This commit is contained in:
Mateusz Pusz
2024-06-21 04:18:56 +09:00
committed by GitHub
19 changed files with 245 additions and 108 deletions

View File

@ -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());

View File

@ -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>);
```

View File

@ -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<delta<si::degree_Celsius>> temp); // ill-formed
quantity<N * m / (delta<deg_C> * mol)> 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<QuantitySpec>` 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<isq::distance[si::metre]> qp1{100 * m};
quantity_point<isq::distance[si::metre]> qp2{120 * m};
quantity_point<isq::distance[si::metre]> qp1 = 100 * absolute<m>;
quantity_point<isq::distance[si::metre]> 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<isq::distance> {} origin;
// quantity_point<si::metre, origin> qp1{100 * m}; // Compile-time error
// quantity_point<si::metre, origin> qp2{120 * m}; // Compile-time error
// quantity_point<si::metre, origin> qp1{100 * m}; // Compile-time error
// quantity_point<si::metre, origin> qp2 = 120 * absolute<m>; // Compile-time error
quantity_point<si::metre, origin> qp1 = origin + 100 * m;
quantity_point<si::metre, origin> qp2 = 120 * m + origin;
@ -387,7 +443,7 @@ namespace si {
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr auto zeroth_kelvin = absolute_zero;
inline constexpr struct ice_point final : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr struct ice_point final : relative_point_origin<273'150 * absolute<milli<kelvin>>>> {} 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<quantity_point{-32 * (mag_ratio<5, 9> * 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<si::degree_Celsius, si::zeroth_degree_Celsius> q1 = si::zeroth_degree_Celsius + 20.5 * deg_C;
quantity_point<si::degree_Celsius, si::zeroth_degree_Celsius> q2 = {20.5 * deg_C, si::zeroth_degree_Celsius};
quantity_point<si::degree_Celsius, si::zeroth_degree_Celsius> q3{20.5 * deg_C};
quantity_point<si::degree_Celsius, si::zeroth_degree_Celsius> q1 = si::zeroth_degree_Celsius + 20.5 * delta<deg_C>;
quantity_point<si::degree_Celsius, si::zeroth_degree_Celsius> q2 = {20.5 * delta<deg_C>, si::zeroth_degree_Celsius};
quantity_point<si::degree_Celsius, si::zeroth_degree_Celsius> q3{20.5 * delta<deg_C>};
quantity_point<si::degree_Celsius, si::zeroth_degree_Celsius> q4 = 20.5 * absolute<deg_C>;
```
- specify a unit and use its zeroth point origin implicitly:
```cpp
quantity_point<si::degree_Celsius> q4 = si::zeroth_degree_Celsius + 20.5 * deg_C;
quantity_point<si::degree_Celsius> q5 = {20.5 * deg_C, si::zeroth_degree_Celsius};
quantity_point<si::degree_Celsius> q6{20.5 * deg_C};
quantity_point<si::degree_Celsius> q5 = si::zeroth_degree_Celsius + 20.5 * delta<deg_C>;
quantity_point<si::degree_Celsius> q6 = {20.5 * delta<deg_C>, si::zeroth_degree_Celsius};
quantity_point<si::degree_Celsius> q7{20.5 * delta<deg_C>};
quantity_point<si::degree_Celsius> 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<quantity_point{21 * deg_C}> {} room_reference_temp;
constexpr struct room_reference_temp final : relative_point_origin<21 * absolute<deg_C>> {} room_reference_temp;
using room_temp = quantity_point<isq::Celsius_temperature[deg_C], room_reference_temp>;
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{};