Unitlib is a header-only C++ library designed to facilitate explicit handling of physical units in C++ programs to enforce unit correctness at compile time. It aims to provide a robust foundation for working with units in a type-safe manner, ensuring that unit-related errors can be caught early in the development process. The design philosophy of Unitlib is to offer clear and intuitive unit handling without getting in the way and maintaining minimal runtime overhead.

Features

Getting Started

To start using Unitlib in your project, include the provided header file in your C++ source files:

#include "Unitlib.h"

Make sure your compiler supports C++20, as Unitlib makes extensive use of C++20 features such as concepts and constexpr.

Usage

Defining Units

Use predefined unit types for SI units by stating their types or using literals:

using namespace Unitlib;

Meter length(2.0);
Second time(5.0);

using namespace Unitlib::Literals;
auto temperature = 1_K;
auto substance_amount = 1.0_mol;

You can create new Units with existing dimensions:

using Inch = Unit>;
    static_assert(Inch(1.0).get_value_in>() == 0.0254);

Create new dimensions by explicitly stating them in terms of SI base unit dimensions or by deriving them from existing dimensions:

using Velocity = Dimension<
    std::ratio<1>,  // Length
    std::ratio<0>,  // Mass
    std::ratio<-1>, // Time
    std::ratio<0>,  // Electric current
    std::ratio<0>,  // Temperature
    std::ratio<0>,  // Amount of substance
    std::ratio<0>>; // Luminous intensity

using Torque = MultiplyDimensions<Force, Length>;
using NewtonMeters = Unit<Torque, double>;
    

Performing Operations

Unitlib allows for natural arithmetic operations while ensuring type safety, even when converting between units of different dimensions:

auto area = length * length;        // Result is in square meters
auto velocity = length / time;      // Result is in meters per second

You can specifically check the resulting units:

// Check dimension and value type at compile time
unit_check<decltype(area), Area, double>(); 

Or always use literals and auto and worry about units only when defining inputs and querying the result:

auto flow_speed = 1_m/1_s;
auto characteristic_length = 1_m;
auto kinematic_viscosity = 1_m * 1_m/1_s;
auto reynolds_number = flow_speed * characteristic_length/kinematic_viscosity;
unit_check<decltype(reynolds_number), Dimensionless, double>();

Constrain template parameters

There is also a concept to constrain template parameters to be of specific Dimension:

template<typename U, typename L, typename v>
requires HasDimension<U, Velocity> && 
            HasDimension<L, Length> && 
            HasDimension<v, KinematicViscosity>
constexpr auto reynolds_number(
    const U& flow_speed, 
    const L& characteristic_length, 
    const v& kinematic_viscosity) {
    return flow_speed * characteristic_length / kinematic_viscosity;
}

Contributing

Contributions, suggestions, and feedback are highly welcome. Whether it's adding new units, improving the library's interface, or optimizing existing code, your input can help make Unitlib better.

Please install the pre-commit hook before committing any potential contributions, by performing this command in the repository root:

ln -s -f ../../hooks/pre-commit .git/hooks/pre-commit

This ensures that tests pass and the code is formatted consistently on each commit.