Skip to content

Comparison of Alternatives

There are plenty of other open source C++ units libraries, many quite well established. However, the tradeoffs required to use these libraries can be so significant that many people can’t or won’t use them. For example: the compiler errors may be inscrutable or overwhelming; the compilation process may become unacceptably slow; or, the required C++ standard may simply be too new for a user.

Au is an accessible, production-tested alternative. We provide a number of rare or outright novel features, with a small compile time footprint — and we’re compatible with every C++ version back to the mature and widely available C++14 standard. Key features include:

  • Fully unit-safe APIs, on both entry and exit.
  • The “safety surface”: conversions that adapt to the overflow risk based on both conversion magnitude, and storage type.
  • Highly composable “quantity maker” APIs make it easy to both compose new units, and apply unit prefixes, on the fly.
  • Human-readable and concise compiler errors, via strong typenames for units.
  • The Zero type: novel, fluent handling of construction, comparison, and sign handling for quantities.
  • Ease of migration (both to and from Au): with minimal setup, we support bidirectional implicit conversions with equivalent types from any other units library.
  • Support for single-header-file delivery, but with easy customization of units and features to include.
  • Proven track record supporting embedded applications as first class citizens, via such features as our safe handling of integer Rep, treating all Reps on equal footing, and our easy ability to exclude expensive <iostream> support.
  • Intelligent, unit-aware functions for rounding and computing inverses.
  • Minimal friction by using a single, short namespace: everything’s in au::.

Detailed comparison matrices

Here’s a more detailed comparison to the most prominent alternatives. We’ll use the following legend1:

Legend Lacks feature /
poor support
Fair /
basic support
Good /
solid support
Best support
(of libraries considered here)

Obtaining the library

These are the first criteria to consider. They will tell you whether you can even use the library at all, and if so, how hard it will be to obtain.

Boost nholthaus mp-units Au
C++ Version Compatibility

The minimum C++ standard required to use the library.

C++98 or C++03
(unclear which, but best in either case)
C++14 C++20 C++14
Ease of Acquisition

Ease of including this library in projects using a wide variety of build environments

Part of boost Single, self-contained header First class conan support; available on vcpkg

Supports single-header delivery, with features:

  • Easy to customize units and I/O support
  • Version-stamped for full reproducibility

Note

These ratings are written with all users and projects in mind. Keep in mind that what matters for you is your project.

For example: mp-units gets low accessibility ratings because of its steep C++20 minimum requirement, and its dependence on a package manager to make the installation easy. However, if your project is already compatible with C++20, and already uses conan, then these “low” ratings would be completely irrelevant for you.

Generic developer experience

Next: how will this library change the generic developer experience? Leaving aside any library features, conventions, or implementation strategies, there are two main impacts to developer experience.

  1. Your program will take longer to compile, because the compiler is doing more work to produce essentially the same program.

  2. You will get more compiler errors that developers will need to understand and fix.

These costs can bring significant benefits, but we still want them to be as small as possible.

Boost nholthaus mp-units Au
Compilation Speed

The extra time the library adds to compiling a translation unit, compared to no units library.

  • Poor: typically adds several seconds per translation unit
  • Fair: enough that end users tend to notice
  • Good: not "subjectively noticeable"
Very slow, but can be greatly improved by removing I/O support and most units Possibly "best", but will need to assess all libraries on the same code
Compiler Error Readability

The ability to understand errors when the library catches a mistake it was designed to catch.

  • Poor: Excessively long, nested types
  • Fair: Short, but dimension names lacking
  • Good: Brief typenames with user-facing unit names
Infamously challenging Positional dimensions Pioneered strong typedefs for units

Library features

At this point, you’ve assessed:

  • whether you can use each library at all;
  • how hard it will be to add to your project;
  • and, what costs you’ll pay in developer experience if you do.

Now we’re ready to compare the libraries “as units libraries” — that is, in terms of their core features.

Boost nholthaus mp-units Au
Conversion Safety

Guarding against unit conversions that are likely to produce large errors.

(For example: we can convert an integer number of feet to inches, but not vice versa.)

Integer Reps unsafe Policy consistent with std::chrono library Automatically adapts to level of overflow risk
Unit Safety

The ability to judge the unit-correctness of every individual line of code by inspection, in isolation.

  • Fair: can achieve indirectly, by casting to known type before retrieving value.
  • Good: provide unit-safe interfaces.
Only contains unit-safe interfaces
Low Friction

