|
Unit Conversion and Dimensional Analysis Library 3.6.1
A compile-time, header-only C++23 dimensional-analysis library
|
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>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 |
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.
| 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.
| 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.
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.
| using units::detail::delta_unit_t |
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.
|
inlineconstexpr |
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.