--- date: 2023-12-09 authors: - mpusz categories: - Releases --- # mp-units 2.1.0 released! **A new product version can be obtained from [GitHub](https://github.com/mpusz/mp-units/releases/tag/v2.1.0) and [Conan](https://conan.io/center/recipes/mp-units?version=2.1.0).** The list of the most significant changes introduced by the new version can be found in our [Release Notes](../../release_notes.md#2.1.0). We will also describe the most important of them in this post. ## No more parenthesis while creating quantities with derived units The V2 design introduced a way to create a `quantity` by multiplying a raw value and a unit: ```cpp quantity q1 = 42 * m; ``` However, this meant that when we wanted to create a quantity having a derived unit, we had to put parenthesis around the unit equation or create a custom value of the named unit: ```cpp quantity q2 = 60 * (km / h); constexpr auto kmph = km / h; quantity q3 = 60 * kmph; quantity q4 = 50 * (1 / s); ``` With the new version, we removed this restriction, and now we can type: ```cpp quantity q5 = 60 * km / h; quantity q6 = 50 / s; ``` As a side effect, we introduced a **breaking change**. We can't use the following definition of hertz anymore: ```cpp inline constexpr struct hertz : named_unit<"Hz", 1 / second, kind_of> {} hertz; ``` and have to type either: ```cpp inline constexpr struct hertz : named_unit<"Hz", one / second, kind_of> {} hertz; ``` or ```cpp inline constexpr struct hertz : named_unit<"Hz", inverse(second), kind_of> {} hertz; ``` To be consistent, we applied the same change to the dimensions and quantity specifications definitions. Now, to define a _frequency_ we have to type: === "C++23" ```cpp inline constexpr struct frequency : quantity_spec {} frequency; ``` === "C++20" ```cpp inline constexpr struct frequency : quantity_spec {} frequency; ``` === "Portable" ```cpp QUANTITY_SPEC(frequency, inverse(period_duration)); ``` ## `make_xxx` factory functions replaced with two-parameter constructors In the initial version of the V2 framework, if someone did not like the multiply syntax to create a `quantity` we provided the `make_quantity()` factory function. A similar approach was used for `quantity_point` creation. This version removes those (**breaking change**) and introduces two parameter constructors: ```cpp quantity q(42, si::metre); quantity_point qp(q, mean_sea_level); ``` The above change encourages a better design and results in a terser code. ## Improved definitions of becquerel, gray, and sievert In the initial V2 version, we lacked the definitions of the atomic and nuclear physics quantities, which resulted in simplified and unsafe definitions of becquerel, gray, and sievert units. We still do not model most of the quantities from this domain, but we've added the ones that are necessary for the definition of those units. Thanks to the above, the following expressions will not compile: ```cpp quantity q1 = 1 * Hz + 1 * Bq; quantity q2 = 42 * Gy; ``` ## Compatibility with other libraries redesigned Another significant improvement in this version was redesigning the way we provide compatibility with other similar libraries. The interfaces of `quantity_like_traits` and `quantity_point_like_traits` were changed and extended to provide conversion not only from but also to entities from other libraries (**breaking change**). We've also introduced an innovative approach that allows us to specify if such conversions should happen implicitly or if they need to be forced explicitly. More on this subject can be found in the [Interoperability with Other Libraries](../../users_guide/use_cases/interoperability_with_other_libraries.md) chapter. ## Point origins can now be derived from each other Previously, each class derived from `absolute_point_origin` was considered a unique independent point origin. On the other hand, it was OK to derive multiple classes from the same `relative_point_origin`, and those were specifying the same point in the domain. We found this confusing and limiting. This is why, in this version, the `absolute_point_origin` uses a CRTP idiom to be able to detect between points that should be considered different from the ones that should be equivalent. *[CRTP]: Curiously Recurring Template Pattern If we derive from the same instantiation of `absolute_point_origin` we end up with an equivalent point origin. This change allows us to provide different names for the same temperature points: ```cpp inline constexpr struct absolute_zero : absolute_point_origin {} absolute_zero; inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin; inline constexpr struct ice_point : relative_point_origin {} ice_point; inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius; ``` Please note that this is a **breaking change** as well. ## Unit symbol text can now be properly used at runtime The interface of the previous definition of `unit_symbol` function allowed the use of the returned buffer only at compile-time. This was too limiting as users often want to use unit symbols at runtime (e.g., print them to the console). The new version redesigned the interface of this function (**breaking change**) to return a buffer that can be properly used at both compilation and runtime: ```cpp std::string_view unit1 = unit_symbol(m / s); std::cout << unit1 << "\n"; // m/s std::string_view unit2 = unit_symbol<{.solidus = unit_symbol_solidus::never}>(m / s); std::cout << unit2 << "\n"; // m s⁻¹ ```