mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 18:37:15 +02:00
docs: 2.2 release announcement draft added
This commit is contained in:
299
docs/blog/posts/2.2.0-released.md
Normal file
299
docs/blog/posts/2.2.0-released.md
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
---
|
||||||
|
draft: true
|
||||||
|
date: 2024-01-09
|
||||||
|
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.0) and
|
||||||
|
[Conan](https://conan.io/center/recipes/mp-units?version=2.2.0).**
|
||||||
|
|
||||||
|
Among other features, this release provides long-awaited support for C++20 modules, redesigns text
|
||||||
|
output formatting, and greatly simplifies quantity point usage. This post describes those and a few
|
||||||
|
other smaller interesting improvements, while a list of the most significant changes introduced by
|
||||||
|
the new version can be found in our [Release Notes](../../release_notes.md#2.2.0).
|
||||||
|
|
||||||
|
<!-- more -->
|
||||||
|
|
||||||
|
## C++20 modules
|
||||||
|
|
||||||
|
[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.28.1
|
||||||
|
- Ninja 1.11
|
||||||
|
- clang-17
|
||||||
|
|
||||||
|
In the upcoming months, hopefully the situation will improve with the gcc-14 release and
|
||||||
|
bug fixes in 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).
|
||||||
|
|
||||||
|
In this release, we also highly limited the number of CMake targets (**breaking change**). 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 find now 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
|
||||||
|
(**breaking change**). 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 |
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
## 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 : absolute_point_origin<zero, currency> {} zero;
|
||||||
|
|
||||||
|
quantity_point price_usd = zero + 100 * USD;
|
||||||
|
```
|
||||||
|
|
||||||
|
As we can see above, the new design allows
|
||||||
|
[direct-initialization](https://en.cppreference.com/w/cpp/language/direct_initialization) of a
|
||||||
|
`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 a possibility to specify a default point origin in the units 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 absolute
|
||||||
|
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` (**breaking change**).
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
|
||||||
|
## Changes to units definitions
|
||||||
|
|
||||||
|
[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 (**breaking
|
||||||
|
change**). 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:
|
||||||
|
|
||||||
|
=== "Now"
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
inline constexpr struct ohm : named_unit<{u8"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Before"
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
inline constexpr struct ohm : named_unit<{"Ω", "ohm"}, volt / ampere> {} ohm;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 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<std::remove_const_t<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<std::remove_const_t<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, `fma`, `isfinite`, `isinf`, and `isnan` math function were added by
|
||||||
|
[@NAThompson](https://github.com/NAThompson). 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
|
||||||
|
(**breaking change**).
|
||||||
|
|
||||||
|
Also, the header itself was split into smaller pieces that improve C++20 modules definitions.
|
Reference in New Issue
Block a user