Skip to content

What's new in mp-units 2.0?

After a year of hard work, we've just released mp-units 2.0.0. It can be obtained from GitHub and Conan.

The list of the most significant changes introduced by the new version can be found in our Release Notes. We will also describe some of them in this post.

Why 2.0 if 1.0 was never released?

Version 2 of the mp-units project is a huge change and a new quality for the users. We did not want to pretend that 2.0 is an evolutionary upgrade of the previous version of the project. It feels like a different product.

We could start a new repo named "mp-units-v2" similarly to range-v3 but we decided not to go this path. We kept the same repo and made the scope of the changes and potential breakage explicit with a drastic bump in the project version.

What has changed?

The answer is "nearly everything". The whole library and its documentation were rewritten nearly from scratch.

Here are the significant changes that the users can observe:

  • Repository name

    If you didn't notice, the repository name was changed from "mpusz/units" to "mpusz/mp-units".

  • Header files content and layout

    Previously, all the header files resided in the include/units directory. Now, they can be found in include/mp-units. The project file tree was significantly changed as well. Many files were moved to different subdirectories or renamed.

  • Namespace

    Previously, all the definitions were provided in the units namespace, and now they are in the mp_units one.

  • Abstractions, interfaces, definitions

    The interfaces of all of the types were refactored. We got unit symbols and a new way to construct a quantity and quantity_point. The readability of the generated types was improved thanks to the introduction of expression templates. Nearly all of the template arguments are now passed by values thanks to class NTTP extensions in C++20. As a result, unit definitions are much easier and terser. Also, the V2 has a powerful ability to model systems of quantities and provides definitions for many ISQ quantities.

  • Conan 2.0

    Also, now we support Conan 2.0, which provides an updated way of handling dependencies.

What is gone?

Some cornerstones of the initial design did not prove in practice and were removed while we moved to version 2.

The downcasting facility

The first and the most important of such features was removing the downcasting facility. This feature is still a powerful metaprogramming technique that allows users to map long class template instantiations to nicely named, short, and easy-to-understand user's strong types.

Such mapping works perfectly fine for 1-to-1 relationships. However, we often deal with N-to-1 connections in the quantities and units domain. Here are only a few such examples:

  • work and torque have the same dimension \(L^2MT^{-2}\),
  • becquerel and hertz have the same definition of \(s^{-1}\),
  • litre and cubic decimetre have the same factor.

In the above examples, multiple entities "wanted" to register different names for identical class template instantiations, resulting in compile-time errors. We had to invent some hacks and workarounds to make it work, but we were never satisfied with the outcome.

Additionally, this facility could easily lead to ODR violations or provide different results depending on which header files were included in the translation units. This was too vulnerable to be considered a good practice here.

No UDLs anymore

Over the years, we have learned that UDLs are not a good solution. More information on this subject can be found in the Why don't we use UDLs to create quantities? chapter.

No construction of a quantity from a raw value

To improve safety, we no longer allow the construction of quantities from raw values. In the new design, we always need to explicitly specify a unit to create a quantity:

quantity q1 = 42 * m;
quantity<si::metre> = 2 * km;
quantity q3(42, si::metre);

The previous approach was reported to be error-prone under maintenance. More on this subject can be found in the Why can't I create a quantity by passing a number to a constructor? chapter.

New look and feel

Here is a concise example showing you the new look and feel of the library:

#include <mp-units/format.h>
#include <mp-units/systems/isq/isq.h>
#include <mp-units/systems/si/si.h>
#include <format>

using namespace mp_units;
using namespace mp_units::si::unit_symbols;

quantity<isq::speed[m / s]> avg_speed(quantity<si::metre> d,
                                      quantity<si::second> t)
{ return d / t; }

int main()
{
  auto speed = avg_speed(220 * km, 2 * h);
  std::println("{}", speed);  // 30.5556 m/s
}

All of the changes we provided, although breaking ones, resulted in much better, easier, and safer abstractions. These offer a new quantity on the market and hopefully will be appreciated by our users.

Please check our new documentation to learn about the latest version of the project and find out how to benefit from all the new cool stuff we have here.