mp-units 2.4.0 released!¶
+A new product version can be obtained from +GitHub and +Conan.
+This release was unexpected. We planned a significant new feature to happen next, but while +preparing for it, and also while writing API Reference documentation, we made so many vital fixes +and improvements that we decided that they deserve a dedicated release first.
+This post describes the most significant improvements while a much longer list of the changes +introduced by the new version can be found in our Release Notes.
+ + +ISQ quantities cleanup¶
+Initially, we kept quantities defined in "IEC 80000-13: Information science and technology" in
+a standalone iec80000
namespace, which was renamed to iec
in the previous release.
+It turned out that this was incorrect. Those quantities are also a part of the ISQ. This is why,
+in this release, we moved all of them to the isq
namespace ( breaking change
).
From now on, iec
namespace does not provide any quantities and serves purely as a system of units
+definition. It contains binary prefixes (based on the powers of two) and some units introduced
+by IEC (e.g., var
, erlang
, bit
, or `baud
).
Note
+The quantities in iec
namespace are now deprecated and will be removed in future releases.
Also, it turns out that the latest ISO 80000-3 revision makes a small cleanup to the phase_speed
+and group_speed
quantities. Those were always defined as scalar quantities but also had
+alternative names phase_velocity
and group_velocity
. This is misleading as velocity is
+typically considered a vector quantity. It is why those XXX_velocity
aliases were removed from
+the ISO standard and from mp-units library ( breaking change
).
Units equality¶
+Previously we assumed that units like J
, N m
, and kg m²/s²
are equal. In some cases,
+this might not be entirely correct. Some quantities require a specific derived unit instead of
+a unit with a special name. For example:
-
+
N m
should be used for moment of force (instead ofJ
),
+V A
should be used for apparent power (instead ofW
).
+
This is why, starting from this release units like J
, N m
, and kg m²/s²
will not compare equal
+( breaking change
). However, they are deemed equivalent:
Portable text output¶
+From the very beginning, the text output of symbols could be formatted in two different ways:
+-
+
- Unicode, +
- portable using so-called ASCII alternatives. +
mp-units used the terms "Unicode" or "ASCII" and 'U' or 'A' formatting options for them. +Even though those terms are widely understood in the C++ community, they are technically +incorrect.
+During the recent SG16 meeting, we looked for proper alternatives and ended up with the "portable"
+and "UTF-8" terms ( breaking change
).
From now on, we will provide the following:
+-
+
text_encoding::utf8
,symbol_text<N, M>::utf8()
, andU
formatting option,
+text_encoding::portable
,symbol_text<N, M>::portable()
, andP
formatting option.
+
Note
+The old identifiers and formatting options are now deprecated and will be removed in future +releases.
+char_traits
removed from fixed_string
¶
+During the same SG16 meeting, the room was strongly against providing char_traits
for
+fixed_string
. This is why char_traits
support was removed in this release
+( breaking change
).
Improved units' text output¶
+In the previous release, we introduced common unit abstraction. Initially, all its components
+were printed in parenthesis which contained a list of all the scaled units separated with =
.
+After some feedback, we decided to change it to a new syntax.
For example, the following:
+std::cout << 1 * km + 1 * mi << "\n";
+std::cout << 1 * nmi + 1 * mi << "\n";
+std::cout << 1 * km / h + 1 * m / s << "\n";
+
will print:
+As we can see above, the scaled units output changed as well. Now, the entire scaled unit is
+encapsulated within [...]
brackets to better denote its scope.
Additionally, small magnitudes of scaled units do not use the power of 10
, and also scaled
+units do not have a composition priority over the derived units anymore.
As a result of those changes, the following:
+ +prints:
+ +One more change that we can see above is that litre now use 'L' instead of 'l' for its symbol.
+The latter one too often is confused with the number 1
.
The next improvement adds proper formatting support for magnitudes. All of the formatting options +that were working before for the unit symbols now also work for magnitudes.
+For example:
+using enum text_encoding;
+using enum unit_symbol_solidus;
+using usf = unit_symbol_formatting;
+
+static_assert(unit_symbol(mag<1> / (mag<2> * mag<pi>)*metre) == "[2⁻¹ 𝜋⁻¹ m]");
+static_assert(unit_symbol<usf{.solidus = always}>(mag<1> / (mag<2> * mag<pi>)*metre) == "[1/(2 𝜋) m]");
+static_assert(unit_symbol<usf{.encoding = portable, .solidus = always}>(mag<1> / (mag<2> * mag<pi>)*metre) ==
+ "[1/(2 pi) m]");
+
As we can see above, the library also learned how to print magnitude symbols. This required
+a change in the mag_constant
definition. Now, it takes a magnitude symbol and has to be final
+like for other similar types in the library ( breaking change
):
inline constexpr struct pi final : mag_constant<symbol_text{u8"π", "pi"}, std::numbers::pi_v<long double>> {} pi;
+inline constexpr auto π = pi;
+
Unicode identifiers¶
+The example above introduced something interesting: a π
identifier for a variable. With the
+latest changes to the C++ language, we can officially use Unicode symbols as identifiers in
+the C++ code.
In this release, we've added Unicode identifiers support not only for π
magnitude constant
+but also for unit symbols.
Now we can type the following:
+This might make the source code easier to understand, but typing those identifiers can be tricky. +Sometimes, the best solution to type it might be a copy-paste approach. If we do not like this +idea, we can still use old portable identifiers for those as well.
+Convertibility with QuantityLike
and QuantityPointLike
entities¶
+In this release, we decided to fine-tune further the traits that customize the conversion between
+custom quantity and quantity point types and the ones provided with mp-units
+( breaking change
).
Previously, to_numerical_value
and from_numerical_value
returned a type wrapped in a special
+tag type describing the conversion type (explicit or implicit).
This was a novel and experimental approach. Finally, we decided not to do it and used a bit more
+verbose but a more standard solution. From now on, we need to provide two additional static data
+members of type bool
:
-
+
explicit_import
-true
means that the conversion to the mp-units abstraction is explicit,
+explicit_export
-true
means that the conversion from the mp-units abstraction is + explicit.
+
template<>
+struct mp_units::quantity_point_like_traits<Timestamp> {
+ static constexpr auto reference = si::second;
+ static constexpr auto point_origin = default_point_origin(reference);
+ static constexpr bool explicit_import = false;
+ static constexpr bool explicit_export = true;
+ using rep = decltype(Timestamp::seconds);
+
+ static constexpr rep to_numerical_value(Timestamp ts)
+ {
+ return ts.seconds;
+ }
+
+ static constexpr Timestamp from_numerical_value(rep v)
+ {
+ return Timestamp(v);
+ }
+};
+
template<>
+struct mp_units::quantity_point_like_traits<Timestamp> {
+ static constexpr auto reference = si::second;
+ static constexpr auto point_origin = default_point_origin(reference);
+ using rep = decltype(Timestamp::seconds);
+
+ static constexpr convert_implicitly<rep> to_numerical_value(Timestamp ts)
+ {
+ return ts.seconds;
+ }
+
+ static constexpr convert_explicitly<Timestamp> from_numerical_value(rep v)
+ {
+ return Timestamp(v);
+ }
+};
+
Symbolic constants implementation should be implementation-defined¶
+In the process of writing API Reference, we decided to hide all the metadata associated with
+symbolic constants - tag types used to define units, dimensions, quantity specification, etc.
+( breaking change
).
All the types and values exposed by such types are needed only in the implementation details +of the library. Users should not need them. Hiding those and making them +implementation-defined gives other vendors the freedom to choose different ways to implement +features of this library in their codebases.
+Important
+Based on Hyrum's Law some users may depend on this +information already, and this release will break their code.
+If that is the case for you, we would love to hear about your use case and its rationale. +It may mean that we should either:
+-
+
- extend the library's functionality to support your use case out of the box and keep those + members hidden, +
- restore public visibility of such members and enforce this in the API Reference so that all + the users of various library implementations may use them in the same way as you. +