mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +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