How easy it is to develop with the library. Criteria include:

  • Headers: few, or easily guessable
  • Simple namespace structure
  • Reasonable, safe implicit conversions
  • Single file is very easy
  • User-friendly API typenames (meter_t, ...)
  • Namespaces add verbosity, and friction (for example, math:: namespace prevents ADL)
  • Namespaces: just one, and it's short
  • Includes: either single-header, or easily-guessable header per unit
Composability

The ability to fluently combine the abstractions for units and prefixes to form new units on the fly.

Prefix only No Quantity References compose; prefixes don't QuantityMaker and PrefixApplier APIs
Mixed-Rep Support

The ease of freely mixing different storage types ("Reps") in the same program.

Possible, but user-facing types use a global "preferred" Rep.
Generic Dimensions

The ability to write (template) functions that operate on any dimensionally consistent inputs.

(For example, a function that takes any length and time quantities, and returns the appropriate speed quantity.)

Generic templates, constrained with traits Generic templates, constrained with traits Concepts excel here Currently clunky. Could be better by adding concepts in extra C++20-only file, without compromising C++14 support.
Extensibility

How easy it is to add new units, dimensions, or systems.

Can add new units and dimensions Can even handle, e.g., systems of "natural" units Can add new units and dimensions
Ease of Migration

Support for two migration use cases:

  • From "no units" to this library
  • Between this library and another units library (either direction)
No interop with other units libraries No interop with other units libraries quantity_like_traits "Equivalent types" feature gives more API compatibility
Point Types

Support for "point-like" quantities, also known as "affine space types".

absolute wrapper for unit Optional "offset" for units, but can't distinguish quantity from point.
Magnitudes

The features of the representation for different units' sizes. Key features include:

  • Irrational numbers (such as \(\pi\))
  • Powers (robust against overflow)
  • Roots (exact representations)
Close: lacks only irrationals, basis, and instance arithmetic. Ahead of its time! Uses ratio plus "pi powers": good angle handling, but vulnerable to overflow Full support for Magnitudes Formerly, Au alone was best, but we shared Magnitudes with mp-units
Embedded Friendliness

Support common embedded use cases. Key examples include:

  • Flexibility in the Rep (usually a variety of integral types, and perhaps float, but rarely double).
  • The easy ability to exclude <iostreams>.
Assumed to be good, based on mixed-Rep support Can trim by excluding <iostream>, but integer-Rep support is poor. Assumed to be good, based on mixed-Rep support Best choice of all:
  • No "preferred" Rep.
  • Safe integer operations.
User-defined literals (UDLs)

Concise expressions such as `3_m` for "3 meters", or some comparable alternative.

  • Flexibility in the Rep (usually a variety of integral types, and perhaps float, but rarely double).
  • The easy ability to exclude <iostreams>.
UDLs UDLs and Quantity References Planned to add: #43
Rep Variety

The range of different storage types ("Reps") permitted.

  • Poor: only 1 or 2 types
  • Fair: all built-in numeric types
  • Good: also support custom numeric types
Supports custom numeric types Effectively floating-point only (integer types unsafe) Well defined Representation concept
  • Mature support for is_arithmetic Rep
  • Experimental support for custom Rep
  • No constraints yet (#52)
Zero

Quantity support for constructing from, and comparing with, 0: the only number which is meaningful for every unit. (Includes facilities for working with quantity signs.)

Guidance: use default constructor to construct, but no special facility for comparison Supports copysign(), but no special construction or comparison Has q::zero() member, but no special construction or comparison Can use ZERO to construct or compare any quantity
Angles

First-class support for angular quantities, including degrees and radians.

Curiously imprecise pi value
Non-linear scales (such as dB)

Support for logarithmic "units", such as decibels or nepers

Plan to support someday; see #41.
"Kind" Types

Support for distinguishing different "kinds" of the same dimension, such as a length from a width.

No plans to support.
Explicit Systems of Measurement

Support for different systems, each with their own (possibly incompatible) collection of dimensions.

Single, implicit global system Single, implicit global system. (Intentional design tradeoff: reduces learning curve, and makes compiler errors shorter.)
Units as types

Types that represent abstract units (clearly distinct from quantities of that unit).

Types exist, but conflated with quantity names Can form instances and do arithmetic
Macro Usage

Avoidance of macros, especially in user-facing code.

Present in user-facing APIs Present in user-facing APIs Confined to outer compatibility layer No macros

  1. Users may have expected a “traffic light” style, green/yellow/red color scheme. However, these traditional color schemes have poor accessibility for colorblind readers. The present color scheme was designed to be colorblind-friendly.