Skip to content

Quick Start

This chapter provides a quick introduction to get you started with mp-units. Much more details can be found in our User's Guide.

Quantities

A quantity is a concrete amount of a unit representing a quantity type of a specified dimension with a specific representation. It is represented in the library with a quantity class template.

The SI Brochure says:

SI Brochure

The value of the quantity is the product of the number and the unit. The space between the number and the unit is regarded as a multiplication sign (just as a space between units implies multiplication).

Following the above, the value of a quantity in the mp-units library is created by multiplying a number with a predefined unit:

import mp_units;

using namespace mp_units;

quantity q = 42 * si::metre / si::second;
#include <mp-units/systems/si.h>

using namespace mp_units;

quantity q = 42 * si::metre / si::second;

Info

In case someone doesn't like the multiply syntax or there is an ambiguity between operator* provided by this and other libraries, there are two other ways to create a quantity:

  1. delta construction helper:

    import mp_units;
    
    using namespace mp_units;
    
    quantity q = delta<si::metre / si::second>(42);
    
    #include <mp-units/systems/si.h>
    
    using namespace mp_units;
    
    quantity q = delta<si::metre / si::second>(42);
    
  2. A two-parameter constructor:

    import mp_units;
    
    using namespace mp_units;
    
    quantity q{42, si::metre / si::second};
    
    #include <mp-units/systems/si.h>
    
    using namespace mp_units;
    
    quantity q{42, si::metre / si::second};
    

The above creates an instance of quantity<derived_unit<si::metre, per<si::second>>{}, int>. The same can be obtained using optional unit symbols:

import mp_units;

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

quantity q = 42 * m / s;
#include <mp-units/systems/si.h>

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

quantity q = 42 * m / s;

Important

Unit symbols introduce a lot of short identifiers into the current scope, which may cause naming collisions with unrelated but already existing identifiers in the code base. This is why unit symbols are opt-in and typically should be imported only in the context where they are being used (e.g., function scope).

A user has several options here to choose from depending on the required scenario and possible naming conflicts:

Explicitly "import" all of the symbols of a specific system of units from a dedicated unit_symbols namespace with a using-directive:

using namespace mp_units;

void foo(double speed_m_s)
{
  // imports all the SI symbols at once
  using namespace si::unit_symbols;
  quantity speed = speed_m_s * m / s;
  // ...
}

Note

This solution is perfect for small and isolated scopes but can cause surprising issues when used in larger scopes or when used for the entire program namespace.

There are 29 named units in SI, and each of them has many prefixed variations (e.g., ng, kcd, ...). It is pretty easy to introduce a name collision with those.

Selectively bring only the required and not-conflicting symbols with using-declarations:

using namespace mp_units;

void foo(double N)
{
  // 'N' function parameter would collide with the SI symbol for Newton, so we only bring what we need
  using si::unit_symbols::m;
  using si::unit_symbols::s;
  quantity speed = N * m / s;
  // ...
}

Specify a custom not conflicting unit identifier for a unit:

using namespace mp_units;

void foo(double speed_m_s)
{
  // names of some local variables are conflicting with the symbols we want to use
  auto m = ...;
  auto s = ...;

  constexpr Unit auto mps = si::metre / si::second;
  quantity speed = speed_m_s * mps;
}

Full unit names are straightforward to use and often provide the most readable code:

using namespace mp_units;

void foo(double m, double s)
{
  quantity speed = m * si::metre / (s * si::second);
  // ...
}

Quantities of the same kind can be added, subtracted, and compared to each other:

import mp_units;

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

static_assert(1 * km + 50 * m == 1050 * m);
#include <mp-units/systems/si.h>

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

static_assert(1 * km + 50 * m == 1050 * m);

Various quantities can be multiplied or divided by each other:

static_assert(140 * km / (2 * h) == 70 * km / h);

Note

In case you wonder why this library does not use UDLs to create quantities, please check our FAQ.

Quantity points

The quantity point specifies an absolute quantity with respect to an origin. If no origin is provided explicitly, an implicit one will be provided by the library.

Together with quantities, they model The Affine Space.

Quantity points should be used in all places where adding two values is meaningless (e.g., temperature points, timestamps, altitudes, readouts from the car's odometer, etc.).

The set of operations that can be done on quantity points is limited compared to quantities. This introduces an additional type-safety.

#include <print>
import mp_units;

int main()
{
  using namespace mp_units;
  using namespace mp_units::si::unit_symbols;
  using namespace mp_units::usc::unit_symbols;

  quantity_point temp = point<deg_C>(20.);
  std::println("Temperature: {} ({})",
               temp.quantity_from_zero(),
               temp.in(deg_F).quantity_from_zero());
}
#include <mp-units/format.h>
#include <mp-units/systems/si.h>
#include <mp-units/systems/usc.h>
#include <print>

int main()
{
  using namespace mp_units;
  using namespace mp_units::si::unit_symbols;
  using namespace mp_units::usc::unit_symbols;

  quantity_point temp = point<deg_C>(20.);
  std::println("Temperature: {} ({})",
               temp.quantity_from_zero(),
               temp.in(deg_F).quantity_from_zero());
}

The above outputs:

Temperature: 20 ℃ (68 ℉)

Info

Check The Affine Space chapter to learn more about quantity points.