feat: quantity_spec conversions improved

This commit is contained in:
Mateusz Pusz
2024-12-28 14:02:03 +01:00
parent b685521a18
commit 06cbfae3b3
26 changed files with 1013 additions and 1147 deletions

View File

@ -52,24 +52,6 @@ All of the above quantity specifications have to be marked as `final`.
`QuantitySpecOf` concept is satisfied when both arguments satisfy a [`QuantitySpec`](#QuantitySpec) concept
and when `T` is implicitly convertible to `V`.
??? info "More details"
Additionally:
- `T` should not be a [nested quantity specification of `V`](dimensionless_quantities.md/#nested-quantity-kinds)
- either `T` is quantity kind or `V` should not be a
[nested quantity specification of `T`](dimensionless_quantities.md/#nested-quantity-kinds)
Those additional conditions are required to make the following work:
```cpp
static_assert(ReferenceOf<si::radian, isq::angular_measure>);
static_assert(!ReferenceOf<si::radian, dimensionless>);
static_assert(!ReferenceOf<isq::angular_measure[si::radian], dimensionless>);
static_assert(ReferenceOf<one, isq::angular_measure>);
static_assert(!ReferenceOf<dimensionless[one], isq::angular_measure>);
```
## `Unit<T>` { #Unit }
@ -123,17 +105,8 @@ Such units can be passed as an argument to a `prefixed_unit` class template.
### `UnitOf<T, V>` { #UnitOf }
`UnitOf` concept is satisfied for all units `T` matching an [`AssociatedUnit`](#AssociatedUnit)
concept with an associated quantity type implicitly convertible to `V`.
??? info "More details"
Additionally, the kind of `V` and the kind of quantity type associated with `T` must be the same,
or the quantity type associated with `T` may not be derived from the kind of `V`.
This condition is required to make `dimensionless[si::radian]` invalid as `si::radian` should
be only used for `isq::angular_measure`, which is a
[nested quantity kind within the dimensionless quantities tree](dimensionless_quantities.md/#nested-quantity-kinds).
`UnitOf` concept is satisfied for all units `T` for which an associated quantity spec is implicitly
convertible to the provided [`QuantitySpec`](#QuantitySpec) value.
## `Reference<T>` { #Reference }
@ -150,7 +123,7 @@ A `Reference` can either be:
### `ReferenceOf<T, V>` { #ReferenceOf }
`ReferenceOf` concept is satisfied by references `T` which have a quantity specification that satisfies
[`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
[`QuantitySpecOf<V>`](#QuantitySpecOf) concept.
## `Representation<T>` { #Representation }
@ -205,7 +178,7 @@ satisfied by all types being or deriving from an instantiation of a `quantity` c
### `QuantityOf<T, V>` { #QuantityOf }
`QuantityOf` concept is satisfied by all the quantities for which a [`QuantitySpecOf<V>`](#QuantitySpecOf)
`QuantityOf` concept is satisfied by all the quantities for which a [`ReferenceOf<V>`](#ReferenceOf)
is `true`.
@ -252,10 +225,10 @@ class template.
`QuantityPointOf` concept is satisfied by all the quantity points `T` that match the following value `V`:
| `V` | Condition |
|----------------|-----------------------------------------------------------------------------------------------------|
| `QuantitySpec` | The quantity point quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
| `V` | Condition |
|----------------|-----------------------------------------------------------------------------------------------|
| `QuantitySpec` | The quantity point quantity specification satisfies [`ReferenceOf<V>`](#ReferenceOf) concept. |
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
## `QuantityLike<T>` { #QuantityLike }

View File

@ -311,3 +311,24 @@ inline constexpr struct bit final : named_unit<"bit", one, kind_of<storage_capac
```
but still allow the usage of `one` and its scaled versions for such quantities.
!!! info
It is worth mentioning here that converting up the hierarchy beyond a subkind requires an
explicit conversion. For example:
```cpp
static_assert(implicitly_convertible(isq::rotation, dimensionless));
static_assert(!implicitly_convertible(isq::angular_measure, dimensionless));
static_assert(explicitly_convertible(isq::angular_measure, dimensionless));
```
This increases type safety and prevents accidental quantities with invalid units. For example,
a result of a conversion from `isq::angular_measure[rad]` to `dimensionless` would be
a reference of `dimensionless[rad]`, which contains an incorrect unit for a `dimensionless`
quantity. Such a conversion must be explicit and be preceded by an explicit unit conversion:
```cpp
quantity q1 = isq::angular_measure(42. * rad);
quantity<dimensionless[one]> q2 = dimensionless(q1.in(one));
```