Unit Conversion and Dimensional Analysis Library 3.6.1
A compile-time, header-only C++23 dimensional-analysis library
Loading...
Searching...
No Matches
kind.h File Reference

Opt-in affine wrappers: units::absolute<U> (a point on a scale, carries the unit's datum) and units::delta<U> (an offset-free amount). More...

#include <units/core.h>
#include <algorithm>
#include <cstddef>
#include <ostream>
#include <string>
Include dependency graph for kind.h:

Go to the source code of this file.

Classes

struct  units::traits::is_absolute< T >
 Trait which tests whether T is an absolute<U> point wrapper. More...
struct  units::traits::is_delta< T >
 Trait which tests whether T is a delta<U> amount wrapper. More...
struct  units::traits::is_kind< T >
 Trait which tests whether T is a string-tagged kind<Tag, U>. More...
class  units::affine::absolute< U >
 A point on a (possibly affine) scale — carries the unit's datum. More...
class  units::affine::delta< U >
 An amount of a quantity — offset-free (no datum). More...
struct  units::affine::fixed_string< N >
 A compile-time string usable as a non-type template parameter (the tag of a kind/of). More...
class  units::affine::basic_kind< Tag, U >
 A quantity distinguished by a string TAG — a "kind of quantity" that shares a unit and a dimension with others but is semantically distinct (radial vs. More...
struct  std::hash< units::affine::absolute< U > >
 Hash a point by the hash of its wrapped quantity (two equal points hash equally). More...
struct  std::hash< units::affine::delta< U > >
 Hash an amount by the hash of its wrapped quantity. More...
struct  std::hash< units::affine::basic_kind< Tag, U > >
 Hash a kind by the hash of its wrapped quantity (the tag does not participate — equal values hash equally). More...
struct  std::numeric_limits< units::affine::absolute< U > >
 Numeric limits of a point: the wrapped unit's limits, re-wrapped as points. More...
struct  std::numeric_limits< units::affine::delta< U > >
 Numeric limits of an amount: the wrapped unit's limits, re-wrapped as amounts. More...
struct  std::numeric_limits< units::affine::basic_kind< Tag, U > >
 Numeric limits of a kind: the wrapped unit's limits, re-wrapped as the same kind (tag preserved). More...

Namespaces

namespace  units
 Unit Conversion Library namespace.
namespace  units::traits
 namespace representing type traits which can access the properties of types provided by the units library.
namespace  std
 STL namespace.

Concepts

concept  units::AbsoluteType
 Concept satisfied by any absolute<U> point wrapper.
concept  units::DeltaType
 Concept satisfied by any delta<U> amount wrapper.
concept  units::KindType
 Concept satisfied by any string-tagged kind<Tag, U>.

Typedefs

template<UnitType U>
using units::detail::delta_unit_t
 The offset-free counterpart of a unit: same dimension, scale, and pi factor, but translation stripped.
template<UnitType U, UnitType V>
using units::detail::absolute_result_unit_t = std::conditional_t<is_losslessly_point_convertible_unit<V, U>, U, traits::replace_underlying_t<U, floating_point_promotion_t<typename traits::unit_traits<U>::underlying_type>>>
 The result unit of an absolute (point) operator: keep the LHS unit, promote the underlying only when a point conversion of the RHS into it would be lossy (ratio OR datum).
template<UnitType U, UnitType V>
using units::detail::delta_result_unit_t
 The result unit of a delta (amount) operator: keep the LHS unit, promote the underlying only when the RHS amount cannot convert into it losslessly.
template<affine::fixed_string Tag, UnitType U>
using units::kind = affine::basic_kind<Tag, U>
 The preferred user-facing spelling of a string-tagged quantity kind: units::kind<"radial", meters<double>>.

Functions

template<std::size_t N>
 units::fixed_string (const char(&)[N]) -> fixed_string< N >
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator- (const absolute< U > &lhs, const absolute< V > &rhs) noexcept
 point - point -> delta, kept in the LHS unit (the datum offsets cancel).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator+ (const absolute< U > &lhs, const delta< V > &rhs) noexcept
 point + delta -> point (move the point up by a relative amount), kept in the LHS point's unit.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<V, U>
constexpr auto units::operator+ (const delta< V > &lhs, const absolute< U > &rhs) noexcept
 delta + point -> point (commutative form).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator- (const absolute< U > &lhs, const delta< V > &rhs) noexcept
 point - delta -> point (move the point down by a relative amount), kept in the LHS point's unit.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator+ (const delta< U > &lhs, const delta< V > &rhs) noexcept
 delta + delta -> delta, kept in the LHS unit (underlying promoted only if the RHS would narrow it).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator- (const delta< U > &lhs, const delta< V > &rhs) noexcept
 delta - delta -> delta, kept in the LHS unit (underlying promoted only if the RHS would narrow it).
template<UnitType U>
constexpr delta< U > units::operator- (const delta< U > &d) noexcept
 Unary negation of a delta (an amount can be negated; a point cannot).
template<UnitType U, ArithmeticType T>
constexpr auto units::operator* (const delta< U > &lhs, T rhs) noexcept
 delta scaled by a bare number -> delta.
template<UnitType U, ArithmeticType T>
constexpr auto units::operator* (T lhs, const delta< U > &rhs) noexcept
template<UnitType U, ArithmeticType T>
constexpr auto units::operator/ (const delta< U > &lhs, T rhs) noexcept
 delta divided by a bare number -> delta (promotes like the wrapped unit's own operator/).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr absolute< U > & units::operator+= (absolute< U > &lhs, const delta< V > &rhs) noexcept
 Compound move of a point by a delta.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr absolute< U > & units::operator-= (absolute< U > &lhs, const delta< V > &rhs) noexcept
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr delta< U > & units::operator+= (delta< U > &lhs, const delta< V > &rhs) noexcept
 Compound add of a delta into a delta, in place (the lhs keeps its unit; the rhs is scale-converted).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr delta< U > & units::operator-= (delta< U > &lhs, const delta< V > &rhs) noexcept
template<UnitType U, ArithmeticType T>
constexpr delta< U > & units::operator*= (delta< U > &lhs, T rhs) noexcept
 Compound scale of a delta by a bare number, in place (the underlying stays the lhs type, so the scaled result is assigned back through the lhs unit — an integer delta scaled by an integer stays integer, matching the plain unit's own operator*=).
template<UnitType U, ArithmeticType T>
constexpr delta< U > & units::operator/= (delta< U > &lhs, T rhs) noexcept
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr bool units::operator== (const absolute< U > &lhs, const absolute< V > &rhs) noexcept
 Compare two points (the datum is applied on each side as it unwraps to the plain unit).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr std::partial_ordering units::operator<=> (const absolute< U > &lhs, const absolute< V > &rhs) noexcept
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr bool units::operator== (const delta< U > &lhs, const delta< V > &rhs) noexcept
 Compare two deltas.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr std::partial_ordering units::operator<=> (const delta< U > &lhs, const delta< V > &rhs) noexcept
template<UnitType U>
std::ostream & units::operator<< (std::ostream &os, const absolute< U > &obj)
 Stream a point: its wrapped quantity, unmarked.
template<UnitType U>
std::ostream & units::operator<< (std::ostream &os, const delta< U > &obj)
 Stream a delta: a leading delta marker, then its wrapped quantity.
template<UnitType U>
std::string units::to_string (const absolute< U > &obj)
 String form of a point: its wrapped quantity, unmarked.
template<UnitType U>
std::string units::to_string (const delta< U > &obj)
 String form of a delta: a leading delta marker, then its wrapped quantity.
template<UnitType U>
constexpr auto units::abs (const delta< U > &d) noexcept
 Absolute magnitude of a delta (|amount|), promoting like the wrapped unit's units::abs.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::min (const delta< U > &lhs, const delta< V > &rhs) noexcept
 The smaller of two deltas, kept in the LHS unit (scale-only reconciliation of the rhs).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::max (const delta< U > &lhs, const delta< V > &rhs) noexcept
 The larger of two deltas, kept in the LHS unit (scale-only reconciliation of the rhs).
template<UnitType U, UnitType V, UnitType W>
requires (traits::is_same_dimension_unit_v<U, V> && traits::is_same_dimension_unit_v<U, W>)
constexpr auto units::clamp (const delta< U > &value, const delta< V > &lo, const delta< W > &hi) noexcept
 Clamp a delta into [lo, hi], kept in the value's LHS unit.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::min (const absolute< U > &lhs, const absolute< V > &rhs) noexcept
 The smaller of two points, kept in the LHS unit (affine reconciliation of the rhs).
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::max (const absolute< U > &lhs, const absolute< V > &rhs) noexcept
 The larger of two points, kept in the LHS unit (affine reconciliation of the rhs).
template<UnitType U, UnitType V, UnitType W>
requires (traits::is_same_dimension_unit_v<U, V> && traits::is_same_dimension_unit_v<U, W>)
constexpr auto units::clamp (const absolute< U > &value, const absolute< V > &lo, const absolute< W > &hi) noexcept
 Clamp a point into [lo, hi], kept in the value's LHS unit.
template<UnitType U, ArithmeticType T>
constexpr auto units::operator* (const absolute< U > &lhs, T) noexcept
 Scaling or dividing a POINT is meaningless — a point has no magnitude; only a delta (an amount) scales.
template<UnitType U, ArithmeticType T>
constexpr auto units::operator* (T, const absolute< U > &rhs) noexcept
template<UnitType U, ArithmeticType T>
constexpr auto units::operator/ (const absolute< U > &lhs, T) noexcept
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator/ (const absolute< U > &lhs, const absolute< V > &) noexcept
 Dividing a POINT by a POINT is meaningless — there is no ratio of two absolute positions.
template<UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator+ (const absolute< U > &lhs, const absolute< V > &) noexcept
 Summing two POINTS is meaningless (the sum of two positions has no meaning); subtract them for a delta, or add a delta to move a point.
template<UnitType U, ArithmeticType T>
constexpr auto units::operator+ (const delta< U > &lhs, T) noexcept
 A delta/absolute does not combine with a BARE NUMBER — an amount adds an amount, a point moves by an amount.
template<UnitType U, ArithmeticType T>
constexpr auto units::operator- (const delta< U > &lhs, T) noexcept
template<UnitType U, ArithmeticType T>
constexpr auto units::operator+ (const absolute< U > &lhs, T) noexcept
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator+ (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 kind + kind (same tag) -> kind, kept in the LHS unit.
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator- (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 kind - kind (same tag) -> kind, kept in the LHS unit.
template<fixed_string Tag, UnitType U>
constexpr basic_kind< Tag, U > units::operator- (const basic_kind< Tag, U > &k) noexcept
 Unary negation of a kind (keeps the tag).
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr auto units::operator* (const basic_kind< Tag, U > &lhs, T rhs) noexcept
 kind scaled by a bare number -> kind (same tag), promoting like the wrapped unit's own operator*.
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr auto units::operator* (T lhs, const basic_kind< Tag, U > &rhs) noexcept
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr auto units::operator/ (const basic_kind< Tag, U > &lhs, T rhs) noexcept
 kind divided by a bare number -> kind (same tag).
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::operator/ (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 The ratio of two SAME-tag kinds is a plain dimensionless quantity — the tag cancels, exactly as the ratio of two lengths is a number.
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr basic_kind< Tag, U > & units::operator*= (basic_kind< Tag, U > &lhs, T rhs) noexcept
 Compound scale of a same-tag kind by a bare number, in place (mirrors delta's *=//=).
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr basic_kind< Tag, U > & units::operator/= (basic_kind< Tag, U > &lhs, T rhs) noexcept
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr basic_kind< Tag, U > & units::operator+= (basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 Compound add/subtract of a same-tag kind, in place (the rhs is converted to the lhs unit).
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr basic_kind< Tag, U > & units::operator-= (basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr bool units::operator== (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 Compare two kinds of the SAME tag; the wrapped plain units compare (inheriting the core's value-based, signedness-safe integer comparison).
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr std::partial_ordering units::operator<=> (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
template<fixed_string TagL, fixed_string TagR, UnitType U, UnitType V>
requires (!(TagL == TagR))
constexpr auto units::operator+ (const basic_kind< TagL, U > &, const basic_kind< TagR, V > &) noexcept
template<fixed_string TagL, fixed_string TagR, UnitType U, UnitType V>
requires (!(TagL == TagR))
constexpr auto units::operator- (const basic_kind< TagL, U > &, const basic_kind< TagR, V > &) noexcept
template<fixed_string TagL, fixed_string TagR, UnitType U, UnitType V>
requires (!(TagL == TagR))
constexpr bool units::operator== (const basic_kind< TagL, U > &, const basic_kind< TagR, V > &) noexcept
template<fixed_string Tag, UnitType U, UnitType Plain>
constexpr auto units::operator+ (const basic_kind< Tag, U > &lhs, const Plain &) noexcept
template<fixed_string Tag, UnitType U, UnitType Plain>
constexpr auto units::operator+ (const Plain &, const basic_kind< Tag, U > &rhs) noexcept
template<fixed_string Tag, UnitType U, UnitType Plain>
constexpr auto units::operator- (const basic_kind< Tag, U > &lhs, const Plain &) noexcept
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr auto units::operator+ (const basic_kind< Tag, U > &lhs, T) noexcept
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr auto units::operator+ (T, const basic_kind< Tag, U > &rhs) noexcept
template<fixed_string Tag, UnitType U, ArithmeticType T>
constexpr auto units::operator- (const basic_kind< Tag, U > &lhs, T) noexcept
template<fixed_string Tag, UnitType U>
std::ostream & units::operator<< (std::ostream &os, const basic_kind< Tag, U > &obj)
 Stream a kind: its tag in brackets, then its wrapped quantity (e.g. [radial] 5 m).
template<fixed_string Tag, UnitType U>
std::string units::to_string (const basic_kind< Tag, U > &obj)
 String form of a kind: its tag in brackets, then its wrapped value.
template<fixed_string Tag, UnitType U>
constexpr auto units::abs (const basic_kind< Tag, U > &k) noexcept
 Absolute magnitude of a kind (|value|), keeping the tag, promoting like the wrapped unit's units::abs.
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::min (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 The smaller of two same-tag kinds, kept in the LHS unit (the tag is preserved).
template<fixed_string Tag, UnitType U, UnitType V>
requires traits::is_same_dimension_unit_v<U, V>
constexpr auto units::max (const basic_kind< Tag, U > &lhs, const basic_kind< Tag, V > &rhs) noexcept
 The larger of two same-tag kinds, kept in the LHS unit (the tag is preserved).
template<fixed_string Tag, UnitType U, UnitType V, UnitType W>
requires (traits::is_same_dimension_unit_v<U, V> && traits::is_same_dimension_unit_v<U, W>)
constexpr auto units::clamp (const basic_kind< Tag, U > &value, const basic_kind< Tag, V > &lo, const basic_kind< Tag, W > &hi) noexcept
 Clamp a same-tag kind into [lo, hi], kept in the value's LHS unit.

Variables

template<UnitType From, UnitType To>
constexpr bool units::detail::is_losslessly_point_convertible_unit
 The result unit of a wrapper operator that keeps the LHS UNIT (the "LHS-unit tie-break"): the value stays expressed in U's unit so .value() reads intuitively (absolute<celsius> - absolute<fahrenheit> is a difference in CELSIUS-degrees, not a common sub-unit).
template<class T>
constexpr bool units::traits::is_absolute_v = is_absolute<T>::value
template<class T>
constexpr bool units::traits::is_delta_v = is_delta<T>::value
template<class T>
constexpr bool units::traits::is_kind_v = is_kind<T>::value

Detailed Description

Opt-in affine wrappers: units::absolute<U> (a point on a scale, carries the unit's datum) and units::delta<U> (an offset-free amount).

Include this header only where the point-vs-amount distinction should be enforced in the type; plain-unit code never sees these.

Typedef Documentation

◆ absolute_result_unit_t

template<UnitType U, UnitType V>
using units::detail::absolute_result_unit_t = std::conditional_t<is_losslessly_point_convertible_unit<V, U>, U, traits::replace_underlying_t<U, floating_point_promotion_t<typename traits::unit_traits<U>::underlying_type>>>

The result unit of an absolute (point) operator: keep the LHS unit, promote the underlying only when a point conversion of the RHS into it would be lossy (ratio OR datum).

See the LHS-unit tie-break above.

◆ delta_result_unit_t

template<UnitType U, UnitType V>
using units::detail::delta_result_unit_t
Initial value:
std::conditional_t<is_losslessly_convertible_unit<delta_unit_t<V>, delta_unit_t<U>>, U,
traits::replace_underlying_t<U, floating_point_promotion_t<typename traits::unit_traits<U>::underlying_type>>>
unit< traits::strong_t< conversion_factor< typename traits::conversion_factor_traits< typename traits::unit_traits< U >::conversion_factor >::conversion_ratio, typename traits::conversion_factor_traits< typename traits::unit_traits< U >::conversion_factor >::dimension_type, typename traits::conversion_factor_traits< typename traits::unit_traits< U >::conversion_factor >::pi_exponent_ratio, std::ratio< 0 > > >, typename traits::unit_traits< U >::underlying_type, typename traits::unit_traits< U >::numerical_scale_type > delta_unit_t
The offset-free counterpart of a unit: same dimension, scale, and pi factor, but translation stripped...
Definition kind.h:84

The result unit of a delta (amount) operator: keep the LHS unit, promote the underlying only when the RHS amount cannot convert into it losslessly.

A delta conversion is SCALE-ONLY (the datum is never applied), so losslessness is judged on the offset-free delta_unit_t — the datum translation is irrelevant, and a same-ratio pair (celsius↔kelvin deltas) stays integral rather than needlessly promoting.

◆ delta_unit_t

template<UnitType U>
using units::detail::delta_unit_t
Initial value:
typename traits::conversion_factor_traits<typename traits::unit_traits<U>::conversion_factor>::dimension_type,
typename traits::conversion_factor_traits<typename traits::unit_traits<U>::conversion_factor>::pi_exponent_ratio, std::ratio<0>>>,
typename traits::unit_traits<U>::underlying_type, typename traits::unit_traits<U>::numerical_scale_type>
Definition core.h:2735

The offset-free counterpart of a unit: same dimension, scale, and pi factor, but translation stripped.

Converting a delta between units uses THIS (scale only, no datum), so a temperature difference converts by degree size, not as an absolute point.

Variable Documentation

◆ is_losslessly_point_convertible_unit

template<UnitType From, UnitType To>
bool units::detail::is_losslessly_point_convertible_unit
inlineconstexpr
Initial value:
=
is_losslessly_convertible_unit<From, To> &&
(std::is_floating_point_v<typename traits::unit_traits<To>::underlying_type> ||
std::ratio_equal_v<typename traits::conversion_factor_traits<typename traits::unit_traits<From>::conversion_factor>::translation_ratio,
typename traits::conversion_factor_traits<typename traits::unit_traits<To>::conversion_factor>::translation_ratio>)

The result unit of a wrapper operator that keeps the LHS UNIT (the "LHS-unit tie-break"): the value stays expressed in U's unit so .value() reads intuitively (absolute<celsius> - absolute<fahrenheit> is a difference in CELSIUS-degrees, not a common sub-unit).

The one adjustment is to the UNDERLYING type: keeping U's underlying would NARROW when the RHS unit V cannot convert into U losslessly (a coarse integer LHS that cannot hold the RHS), so in that case the underlying is promoted to floating point. The result UNIT is always U's unit; only its underlying may widen.

This is the wrapper counterpart of lhs_result_unit_t (which the plain-unit operator+/operator- use). Both keep the LHS unit on the lossless path; they diverge only on the coarse-integer-LHS fallback: the plain operators reconcile to the common (finest) unit, the wrappers hold the LHS unit and widen only the underlying (a point keeps its datum in its own unit).

A POINT's lossless test is AFFINE-aware: is_losslessly_convertible_unit examines only the conversion RATIO, so it reports a datum-differing pair whose ratio happens to be 1 (e.g. kelvin↔celsius, ratio 1, datum 273.15) as lossless — but converting an integer point across that datum truncates the fractional offset (273 K → celsius<int> truncates −0.15 → 0). The datum-translation ratios must therefore ALSO match for an integer point conversion to be lossless; otherwise the underlying is promoted so the offset survives. This applies ONLY to absolute (a point carries its datum); a delta is offset-free.