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

View File

@ -172,7 +172,7 @@ Additionally, some CMake options were renamed to better express the impact on ou
Before this release, the library always depended on [gsl-lite](https://github.com/gsl-lite/gsl-lite)
to perform runtime contract and asserts checking. In this release we introduced new options
to control if contract checking should be based on [gsl-lite](https://github.com/gsl-lite/gsl-lite),
[ms-gsl](https://github.com/microsoft/GSL), or maybe completely disabled.
[ms-gsl](https://github.com/microsoft/GSL), or may be completely disabled.
## Freestanding support
@ -205,7 +205,7 @@ origins. For example:
=== "Before"
```cpp
constexpr struct zero : absolute_point_origin<zero, currency> {} zero;
constexpr struct zero final : absolute_point_origin<currency> {} zero;
quantity_point price_usd = zero + 100 * USD;
```
@ -260,6 +260,16 @@ named with its corresponding unit and with the `si::zeroth_degree_Celsius`
## Changes to units definitions
There were several known issues when units were deriving from each other
(e.g., [#512](https://github.com/mpusz/mp-units/issues/512) and
[#537](https://github.com/mpusz/mp-units/issues/537)). We could either highly complicate the
framework to allow these which could result in much longer compilation times or disallow inheriting
from units at all. We chose the second option.
With this release all of of the units must be marked as `final`. To enforce this we have changed
the definition of the `Unit<T>` concept, which now requires type `T` to be `final`
(:boom: **breaking change** :boom:).
[WG21 Study Group 16 (Unicode) raised concerns](https://github.com/sg16-unicode/sg16-meetings#january-24th-2024)
about potential ABI issues when different translation units are compiled with different ordinary
literal encodings. Those issues were resolved with a change to units definitions
@ -272,7 +282,7 @@ is why it was renamed to `symbol_text` (:boom: **breaking change** :boom:).
=== "Now"
```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;
```
=== "Before"
@ -286,9 +296,48 @@ is why it was renamed to `symbol_text` (:boom: **breaking change** :boom:).
On C++20-compliant compilers it should be enough to type the following in the unit's definition:
```cpp
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
inline constexpr struct ohm final : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
```
## Changes to dimension, quantity specification, and point origins definitions
Similarly to units, now also all dimensions, quantity specifications, and point origins have to be
marked `final` (:boom: **breaking change** :boom:).
=== "Now"
```cpp
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct length final : quantity_spec<dim_length> {} length;
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
inline constexpr auto zeroth_kelvin = absolute_zero;
inline constexpr struct kelvin final : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
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;
inline constexpr struct degree_Celsius final : named_unit<symbol_text{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
```
=== "Before"
```cpp
inline constexpr struct dim_length : base_dimension<"L"> {} dim_length;
inline constexpr struct length : quantity_spec<dim_length> {} length;
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 kelvin : named_unit<"K", kind_of<isq::thermodynamic_temperature>, zeroth_kelvin> {} kelvin;
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 degree_Celsius : named_unit<symbol_text{u8"°C", "`C"}, kelvin, zeroth_degree_Celsius> {} degree_Celsius;
```
Please also note, that the `absolute_point_origin` does not use CRTP idiom anymore (:boom: **breaking change** :boom:).
## Improved text output
With this release, we can print not only whole quantities but also just their units or dimensions.
@ -461,8 +510,8 @@ conversion factor. Here is a comparison of the code with previous and current de
=== "Now"
```cpp
inline constexpr struct yard : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct foot : named_unit<"ft", mag_ratio<1, 3> * yard> {} foot;
inline constexpr struct yard final : named_unit<"yd", mag_ratio<9'144, 10'000> * si::metre> {} yard;
inline constexpr struct foot final : named_unit<"ft", mag_ratio<1, 3> * yard> {} foot;
```
=== "Before"

View File

@ -342,7 +342,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`MP_UNITS_API_STD_FORMAT`](#MP_UNITS_API_STD_FORMAT){ #MP_UNITS_API_STD_FORMAT }
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `AUTO`/`TRUE`/`FALSE` (Default: `AUTO`)
Enables the usage of [`std::format`](https://en.cppreference.com/w/cpp/utility/format/format)
and associated facilities for text formatting. If it is not supported, then
@ -352,7 +352,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`MP_UNITS_API_STRING_VIEW_RET`](#MP_UNITS_API_STRING_VIEW_RET){ #MP_UNITS_API_STRING_VIEW_RET }
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `AUTO`/`TRUE`/`FALSE` (Default: `AUTO`)
Enables returning `std::string_view` from the
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
@ -364,7 +364,7 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`MP_UNITS_API_NO_CRTP`](#MP_UNITS_API_NO_CRTP){ #MP_UNITS_API_NO_CRTP }
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `AUTO`/`TRUE`/`FALSE` (Default: `AUTO`)
Removes the need for the usage of the CRTP idiom in the
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).

View File

@ -33,7 +33,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
using namespace mp_units;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
inline constexpr struct smoot final : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
int main()
{
@ -53,7 +53,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
using namespace mp_units;
inline constexpr struct smoot : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
inline constexpr struct smoot final : named_unit<"smoot", mag<67> * usc::inch> {} smoot;
int main()
{
@ -69,7 +69,7 @@ Output:
Harvard Bridge length = 364.4 smoot (2034.6 ft, 620.14 m) ± 1 εar
```
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/zsW1f6Tn1)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/f8f4KnKh8)"
??? question "What is `smoot`?"

View File

@ -7,7 +7,7 @@ tags:
# `avg_speed`
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/EYo7879qd)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/TnqGa4sdn)"
Let's continue the previous example. This time, our purpose will not be to showcase as many
library features as possible, but we will scope on different interfaces one can provide

View File

@ -6,7 +6,7 @@ tags:
# `hello_units`
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/KKGGhKjqn)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/bT4GGPbef)"
This is a really simple example showcasing the features of the **mp-units** library.
@ -18,20 +18,20 @@ First, we either import the `mp_units` module or include the headers for:
- text formatting and stream output support
```cpp title="hello_units.cpp" linenums="1"
--8<-- "example/hello_units.cpp:28:40"
--8<-- "example/hello_units.cpp:28:41"
```
Also, to shorten the definitions, we "import" all the symbols from the `mp_units` namespace.
```cpp title="hello_units.cpp" linenums="13"
--8<-- "example/hello_units.cpp:41:42"
```cpp title="hello_units.cpp" linenums="14"
--8<-- "example/hello_units.cpp:42:43"
```
Next, we define a simple function that calculates the average speed based on the provided
arguments of length and time:
```cpp title="hello_units.cpp" linenums="14"
--8<-- "example/hello_units.cpp:43:46"
```cpp title="hello_units.cpp" linenums="15"
--8<-- "example/hello_units.cpp:44:47"
```
The above function template takes any quantities implicitly convertible to `isq::length`
@ -45,37 +45,37 @@ that its quantity type is implicitly convertible to `isq::speed`.
type is beneficial for users of such a function as it provides more information
of what to expect from a function than just using `auto`.
```cpp title="hello_units.cpp" linenums="18"
--8<-- "example/hello_units.cpp:48:51"
```cpp title="hello_units.cpp" linenums="19"
--8<-- "example/hello_units.cpp:49:52"
```
The above lines explicitly opt into using unit symbols from two systems of units.
As this introduces a lot of short identifiers into the current scope, it is not done
implicitly while including a header file.
```cpp title="hello_units.cpp" linenums="22"
--8<-- "example/hello_units.cpp:53:59"
```cpp title="hello_units.cpp" linenums="23"
--8<-- "example/hello_units.cpp:54:60"
```
- Lines `21` & `22` create a quantity of kind `isq::length / isq::time` with the numbers
- Lines `23` & `24` create a quantity of kind `isq::length / isq::time` with the numbers
and units provided. Such quantities can be converted or assigned to any other quantity
with a matching kind.
- Line `23` calls our function template with quantities of kind `isq::length` and
- Line `25` calls our function template with quantities of kind `isq::length` and
`isq::time` and number and units provided.
- Line `24` explicitly provides quantity types of the quantities passed to a function template.
- Line `26` explicitly provides quantity types of the quantities passed to a function template.
This time, those will not be quantity kinds anymore and will have
[more restrictive conversion rules](../framework_basics/simple_and_typed_quantities.md#quantity_cast-to-force-unsafe-conversions).
- Line `25` changes the unit of a quantity `v3` to `m / s` in a
- Line `27` changes the unit of a quantity `v3` to `m / s` in a
[value-preserving way](../framework_basics/value_conversions.md#value-preserving-conversions)
(floating-point representations are considered to be value-preserving).
- Line `26` does a similar operation, but this time, it would also succeed for
- Line `28` does a similar operation, but this time, it would also succeed for
[value-truncating cases](../framework_basics/value_conversions.md#value-truncating-conversions)
(if that was the case).
- Line `27` does a [value-truncating conversion](../framework_basics/value_conversions.md#value-truncating-conversions)
- Line `29` does a [value-truncating conversion](../framework_basics/value_conversions.md#value-truncating-conversions)
of changing the underlying representation type from `double` to `int`.
```cpp title="hello_units.cpp" linenums="29"
--8<-- "example/hello_units.cpp:61"
```cpp title="hello_units.cpp" linenums="30"
--8<-- "example/hello_units.cpp:62"
```
The above presents [various ways to print a quantity](../framework_basics/text_output.md).

View File

@ -6,14 +6,14 @@ tags:
# `si_constants`
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/sEqWcchdE)"
!!! example "[Try it on Compiler Explorer](https://godbolt.org/z/MevcK8vYT)"
The next example presents all the seven defining constants of the SI system. We can observe
how [Faster-than-lightspeed Constants](../framework_basics/faster_than_lightspeed_constants.md)
work in practice.
```cpp title="si_constants.cpp" linenums="1"
--8<-- "example/si_constants.cpp:28:39"
--8<-- "example/si_constants.cpp:28:40"
```
As always, we start with the inclusion of all the needed header files. After that, for
@ -21,8 +21,8 @@ the simplicity of this example, we
[hack the character of quantities](../framework_basics/character_of_a_quantity.md#hacking-the-character)
to be able to express vector quantities with simple scalar types.
```cpp title="si_constants.cpp" linenums="13"
--8<-- "example/si_constants.cpp:41:"
```cpp title="si_constants.cpp" linenums="14"
--8<-- "example/si_constants.cpp:42:"
```
The main part of the example prints all of the SI-defining constants. While analyzing the output of

View File

@ -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"

View File

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

View File

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

View File

@ -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.

View File

@ -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

View File

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

View File

@ -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_;

View File

@ -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"

View File

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

View File

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

View File

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

View File

@ -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 {

View File

@ -256,8 +256,8 @@ include the _mp-units/systems/si/chrono.h_ file to benefit from it. This file pr
to the `std::chrono` abstractions:
```cpp
inline constexpr struct ts_origin : relative_point_origin<chrono_point_origin<system_clock> + 1 * h> {} ts_origin;
inline constexpr struct my_origin : absolute_point_origin<my_origin, isq::time> {} my_origin;
inline constexpr struct ts_origin final : relative_point_origin<chrono_point_origin<system_clock> + 1 * h> {} ts_origin;
inline constexpr struct my_origin final : absolute_point_origin<isq::time> {} my_origin;
quantity_point qp1 = sys_seconds{1s};
auto tp1 = to_chrono_time_point(qp1); // OK

View File

@ -29,7 +29,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<isq::length> {} horizontal_length;
// ...
@ -45,7 +45,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
// ...
@ -65,7 +65,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
// ...
@ -85,7 +85,7 @@ your code using **mp-units**:
// ...
inline constexpr struct horizontal_length : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
inline constexpr struct horizontal_length final : quantity_spec<horizontal_length, isq::length> {} horizontal_length;
// ...
@ -96,6 +96,7 @@ your code using **mp-units**:
```cpp
#include <iostream>
#include <mp-units/ext/format.h>
#ifdef MP_UNITS_MODULES
#include <mp-units/compat_macros.h>
import mp_units;
@ -157,3 +158,30 @@ from additional features provided with the library).
This macro resolves to either the `std` or `fmt` namespace, depending on the value of
[MP_UNITS_API_STD_FORMAT](../../getting_started/installation_and_usage.md#MP_UNITS_API_STD_FORMAT)
CMake option.
To include the header files of the underlying text formatting framework, the following include
should be used:
```cpp
#include <mp-units/ext/format.h>
```
### Contracts
The mp-units library internally does contract checking by default. It can be disabled with a Conan
or CMake option. However, when enabled, it can use either [gsl-lite](https://github.com/gsl-lite/gsl-lite)
or [ms-gsl](https://github.com/microsoft/GSL). To write a code that is independent from the
underlying framework, the following preprocessor macros are exposed:
- `MP_UNITS_EXPECTS(expr)`
- `MP_UNITS_EXPECTS_DEBUG(expr)`
- `MP_UNITS_ASSERT(expr)`
- `MP_UNITS_ASSERT_DEBUG(expr)`
Their meaning is consistent with respective [gsl-lite](https://github.com/gsl-lite/gsl-lite?tab=readme-ov-file#contract-checking-configuration-macros).
Also, to include the header files of the underlying framework, the following include should be used:
```cpp
#include <mp-units/ext/contracts.h>
```