forked from mpusz/mp-units
522 lines
24 KiB
Markdown
522 lines
24 KiB
Markdown
---
|
|
date: 2024-06-14
|
|
authors:
|
|
- mpusz
|
|
categories:
|
|
- Releases
|
|
---
|
|
|
|
# mp-units 2.2.0 released!
|
|
|
|
**A new product version can be obtained from
|
|
[GitHub](https://github.com/mpusz/mp-units/releases/tag/v2.2.1) and
|
|
[Conan](https://conan.io/center/recipes/mp-units?version=2.2.1).**
|
|
|
|
Among other features, this release provides long-awaited support for C++20 modules, redesigns and
|
|
enhances text output formatting, and greatly simplifies quantity point usage. This post describes
|
|
those and a few other smaller interesting improvements, while a much longer list of the most
|
|
significant changes introduced by the new version can be found in our
|
|
[Release Notes](../../release_notes.md#2.2.1).
|
|
|
|
<!-- more -->
|
|
|
|
## C++20 modules and project structure cleanup
|
|
|
|
[GitHub Issue #7](https://github.com/mpusz/mp-units/issues/7) was our oldest open issue
|
|
before this release. Not anymore. After 4.5 years, we finally closed it, even though
|
|
the C++ modules' support is still really limited.
|
|
|
|
!!! info
|
|
|
|
To benefit from C++ modules, we need at least:
|
|
|
|
- CMake 3.29.3
|
|
- Ninja 1.11
|
|
- clang-17
|
|
|
|
In the upcoming months, hopefully, the situation will improve with the bug fixes in
|
|
CMake, gcc-14, and MSVC.
|
|
|
|
!!! note
|
|
|
|
More requirements for C++ modules support can be found in the
|
|
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
|
|
|
|
To enable the compilation and distribution of C++ modules, a
|
|
[`cxx_modules`](../../getting_started/installation_and_usage.md#cxx_modules) Conan or
|
|
[`MP_UNITS_BUILD_CXX_MODULES`](../../getting_started/installation_and_usage.md#MP_UNITS_BUILD_CXX_MODULES)
|
|
CMake option has to be enabled.
|
|
|
|
With the above, the following C++ modules will be provided:
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
mp_units --- mp_units.systems --- mp_units.core
|
|
```
|
|
|
|
| C++ Module | CMake Target | Contents |
|
|
|--------------------|----------------------|----------------------------------------------------------|
|
|
| `mp_units.core` | `mp-units::core` | Core library framework and systems-independent utilities |
|
|
| `mp_units.systems` | `mp-units::systems` | All the systems of quantities and units |
|
|
| `mp_units` | `mp-units::mp-units` | Core + Systems |
|
|
|
|
The easiest way to use them is just to `import mp_units;` at the beginning of your translation unit
|
|
(see the [Quick Start](../../getting_started/quick_start.md) chapter for some usage examples).
|
|
|
|
!!! note
|
|
|
|
C++20 modules support still have some issues when imported from the installed CMake target.
|
|
See the following [GitLab issue for more details](https://gitlab.kitware.com/cmake/cmake/-/issues/25909#note_1525377).
|
|
|
|
In this release, we also highly limited the number of CMake targets (:boom: **breaking change** :boom:).
|
|
Now, they correspond exactly to the C++ modules they provide. This means that many smaller partial
|
|
targets were removed. We also merged text output targets with the core library's definition.
|
|
|
|
The table below specifies where we can now find the contents of previously available CMake targets:
|
|
|
|
| Before | Now |
|
|
|---------------------------|---------------------|
|
|
| `mp-units::utility` | `mp-units::core` |
|
|
| `mp-units::core-io` | `mp-units::core` |
|
|
| `mp-units::core-fmt` | `mp-units::core` |
|
|
| `mp-units::{system_name}` | `mp-units::systems` |
|
|
|
|
While we were enabling C++ modules, we also had to refactor our header files slightly
|
|
(:boom: **breaking change** :boom:). Some had to be split into smaller pieces (e.g., _math.h_),
|
|
while others had to be moved to a different subdirectory (e.g., _chrono.h_).
|
|
|
|
In version 2.2, the following headers have a new location or contents:
|
|
|
|
| Header File | C++ Module | Contents |
|
|
|-----------------------------------|--------------------|-------------------------------------------------|
|
|
| _mp-units/math.h_ | `mp_units.core` | System-independent functions only |
|
|
| _mp-units/systems/si/math.h_ | `mp_units.systems` | Trigonometric functions using `si::radian` |
|
|
| _mp-units/systems/angular/math.h_ | `mp_units.systems` | Trigonometric functions using `angular::radian` |
|
|
| _mp-units/systems/si/chrono.h_ | `mp_units.systems` | `std::chrono` compatibility traits |
|
|
|
|
Benefiting from this opportunity, we also cleaned up core and systems definitions
|
|
(:boom: **breaking change** :boom:).
|
|
|
|
Regarding the library's core, we removed `core.h` and exposed only one header `framework.h` that
|
|
provides all of the library's framework so the user does not have to enumerate files like `unit.h`,
|
|
`quantity.h`, and `quantity_point.h` anymore. Those headers are not gone, they were put to
|
|
the `mp-units/framework` subheader. So they are still there if you really need them.
|
|
|
|
Regarding the changes in systems definitions, we moved the wrapper header files with the entire
|
|
system definition to the `mp-units/systems` subdirectory. Additionally, they now also include
|
|
`framework.h`, so a system include is enough to use the library. Thanks to that our users don't
|
|
have to write tedious code like the below anymore:
|
|
|
|
=== "Now"
|
|
|
|
```cpp
|
|
#include <mp-units/systems/cgs.h>
|
|
#include <mp-units/systems/international.h>
|
|
#include <mp-units/systems/isq.h>
|
|
#include <mp-units/systems/si.h>
|
|
|
|
// ...
|
|
```
|
|
|
|
=== "Before"
|
|
|
|
```cpp
|
|
#include <mp-units/quantity_point.h>
|
|
#include <mp-units/systems/cgs/cgs.h>
|
|
#include <mp-units/systems/international/international.h>
|
|
#include <mp-units/systems/isq/isq.h>
|
|
#include <mp-units/systems/si/si.h>
|
|
|
|
// ...
|
|
```
|
|
|
|
Additionally, we merged all of the compatibility-related macros into one header file
|
|
`mp-units/compat_macros.h`. This header file should be explicitly included before importing C++
|
|
modules if we want to benefit from the
|
|
[Wide Compatibility tools](../../users_guide/use_cases/wide_compatibility.md).
|
|
|
|
|
|
## Better control over the library's API
|
|
|
|
With this release, nearly all of the Conan and CMake build options were refactored with the intent
|
|
of providing better control over the library's API.
|
|
|
|
Previously, the library used the latest available feature set supported by a specific
|
|
compiler. For example,
|
|
[`quantity_spec` definitions would use CRTP](../../users_guide/framework_basics/systems_of_quantities.md#defining-quantities)
|
|
on an older compiler or provide a simpler API on a newer one thanks to the C++23 `this` deduction
|
|
feature. This could lead to surprising results where the same code written by the user would
|
|
compile fine on one compiler but not the other.
|
|
|
|
From this release, all API extensions have their corresponding configuration options in Conan and
|
|
CMake. With this, a user has full control over the API exposed by the library. Those options expose
|
|
three values:
|
|
|
|
- `True` - The feature is always enabled (the configuration error will happen if the compiler does
|
|
not support this feature)
|
|
- `False` - The feature is disabled, and an older alternative is always used.
|
|
- `Auto` - The feature is automatically enabled if the compiler supports it (old behavior).
|
|
|
|
Additionally, some CMake options were renamed to better express the impact on our users
|
|
(:boom: **breaking change** :boom:). For example, now CMake options include:
|
|
|
|
- `MP_UNITS_API_*` - options affecting the library's API,
|
|
- `MP_UNITS_BUILD_*` - options affecting the build process,
|
|
- `MP_UNITS_DEV_*` - options primarily useful for the project developers or people who want to
|
|
compile our unit tests and examples.
|
|
|
|
|
|
## Configurable contracts checking
|
|
|
|
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 may be completely disabled.
|
|
|
|
|
|
## Freestanding support
|
|
|
|
From this release it is possible to configure the library in the
|
|
[freestanding](https://en.cppreference.com/w/cpp/freestanding) mode. This limits the functionality
|
|
and interface of the library to be compatible with the freestanding implementations.
|
|
|
|
!!! info
|
|
|
|
To learn more, please refer to the [Build options](../../getting_started/installation_and_usage.md#build-options)
|
|
chapter.
|
|
|
|
|
|
## Simplified quantity point support
|
|
|
|
This release significantly simplifies the usage of quantity points and affine space abstractions
|
|
in general.
|
|
|
|
Previously, the user always had to define an explicit point origin even if the domain being modeled
|
|
does not have such an explicit origin. Now, in such cases, we can benefit from the implicit point
|
|
origins. For example:
|
|
|
|
=== "Now"
|
|
|
|
```cpp
|
|
quantity_point price_usd{100 * USD};
|
|
```
|
|
|
|
=== "Before"
|
|
|
|
```cpp
|
|
constexpr struct zero final : absolute_point_origin<currency> {} zero;
|
|
|
|
quantity_point price_usd = zero + 100 * USD;
|
|
```
|
|
|
|
As we can see above, the new design allows
|
|
[direct-initializing](https://en.cppreference.com/w/cpp/language/direct_initialization)
|
|
`quantity_point` class template from a `quantity`, but only if the former one is defined in terms
|
|
of the implicit point origin. Otherwise, an explicit origin still always has to be provided during
|
|
initialization.
|
|
|
|
Also, we introduced the possibility of specifying a default point origin in the unit definition.
|
|
With that, we could provide proper temperature scales without forcing the user to always use
|
|
the origins explicitly. Also, a new member function, `.quantity_from_zero(),` was introduced
|
|
that always returns the quantity from the unit's specific point origin or from the implicit
|
|
point origin otherwise.
|
|
|
|
=== "Now"
|
|
|
|
```cpp
|
|
quantity_point temp{20 * deg_C};
|
|
std::cout << "Temperature: " << temp << " ("
|
|
<< temp.in(deg_F).quantity_from_zero() << ", "
|
|
<< temp.in(K).quantity_from_zero() << ")\n";
|
|
```
|
|
|
|
=== "Before"
|
|
|
|
```cpp
|
|
quantity_point temp = si::zeroth_degree_Celsius + 20 * deg_C;
|
|
std::cout << "Temperature: " << temp << " ("
|
|
<< temp.in(deg_F).quantity_from(usc::zeroth_degree_Fahrenheit) << ", "
|
|
<< temp.in(K).quantity_from(si::zeroth_kelvin) << ")\n";
|
|
```
|
|
|
|
More information about the new design can be found in
|
|
[The Affine Space](../../users_guide/framework_basics/the_affine_space.md)
|
|
chapter.
|
|
|
|
|
|
## Unified temperature point origins names
|
|
|
|
By omission, we had the following temperature point origins in the library:
|
|
|
|
- `si::zero_kelvin` (for `si::kelvin`),
|
|
- `si::zeroth_degree_Celsius` (for `si::degree_Celsius`),
|
|
- `usc::zero_Fahrenheit` (for `usc::degree_Fahrenheit`).
|
|
|
|
With this release, the last one was renamed to `usc::zeroth_degree_Fahrenheit` to be consistently
|
|
named with its corresponding unit and with the `si::zeroth_degree_Celsius`
|
|
(:boom: **breaking change** :boom:).
|
|
|
|
|
|
## 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
|
|
(:boom: **breaking change** :boom:). It affects only units that specify both Unicode and ASCII
|
|
symbols. The new design requires the Unicode symbol to be provided as a UTF-8 literal.
|
|
|
|
This also means that the `basic_symbol_text` has fixed character types for both symbols. This
|
|
is why it was renamed to `symbol_text` (:boom: **breaking change** :boom:).
|
|
|
|
=== "Now"
|
|
|
|
```cpp
|
|
inline constexpr struct ohm final : named_unit<symbol_text{u8"Ω", "ohm"}, volt / ampere> {} ohm;
|
|
```
|
|
|
|
=== "Before"
|
|
|
|
```cpp
|
|
inline constexpr struct ohm : named_unit<basic_symbol_text{"Ω", "ohm"}, volt / ampere> {} ohm;
|
|
```
|
|
|
|
!!! note
|
|
|
|
On C++20-compliant compilers it should be enough to type the following in the unit's definition:
|
|
|
|
```cpp
|
|
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"}, 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"}, 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.
|
|
Also, we fixed the `std::format` support so users can now enjoy full C++20 compatibility and
|
|
don't have to use [fmtlib](https://github.com/fmtlib/fmt) anymore.
|
|
|
|
We have also changed the grammar for quantities formatting (:boom: **breaking change** :boom:).
|
|
It introduces the composition of underlying formatters that finally allows us to properly format
|
|
user-defined representation types (assuming they have `std::format` support). Additionally, thanks
|
|
to a new `%?` token, we can provide a custom format string that will properly print quantity of
|
|
any unit.
|
|
|
|
Here is a small preview of what is now available:
|
|
|
|
```cpp
|
|
using namespace mp_units::si::unit_symbols;
|
|
using namespace mp_units::international::unit_symbols;
|
|
quantity q = (90. * km / h).in(mph);
|
|
|
|
std::cout << "Number: " << q.numerical_value_in(mph) << "\n";
|
|
std::cout << "Unit: " << q.unit << "\n";
|
|
std::cout << "Dimension: " << q.dimension << "\n";
|
|
std::println("{::N[.2f]}", q);
|
|
std::println("{:.4f} in {} of {}", q.numerical_value_in(mph), q.unit, q.dimension);
|
|
std::println("{:%N in %U of %D:N[.4f]}", q);
|
|
```
|
|
|
|
```text
|
|
Number: 55.9234
|
|
Unit: mi/h
|
|
Dimension: LT⁻¹
|
|
55.92 mi/h
|
|
55.9234 in mi/h of LT⁻¹
|
|
55.9234 in mi/h of LT⁻¹
|
|
```
|
|
|
|
More on this subject can be found in the updated [Text Output](../../users_guide/framework_basics/text_output.md)
|
|
chapter.
|
|
|
|
|
|
## Improved casts
|
|
|
|
We added a new conversion function. `value_cast<Unit, Representation>` forces the conversion
|
|
of both a unit and representation type in one step and always ensures that the best precision
|
|
is provided.
|
|
|
|
Also, we have finally added proper implementations of `value_cast` and `quantity_cast` for
|
|
quantity points.
|
|
|
|
|
|
## Even better error messages
|
|
|
|
This release made a few small refactorings that, without changing the user-facing API, allowed us
|
|
to improve the readability of the generated types that can be observed in the compilation errors.
|
|
|
|
Example 1 (clang):
|
|
|
|
=== "Now"
|
|
|
|
```txt
|
|
error: no matching function for call to 'time_to_goal'
|
|
26 | const quantity ttg = time_to_goal(half_marathon_distance, pace);
|
|
| ^~~~~~~~~~~~
|
|
note: candidate template ignored: constraints not satisfied [with distance:auto = quantity<kilo_<metre>{}, double>,
|
|
speed:auto = quantity<derived_unit<second, per<kilo_<metre>>>{}, double>]
|
|
13 | QuantityOf<isq::time> auto time_to_goal(QuantityOf<isq::length> auto distance,
|
|
| ^
|
|
note: because 'QuantityOf<quantity<derived_unit<si::second, per<si::kilo_<si::metre> > >{{{}}}>, isq::speed>' evaluated to false
|
|
14 | QuantityOf<isq::speed> auto speed)
|
|
| ^
|
|
note: because 'QuantitySpecOf<std::remove_const_t<decltype(quantity<derived_unit<second, per<kilo_<metre> > >{{{}}}, double>::quantity_spec)>, struct speed{{{}}}>' evaluated to false
|
|
61 | concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
|
| ^
|
|
note: because 'implicitly_convertible(kind_of_<derived_quantity_spec<isq::time, per<isq::length> > >{}, struct speed{{{}}})' evaluated to false
|
|
147 | QuantitySpec<T> && QuantitySpec<decltype(QS)> && implicitly_convertible(T{}, QS) &&
|
|
| ^
|
|
1 error generated.
|
|
Compiler returned: 1
|
|
```
|
|
|
|
=== "Before"
|
|
|
|
```txt
|
|
error: no matching function for call to 'time_to_goal'
|
|
26 | const quantity ttg = time_to_goal(half_marathon_distance, pace);
|
|
| ^~~~~~~~~~~~
|
|
note: candidate template ignored: constraints not satisfied [with distance:auto = quantity<kilo_<metre{{}}>{}, double>,
|
|
speed:auto = quantity<derived_unit<second, per<kilo_<metre{{}}>>>{}, double>]
|
|
13 | QuantityOf<isq::time> auto time_to_goal(QuantityOf<isq::length> auto distance,
|
|
| ^
|
|
note: because 'QuantityOf<quantity<derived_unit<si::second, per<si::kilo_<si::metre{{}}> > >{{{}}}>, isq::speed>' evaluated to false
|
|
14 | QuantityOf<isq::speed> auto speed)
|
|
| ^
|
|
note: because 'QuantitySpecOf<std::remove_const_t<decltype(quantity<derived_unit<second, per<kilo_<metre{{}}> > >{{{}}}, double>::quantity_spec)>, struct speed{{{}}}>' evaluated to false
|
|
61 | concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;
|
|
| ^
|
|
note: because 'implicitly_convertible(kind_of_<derived_quantity_spec<isq::time, per<isq::length> >{{}, {{}}}>{}, struct speed{{{}}})' evaluated to false
|
|
147 | QuantitySpec<T> && QuantitySpec<decltype(QS)> && implicitly_convertible(T{}, QS) &&
|
|
| ^
|
|
1 error generated.
|
|
Compiler returned: 1
|
|
```
|
|
|
|
Example 2 (gcc):
|
|
|
|
=== "Now"
|
|
|
|
```txt
|
|
error: no matching function for call to 'Box::Box(quantity<reference<isq::height, si::metre>(), int>, quantity<reference<horizontal_length, si::metre>(), int>,
|
|
quantity<reference<isq::width, si::metre>(), int>)'
|
|
27 | Box my_box(isq::height(1 * m), horizontal_length(2 * m), isq::width(3 * m));
|
|
| ^
|
|
note: candidate: 'Box::Box(quantity<reference<horizontal_length, si::metre>()>, quantity<reference<isq::width, si::metre>()>,
|
|
quantity<reference<isq::height, si::metre>()>)'
|
|
19 | Box(quantity<horizontal_length[m]> l, quantity<isq::width[m]> w, quantity<isq::height[m]> h):
|
|
| ^~~
|
|
note: no known conversion for argument 1 from 'quantity<reference<isq::height, si::metre>(),int>'
|
|
to 'quantity<reference<horizontal_length, si::metre>(),double>'
|
|
19 | Box(quantity<horizontal_length[m]> l, quantity<isq::width[m]> w, quantity<isq::height[m]> h):
|
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
|
|
```
|
|
|
|
=== "Before"
|
|
|
|
```txt
|
|
error: no matching function for call to 'Box::Box(quantity<reference<isq::height(), si::metre()>(), int>, quantity<reference<horizontal_length(), si::metre()>(), int>,
|
|
quantity<reference<isq::width(), si::metre()>(), int>)'
|
|
27 | Box my_box(isq::height(1 * m), horizontal_length(2 * m), isq::width(3 * m));
|
|
| ^
|
|
note: candidate: 'Box::Box(quantity<reference<horizontal_length(), si::metre()>()>, quantity<reference<isq::width(), si::metre()>()>,
|
|
quantity<reference<isq::height(), si::metre()>()>)'
|
|
19 | Box(quantity<horizontal_length[m]> l, quantity<isq::width[m]> w, quantity<isq::height[m]> h):
|
|
| ^~~
|
|
note: no known conversion for argument 1 from 'quantity<reference<isq::height(), si::metre()>(),int>'
|
|
to 'quantity<reference<horizontal_length(), si::metre()>(),double>'
|
|
19 | Box(quantity<horizontal_length[m]> l, quantity<isq::width[m]> w, quantity<isq::height[m]> h):
|
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
|
|
```
|
|
|
|
|
|
## _math.h_ header changes
|
|
|
|
This release provided lots of changes to the _mp_units/math.h_ header file.
|
|
|
|
First, we got several outstanding contributions:
|
|
|
|
- `fma`, `isfinite`, `isinf`, and `isnan` math functions were added by
|
|
[@NAThompson](https://github.com/NAThompson),
|
|
- `ppm`, `atan2`, `fmod`, and `remainder` were added by [@nebkat](https://github.com/nebkat).
|
|
|
|
Thanks!
|
|
|
|
Additionally, we changed the namespace for trigonometric functions using SI units. Now they are
|
|
inside of the `mp_units::si` subnamespace and not in `mp_units::isq` like it was the case before
|
|
(:boom: **breaking change** :boom:).
|
|
|
|
Also, the header itself was split into smaller pieces that improve C++20 modules definitions.
|
|
|
|
|
|
## `ratio` made an implementation detail of the library
|
|
|
|
We decided not to expose `ratio` and associated interfaces in the public part of the library
|
|
(:boom: **breaking change** :boom:). Standardization of it could be problematic as we have
|
|
[`std::ratio`](https://en.cppreference.com/w/cpp/numeric/ratio/ratio) already.
|
|
|
|
Alternatively, as in the public interface it was always only used with `mag`, we introduced a new
|
|
helper called `mag_ratio` to provide the magnitude of the unit defined in terms of a rational
|
|
conversion factor. Here is a comparison of the code with previous and current definitions:
|
|
|
|
=== "Now"
|
|
|
|
```cpp
|
|
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"
|
|
|
|
```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;
|
|
```
|