Merge branch 'master' into feature/more-value-casts

This commit is contained in:
Mateusz Pusz
2024-06-14 21:44:19 +09:00
committed by GitHub
102 changed files with 1293 additions and 1021 deletions
@@ -97,15 +97,15 @@ enumeration can be appended to the `quantity_spec` describing such a quantity ty
=== "C++23"
```cpp
inline constexpr struct position_vector : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<length, quantity_character::vector> {} displacement;
inline constexpr struct position_vector final : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<length, quantity_character::vector> {} displacement;
```
=== "C++20"
```cpp
inline constexpr struct position_vector : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
inline constexpr struct position_vector final : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
```
=== "Portable"
@@ -126,13 +126,13 @@ character override is needed):
=== "C++23"
```cpp
inline constexpr struct velocity : quantity_spec<speed, position_vector / duration> {} velocity;
inline constexpr struct velocity final : quantity_spec<speed, position_vector / duration> {} velocity;
```
=== "C++20"
```cpp
inline constexpr struct velocity : quantity_spec<velocity, speed, position_vector / duration> {} velocity;
inline constexpr struct velocity final : quantity_spec<velocity, speed, position_vector / duration> {} velocity;
```
=== "Portable"
@@ -16,6 +16,8 @@ or derived [quantity](../../appendix/glossary.md#quantity):
by the library's framework based on the [quantity equation](../../appendix/glossary.md#quantity-equation)
provided in the [quantity specification](../../appendix/glossary.md#quantity_spec).
All of the above dimensions have to be marked as `final`.
### `DimensionOf<T, V>` { #DimensionOf }
@@ -42,6 +44,8 @@ including:
- Intermediate [derived quantity](../../appendix/glossary.md#derived-quantity) specifications being
a result of a [quantity equations](../../appendix/glossary.md#quantity-equation) on other specifications.
All of the above quantity specifications have to be marked as `final`.
### `QuantitySpecOf<T, V>` { #QuantitySpecOf }
@@ -84,6 +88,8 @@ and when `T` is implicitly convertible to `V`.
- [Derived unnamed units](../../appendix/glossary.md#derived-unit) being a result of a
[unit equations](../../appendix/glossary.md#unit-equation) on other units.
All of the above units have to be marked as `final`.
!!! note
In the **mp-units** library, [physical constants are also implemented as units](faster_than_lightspeed_constants.md).
@@ -235,7 +241,7 @@ implicitly convertible from quantity specification `V`, which means that `V` mus
However, if we define `mean_sea_level` in the following way:
```cpp
inline constexpr struct mean_sea_level : absolute_point_origin<isq::altitude> {} mean_sea_level;
inline constexpr struct mean_sea_level final : absolute_point_origin<isq::altitude> {} mean_sea_level;
```
then it can't be used as a point origin for _points_ of `isq::length` or `isq::width` as none of them
@@ -328,7 +334,7 @@ for which an instantiation of `quantity_point_like_traits` type trait yields a v
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
using T = std::chrono::time_point<C, std::chrono::seconds>;
static constexpr auto reference = si::second;
static constexpr struct point_origin : absolute_point_origin<isq::time> {} point_origin{};
static constexpr struct point_origin final : absolute_point_origin<isq::time> {} point_origin{};
using rep = std::chrono::seconds::rep;
[[nodiscard]] static constexpr convert_implicitly<quantity<reference, rep>> to_quantity(const T& qp)
@@ -60,8 +60,8 @@ For example:
the following way:
```cpp
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
```
[Derived dimensions](../../appendix/glossary.md#derived-dimension) are implicitly created
@@ -71,9 +71,9 @@ provided in the [quantity specification](../../appendix/glossary.md#quantity_spe
=== "C++23"
```cpp
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct time : quantity_spec<dim_time> {} time;
inline constexpr struct speed : quantity_spec<length / time> {} speed;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct time final : quantity_spec<dim_time> {} time;
inline constexpr struct speed final : quantity_spec<length / time> {} speed;
static_assert(speed.dimension == dim_length / dim_time);
```
@@ -81,9 +81,9 @@ provided in the [quantity specification](../../appendix/glossary.md#quantity_spe
=== "C++20"
```cpp
inline constexpr struct length : quantity_spec<length, dim_length> {} length;
inline constexpr struct time : quantity_spec<time, dim_time> {} time;
inline constexpr struct speed : quantity_spec<speed, length / time> {} speed;
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct time final : quantity_spec<time, dim_time> {} time;
inline constexpr struct speed final : quantity_spec<speed, length / time> {} speed;
static_assert(speed.dimension == dim_length / dim_time);
```
@@ -183,17 +183,17 @@ Quantity specification can be defined by the user in one of the following ways:
=== "C++23"
```cpp
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct height : quantity_spec<length> {} height;
inline constexpr struct speed : quantity_spec<length / time> {} speed;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct height final : quantity_spec<length> {} height;
inline constexpr struct speed final : quantity_spec<length / time> {} speed;
```
=== "C++20"
```cpp
inline constexpr struct length : quantity_spec<length, dim_length> {} length;
inline constexpr struct height : quantity_spec<height, length> {} height;
inline constexpr struct speed : quantity_spec<speed, length / time> {} speed;
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct height final : quantity_spec<height, length> {} height;
inline constexpr struct speed final : quantity_spec<speed, length / time> {} speed;
```
=== "Portable"
@@ -234,13 +234,13 @@ A unit can be defined by the user in one of the following ways:
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
template<PrefixableUnit auto U> inline constexpr kilo_<decltype(U)> kilo;
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct minute final : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct gram final : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr auto kilogram = kilo<gram>;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct speed_of_light_in_vacuum : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct speed_of_light_in_vacuum final : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
```
The [unit equation](../../appendix/glossary.md#unit-equation) of `si::metre / si::second` results
@@ -346,13 +346,13 @@ For example:
- the absolute point origin can be defined in the following way:
```cpp
inline constexpr struct absolute_zero : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
```
- the relative point origin can be defined in the following way:
```cpp
inline constexpr struct ice_point : relative_point_origin<absolute_zero + 273'150 * milli<kelvin>> {} ice_point;
inline constexpr struct ice_point final : relative_point_origin<absolute_zero + 273'150 * milli<kelvin>> {} ice_point;
```
@@ -113,7 +113,7 @@ that uses a unit that is proportional to the ratio of kilometers per megaparsecs
units of _length_:
```cpp
inline constexpr struct hubble_constant :
inline constexpr struct hubble_constant final :
named_unit<{u8"H₀", "H_0"}, mag_ratio<701, 10> * si::kilo<si::metre> / si::second / si::mega<parsec>> {} hubble_constant;
```
@@ -158,9 +158,9 @@ Besides the unit `one`, there are a few other scaled units predefined in the lib
with dimensionless quantities:
```cpp
inline constexpr struct percent : named_unit<"%", mag_ratio<1, 100> * one> {} percent;
inline constexpr struct per_mille : named_unit<{u8"‰", "%o"}, mag_ratio<1, 1000> * one> {} per_mille;
inline constexpr struct parts_per_million : named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {} parts_per_million;
inline constexpr struct percent final : named_unit<"%", mag_ratio<1, 100> * one> {} percent;
inline constexpr struct per_mille final : named_unit<{u8"‰", "%o"}, mag_ratio<1, 1000> * one> {} per_mille;
inline constexpr struct parts_per_million final : named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {} parts_per_million;
inline constexpr auto ppm = parts_per_million;
```
@@ -217,17 +217,17 @@ to the quantity specification:
=== "C++23"
```cpp
inline constexpr struct angular_measure : quantity_spec<dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure : quantity_spec<dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity : quantity_spec<dimensionless, is_kind> {} storage_capacity;
inline constexpr struct angular_measure final : quantity_spec<dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure final : quantity_spec<dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity final : quantity_spec<dimensionless, is_kind> {} storage_capacity;
```
=== "C++20"
```cpp
inline constexpr struct angular_measure : quantity_spec<angular_measure, dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure : quantity_spec<solid_angular_measure, dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity : quantity_spec<storage_capacity, dimensionless, is_kind> {} storage_capacity;
inline constexpr struct angular_measure final : quantity_spec<angular_measure, dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure final : quantity_spec<solid_angular_measure, dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity final : quantity_spec<storage_capacity, dimensionless, is_kind> {} storage_capacity;
```
=== "Portable"
@@ -242,9 +242,9 @@ With the above, we can constrain `radian`, `steradian`, and `bit` to be allowed
specific quantity kinds only:
```cpp
inline constexpr struct radian : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct bit : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
inline constexpr struct radian final : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian final : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct bit final : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
```
but still allow the usage of `one` and its scaled versions for such quantities.
@@ -39,12 +39,12 @@ namespace si {
namespace si2019 {
inline constexpr struct speed_of_light_in_vacuum :
inline constexpr struct speed_of_light_in_vacuum final :
named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
} // namespace si2019
inline constexpr struct magnetic_constant :
inline constexpr struct magnetic_constant final :
named_unit<{u8"μ₀", "u_0"}, mag<4> * mag_pi * mag_power<10, -7> * henry / metre> {} magnetic_constant;
} // namespace mp_units::si
@@ -6,8 +6,8 @@ The **mp-units** library decided to use a rather unusual pattern to define entit
Here is how we define `metre` and `second` [SI](../../appendix/glossary.md#si) base units:
```cpp
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
```
Please note that the above reuses the same identifier for a type and its value. The rationale
@@ -94,9 +94,9 @@ the value-based [unit equation](../../appendix/glossary.md#unit-equation) to a c
definition:
```cpp
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct pascal : named_unit<"Pa", newton / square(metre)> {} pascal;
inline constexpr struct joule : named_unit<"J", newton * metre> {} joule;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct pascal final : named_unit<"Pa", newton / square(metre)> {} pascal;
inline constexpr struct joule final : named_unit<"J", newton * metre> {} joule;
```
@@ -316,13 +316,13 @@ Let's see another example:
using namespace mp_units;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
: quantity_spec<isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final :
quantity_spec<isq::length> {} horizontal_length;
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
inline constexpr struct horizontal_area final :
quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[square(si::metre)]> base_;
@@ -429,13 +429,13 @@ Let's see another example:
using namespace mp_units;
// add a custom quantity type of kind isq::length
inline constexpr struct horizontal_length
: quantity_spec<isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final :
quantity_spec<isq::length> {} horizontal_length;
// add a custom derived quantity type of kind isq::area
// with a constrained quantity equation
inline constexpr struct horizontal_area
: quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
inline constexpr struct horizontal_area final :
quantity_spec<isq::area, horizontal_length * isq::width> {} horizontal_area;
class StorageTank {
quantity<horizontal_area[square(si::metre)]> base_;
@@ -148,45 +148,45 @@ For example, here is how the above quantity kind tree can be modeled in the libr
=== "C++23"
```cpp
inline constexpr struct length : quantity_spec<dim_length> {} length;
inline constexpr struct width : quantity_spec<length> {} width;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct width final : quantity_spec<length> {} width;
inline constexpr auto breadth = width;
inline constexpr struct height : quantity_spec<length> {} height;
inline constexpr struct height final : quantity_spec<length> {} height;
inline constexpr auto depth = height;
inline constexpr auto altitude = height;
inline constexpr struct thickness : quantity_spec<width> {} thickness;
inline constexpr struct diameter : quantity_spec<width> {} diameter;
inline constexpr struct radius : quantity_spec<width> {} radius;
inline constexpr struct radius_of_curvature : quantity_spec<radius> {} radius_of_curvature;
inline constexpr struct path_length : quantity_spec<length> {} path_length;
inline constexpr struct thickness final : quantity_spec<width> {} thickness;
inline constexpr struct diameter final : quantity_spec<width> {} diameter;
inline constexpr struct radius final : quantity_spec<width> {} radius;
inline constexpr struct radius_of_curvature final : quantity_spec<radius> {} radius_of_curvature;
inline constexpr struct path_length final : quantity_spec<length> {} path_length;
inline constexpr auto arc_length = path_length;
inline constexpr struct distance : quantity_spec<path_length> {} distance;
inline constexpr struct radial_distance : quantity_spec<distance> {} radial_distance;
inline constexpr struct wavelength : quantity_spec<length> {} wavelength;
inline constexpr struct position_vector : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<length, quantity_character::vector> {} displacement;
inline constexpr struct distance final : quantity_spec<path_length> {} distance;
inline constexpr struct radial_distance final : quantity_spec<distance> {} radial_distance;
inline constexpr struct wavelength final : quantity_spec<length> {} wavelength;
inline constexpr struct position_vector final : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<length, quantity_character::vector> {} displacement;
```
=== "C++20"
```cpp
inline constexpr struct length : quantity_spec<length, dim_length> {} length;
inline constexpr struct width : quantity_spec<width, length> {} width;
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct width final : quantity_spec<width, length> {} width;
inline constexpr auto breadth = width;
inline constexpr struct height : quantity_spec<height, length> {} height;
inline constexpr struct height final : quantity_spec<height, length> {} height;
inline constexpr auto depth = height;
inline constexpr auto altitude = height;
inline constexpr struct thickness : quantity_spec<thickness, width> {} thickness;
inline constexpr struct diameter : quantity_spec<diameter, width> {} diameter;
inline constexpr struct radius : quantity_spec<radius, width> {} radius;
inline constexpr struct radius_of_curvature : quantity_spec<radius_of_curvature, radius> {} radius_of_curvature;
inline constexpr struct path_length : quantity_spec<path_length, length> {} path_length;
inline constexpr struct thickness final : quantity_spec<thickness, width> {} thickness;
inline constexpr struct diameter final : quantity_spec<diameter, width> {} diameter;
inline constexpr struct radius final : quantity_spec<radius, width> {} radius;
inline constexpr struct radius_of_curvature final : quantity_spec<radius_of_curvature, radius> {} radius_of_curvature;
inline constexpr struct path_length final : quantity_spec<path_length, length> {} path_length;
inline constexpr auto arc_length = path_length;
inline constexpr struct distance : quantity_spec<distance, path_length> {} distance;
inline constexpr struct radial_distance : quantity_spec<radial_distance, distance> {} radial_distance;
inline constexpr struct wavelength : quantity_spec<wavelength, length> {} wavelength;
inline constexpr struct position_vector : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
inline constexpr struct distance final : quantity_spec<distance, path_length> {} distance;
inline constexpr struct radial_distance final : quantity_spec<radial_distance, distance> {} radial_distance;
inline constexpr struct wavelength final : quantity_spec<wavelength, length> {} wavelength;
inline constexpr struct position_vector final : quantity_spec<position_vector, length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement final : quantity_spec<displacement, length, quantity_character::vector> {} displacement;
```
=== "Portable"
@@ -26,7 +26,7 @@ this is expressed by associating a quantity kind (that we discussed in detail in
previous chapter) with a unit that is used to express it:
```cpp
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
```
!!! important
@@ -67,7 +67,7 @@ of a specific predefined [unit equation](../../appendix/glossary.md#unit-equatio
For example, a unit of _power_ quantity is defined in the library as:
```cpp
inline constexpr struct watt : named_unit<"W", joule / second> {} watt;
inline constexpr struct watt final : named_unit<"W", joule / second> {} watt;
```
However, a _power_ quantity can be expressed in other units as well. For example,
@@ -110,8 +110,8 @@ The library allows constraining such units to work only with quantities of a spe
the following way:
```cpp
inline constexpr struct hertz : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
inline constexpr struct becquerel : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
inline constexpr struct hertz final : named_unit<"Hz", one / second, kind_of<isq::frequency>> {} hertz;
inline constexpr struct becquerel final : named_unit<"Bq", one / second, kind_of<isq::activity>> {} becquerel;
```
With the above, `hertz` can only be used with _frequencies_, while `becquerel` should only be used with
@@ -168,25 +168,25 @@ be explicitly expressed with predefined SI prefixes. Those include units like mi
electronvolt:
```cpp
inline constexpr struct minute : named_unit<"min", mag<60> * si::second> {} minute;
inline constexpr struct hour : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct electronvolt : named_unit<"eV", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * si::joule> {} electronvolt;
inline constexpr struct minute final : named_unit<"min", mag<60> * si::second> {} minute;
inline constexpr struct hour final : named_unit<"h", mag<60> * minute> {} hour;
inline constexpr struct electronvolt final : named_unit<"eV", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * si::joule> {} electronvolt;
```
Also, units of other [systems of units](../../appendix/glossary.md#system-of-units) are often defined
in terms of scaled versions of the SI units. For example, the international yard is defined as:
```cpp
inline constexpr struct yard : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct yard final : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
```
For some units, a magnitude might also be irrational. The best example here is a `degree` which
is defined using a floating-point magnitude having a factor of the number π (Pi):
```cpp
inline constexpr struct mag_pi : magnitude<std::numbers::pi_v<long double>> {} mag_pi;
inline constexpr struct mag_pi final : magnitude<std::numbers::pi_v<long double>> {} mag_pi;
```
```cpp
inline constexpr struct degree : named_unit<{u8"°", "deg"}, mag_pi / mag<180> * si::radian> {} degree;
inline constexpr struct degree final : named_unit<{u8"°", "deg"}, mag_pi / mag<180> * si::radian> {} degree;
```
@@ -33,30 +33,30 @@ and units of derived quantities.
=== "Dimensions"
```cpp
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_electric_current : base_dimension<"I"> {} dim_electric_current;
inline constexpr struct dim_thermodynamic_temperature : base_dimension<{u8"Θ", "O"}> {} dim_thermodynamic_temperature;
inline constexpr struct dim_amount_of_substance : base_dimension<"N"> {} dim_amount_of_substance;
inline constexpr struct dim_luminous_intensity : base_dimension<"J"> {} dim_luminous_intensity;
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_mass final : base_dimension<"M"> {} dim_mass;
inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
inline constexpr struct dim_electric_current final : base_dimension<"I"> {} dim_electric_current;
inline constexpr struct dim_thermodynamic_temperature final : base_dimension<{u8"Θ", "O"}> {} dim_thermodynamic_temperature;
inline constexpr struct dim_amount_of_substance final : base_dimension<"N"> {} dim_amount_of_substance;
inline constexpr struct dim_luminous_intensity final : base_dimension<"J"> {} dim_luminous_intensity;
```
=== "Units"
```cpp
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct metre final : named_unit<"m", kind_of<isq::length>> {} metre;
inline constexpr struct gram final : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr auto kilogram = kilo<gram>;
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct joule : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt : named_unit<"W", joule / second> {} watt;
inline constexpr struct coulomb : named_unit<"C", ampere * second> {} coulomb;
inline constexpr struct volt : named_unit<"V", watt / ampere> {} volt;
inline constexpr struct farad : named_unit<"F", coulomb / volt> {} farad;
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct joule final : named_unit<"J", newton * metre> {} joule;
inline constexpr struct watt final : named_unit<"W", joule / second> {} watt;
inline constexpr struct coulomb final : named_unit<"C", ampere * second> {} coulomb;
inline constexpr struct volt final : named_unit<"V", watt / ampere> {} volt;
inline constexpr struct farad final : named_unit<"F", coulomb / volt> {} farad;
inline constexpr struct ohm final : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```
=== "Prefixes"
@@ -75,13 +75,13 @@ and units of derived quantities.
=== "Constants"
```cpp
inline constexpr struct hyperfine_structure_transition_frequency_of_cs : named_unit<{u8"Δν_Cs", "dv_Cs"}, mag<9'192'631'770> * hertz> {} hyperfine_structure_transition_frequency_of_cs;
inline constexpr struct speed_of_light_in_vacuum : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct planck_constant : named_unit<"h", mag_ratio<662'607'015, 100'000'000> * mag_power<10, -34> * joule * second> {} planck_constant;
inline constexpr struct elementary_charge : named_unit<"e", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * coulomb> {} elementary_charge;
inline constexpr struct boltzmann_constant : named_unit<"k", mag_ratio<1'380'649, 1'000'000> * mag_power<10, -23> * joule / kelvin> {} boltzmann_constant;
inline constexpr struct avogadro_constant : named_unit<"N_A", mag_ratio<602'214'076, 100'000'000> * mag_power<10, 23> / mole> {} avogadro_constant;
inline constexpr struct luminous_efficacy : named_unit<"K_cd", mag<683> * lumen / watt> {} luminous_efficacy;
inline constexpr struct hyperfine_structure_transition_frequency_of_cs final : named_unit<{u8"Δν_Cs", "dv_Cs"}, mag<9'192'631'770> * hertz> {} hyperfine_structure_transition_frequency_of_cs;
inline constexpr struct speed_of_light_in_vacuum final : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
inline constexpr struct planck_constant final : named_unit<"h", mag_ratio<662'607'015, 100'000'000> * mag_power<10, -34> * joule * second> {} planck_constant;
inline constexpr struct elementary_charge final : named_unit<"e", mag_ratio<1'602'176'634, 1'000'000'000> * mag_power<10, -19> * coulomb> {} elementary_charge;
inline constexpr struct boltzmann_constant final : named_unit<"k", mag_ratio<1'380'649, 1'000'000> * mag_power<10, -23> * joule / kelvin> {} boltzmann_constant;
inline constexpr struct avogadro_constant final : named_unit<"N_A", mag_ratio<602'214'076, 100'000'000> * mag_power<10, 23> / mole> {} avogadro_constant;
inline constexpr struct luminous_efficacy final : named_unit<"K_cd", mag<683> * lumen / watt> {} luminous_efficacy;
```
!!! important
@@ -105,7 +105,7 @@ and units of derived quantities.
template name to initialize it with two symbols:
```cpp
inline constexpr struct ohm : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct ohm final : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```
@@ -172,7 +172,7 @@ origin.
![affine_space_2](affine_space_2.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
inline constexpr struct origin : absolute_point_origin<origin, isq::distance> {} origin;
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
@@ -197,14 +197,6 @@ assert(origin - qp2 == -120 * m);
// assert(origin - origin == 0 * m); // Compile-time error
```
!!! info
The `absolute_point_origin` class template uses the CRTP idiom to enforce the uniqueness of
such a type. You should pass the type of a derived class as the first argument of the template
instantiation.
*[CRTP]: Curiously Recurring Template Parameter
We can't construct a quantity point directly from the quantity anymore when a custom, named origin
is used. To prevent potential safety and maintenance issues, we always need to
explicitly provide both a compatible origin and a quantity measured from it to construct a quantity
@@ -249,8 +241,8 @@ type and unit is being used:
![affine_space_3](affine_space_3.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
inline constexpr struct origin1 : absolute_point_origin<origin1, isq::distance> {} origin1;
inline constexpr struct origin2 : absolute_point_origin<origin2, isq::distance> {} origin2;
inline constexpr struct origin1 final : absolute_point_origin<isq::distance> {} origin1;
inline constexpr struct origin2 final : absolute_point_origin<isq::distance> {} origin2;
quantity_point qp1 = origin1 + 100 * m;
quantity_point qp2 = origin2 + 120 * m;
@@ -284,10 +276,10 @@ For such cases, relative point origins should be used:
![affine_space_4](affine_space_4.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
inline constexpr struct A : absolute_point_origin<A, isq::distance> {} A;
inline constexpr struct B : relative_point_origin<A + 10 * m> {} B;
inline constexpr struct C : relative_point_origin<B + 10 * m> {} C;
inline constexpr struct D : relative_point_origin<A + 30 * m> {} D;
inline constexpr struct A final : absolute_point_origin<isq::distance> {} A;
inline constexpr struct B final : relative_point_origin<A + 10 * m> {} B;
inline constexpr struct C final : relative_point_origin<B + 10 * m> {} C;
inline constexpr struct D final : relative_point_origin<A + 30 * m> {} D;
quantity_point qp1 = C + 100 * m;
quantity_point qp2 = D + 120 * m;
@@ -392,17 +384,17 @@ point origins for this purpose:
```cpp
namespace si {
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
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 : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
inline constexpr struct ice_point final : relative_point_origin<quantity_point{273'150 * milli<kelvin>}> {} ice_point;
inline constexpr auto zeroth_degree_Celsius = ice_point;
}
namespace usc {
inline constexpr struct zeroth_degree_Fahrenheit :
inline constexpr struct zeroth_degree_Fahrenheit final :
relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
}
@@ -426,16 +418,16 @@ definitions:
```cpp
namespace si {
inline constexpr struct kelvin :
inline constexpr struct kelvin final :
named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
inline constexpr struct degree_Celsius :
inline constexpr struct degree_Celsius final :
named_unit<{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
}
namespace usc {
inline constexpr struct degree_Fahrenheit :
inline constexpr struct degree_Fahrenheit final :
named_unit<{u8"°F", "`F"}, mag_ratio<5, 9> * si::degree_Celsius,
zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
@@ -481,7 +473,7 @@ the following way:
![affine_space_6](affine_space_6.svg){style="width:80%;display: block;margin: 0 auto;"}
```cpp
constexpr struct room_reference_temp : relative_point_origin<quantity_point{21 * deg_C}> {} room_reference_temp;
constexpr struct room_reference_temp final : relative_point_origin<quantity_point{21 * 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);
@@ -85,11 +85,11 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
=== "C++23"
```cpp
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency : quantity_spec<dim_currency> {} currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency final : quantity_spec<dim_currency> {} currency;
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar final : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
namespace unit_symbols {
@@ -105,11 +105,11 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
=== "C++20"
```cpp
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency : quantity_spec<currency, dim_currency> {} currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
inline constexpr struct currency final : quantity_spec<currency, dim_currency> {} currency;
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar final : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
namespace unit_symbols {
@@ -125,11 +125,11 @@ the `value_cast<U, Rep>(q)` which always returns the most precise result:
=== "Portable"
```cpp
inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
inline constexpr struct dim_currency final : base_dimension<"$"> {} dim_currency;
QUANTITY_SPEC(currency, dim_currency);
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
inline constexpr struct us_dollar final : named_unit<"USD", kind_of<currency>> {} us_dollar;
inline constexpr struct scaled_us_dollar final : named_unit<"USD_s", mag_power<10, -8> * us_dollar> {} scaled_us_dollar;
namespace unit_symbols {