Basic Concepts¶
The most important concepts in the mp-units library are Dimension, QuantitySpec, Unit,
Reference, Representation, Quantity, and QuantityPoint:
flowchart TD
Dimension --- QuantitySpec
QuantitySpec --- Reference
Unit --- Reference
Reference --- Quantity
Representation --- Quantity
Quantity --- QuantityPoint
PointOrigin --- QuantityPoint
click Dimension "#Dimension"
click QuantitySpec "#QuantitySpec"
click Unit "#Unit"
click Reference "#Reference"
click Representation "#Representation"
click Quantity "#Quantity"
click PointOrigin "#PointOrigin"
click QuantityPoint "#QuantityPoint"
Dimension<T>¶
Dimension concept matches a dimension of either a base
or derived quantity:
- Base dimensions are explicitly defined by a user
by inheriting from the instantiation of a
base_dimensionclass template. It should be instantiated with a unique symbol identifier describing this dimension in a specific system of quantities. - Derived dimensions are implicitly created by the library's framework based on the quantity equation provided in the quantity specification.
Examples
isq::dim_length, isq::dim_mass, isq::dim_time, isq::dim_electric_current,
isq::dim_thermodynamic_temperature, isq::dim_amount_of_substance, and
isq::dim_luminous_intensity are the dimensions of base quantities in the
ISQ.
IEC 80000 provides iec80000::dim_traffic_intensity base dimension to extend ISQ
with information technology quantities.
A Dimension can be defined by the user in the following way:
The division on quantity specifications also divides their dimensions:
The dimension equation of isq::dim_length / isq::dim_time
results in the derived_dimension<isq::dim_length, per<isq::dim_time>> type.
DimensionOf<T, V>¶
DimensionOf concept is satisfied when both arguments satisfy a Dimension concept and
when they compare equal.
QuantitySpec<T>¶
QuantitySpec concept matches all the quantity specifications
including:
- Base quantities defined by a user by inheriting from
the
quantity_specclass template instantiated with a base dimension argument. - Derived named quantities defined by a user by
inheriting from the
quantity_specclass template instantiated with a result of a quantity equation passed as an argument. - Other named quantities forming a hierarchy of quantities
of the same kind defined by a user by inheriting from the
quantity_specclass template instantiated with another "parent" quantity specification passed as an argument. - Quantity kinds describing a family of mutually comparable quantities.
- Intermediate derived quantity specifications being a result of a quantity equations on other specifications.
Examples
isq::length, isq::mass, isq::time, isq::electric_current, isq::thermodynamic_temperature,
isq::amount_of_substance, and isq::luminous_intensity are the specifications of base quantities
in the ISQ.
isq::width, isq::height, isq::radius, and isq::position_vector are only a few of many
quantities of a kind length specified in the ISQ.
kind_of<isq::length> behaves as any of the quantities of a kind length.
isq::area, isq::speed, isq::moment_of_force are only a few of many derived quantities provided
in the ISQ.
QuantitySpec can be defined by the user in one of the following ways:
The quantity equation of isq::length / isq::time results
in the derived_quantity_spec<isq::length, per<isq::time>> type.
QuantitySpecOf<T, V>¶
QuantitySpecOf concept is satisfied when both arguments satisfy a QuantitySpec concept
and when T is implicitly convertible to V.
More details
Additionally:
Tshould not be a nested quantity specification ofV- either
Tis quantity kind orVshould not be a nested quantity specification ofT
Those additional conditions are required to make the following work:
static_assert(ReferenceOf<si::radian, isq::angular_measure>);
static_assert(!ReferenceOf<si::radian, dimensionless>);
static_assert(!ReferenceOf<isq::angular_measure[si::radian], dimensionless>);
static_assert(ReferenceOf<one, isq::angular_measure>);
static_assert(!ReferenceOf<dimensionless[one], isq::angular_measure>);
Unit<T>¶
Unit concept matches all the units in the library including:
- Base units defined by a user by inheriting from the
named_unitclass template instantiated with a unique symbol identifier describing this unit in a specific system of units. - Named scaled units defined by a user by inheriting from the
named_unitclass template instantiated with a unique symbol identifier and a product of multiplying another unit with some magnitude. - Prefixed units defined by a user by inheriting from the
prefixed_unitclass template instantiated with a prefix symbol, a magnitude, and a unit to be prefixed. - Derived named units defined by a user by inheriting from the
named_unitclass template instantiated with a unique symbol identifier and a result of unit equation passed as an argument. - Derived unnamed units being a result of a unit equations on other units.
Note
In the mp-units library, physical constants are also implemented as units.
Examples
si::second, si::metre, si::kilogram, si::ampere, si::kelvin, si::mole, and si::candela
are the base units of SI.
si::kilo<si::metre> is a prefixed unit on length.
si::radian, si::newton, and si::watt are examples of named derived quantities within
SI.
non_si::minute is an example of a scaled unit of time.
si::si2019::speed_of_light_in_vacuum is a physical constant standardized by the SI in 2019.
Unit can be defined by the user in one of the following ways:
template<PrefixableUnit auto U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {};
template<PrefixableUnit auto U> inline constexpr kilo_<U> kilo;
inline constexpr struct second : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct gram : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr struct minute : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct kilogram : decltype(kilo<gram>) {} kilogram;
inline constexpr struct newton : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct speed_of_light_in_vacuum : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
The unit equation of si::metre / si::second results
in the derived_unit<si::metre, per<si::second>> type.
AssociatedUnit<T>¶
AssociatedUnit concept describes a unit with an associated quantity
and is satisfied by:
- All units derived from a
named_unitclass template instantiated with a unique symbol identifier and aQuantitySpec. - All units being a result of a unit equations on other associated units.
Examples
All units in the SI have associated quantities. For example,
si::second is specified to measure isq::time.
Natural units typically do not have an associated quantity. For example, if we assume c = 1,
a natural::second unit can be used to measure both time and length. In such case speed
would be a dimensionless quantity.
PrefixableUnit<T>¶
PrefixableUnit concept is satisfied by all units derived from a named_unit class template for
which a customization point unit_can_be_prefixed<T{}> was not explicitly set to false. Such
units can be passed as an argument to a prefixed_unit class template.
Examples
All units in the SI can be prefixed with SI-defined prefixes.
Some off-system units like non_si::day
can't be prefixed. To enforce that the following has to be provided:
UnitOf<T, V>¶
UnitOf concept is satisfied for all units T matching an AssociatedUnit
concept with an associated quantity type implicitly convertible to V.
More details
Additionally, the kind of V and the kind of quantity type associated with T must be the same,
or the quantity type associated with T may not be derived from the kind of V.
This condition is required to make dimensionless[si::radian] invalid as si::radian should
be only used for isq::angular_measure which is a
nested quantity kind within the dimensionless quantities tree.
Reference<T>¶
Reference concept is satisfied by all quantity reference
types. Such types provide all the meta-information required to create a Quantity.
A Reference can either be:
- An AssociatedUnit.
- The instantiation of a
referenceclass template with aQuantitySpecpassed as the first template argument and aUnitpassed as the second one.
Examples
si::metre is defined in the SI as a unit of isq::length
and thus can be used as a reference to instantiate a quantity of length.
The expression isq::height[m] results with reference<isq::height, si::metre> which can be used to
instantiate a quantity of isq::height with a unit of si::metre.
ReferenceOf<T, V>¶
ReferenceOf concept is satisfied by references T that match the following value V:
V |
Condition |
|---|---|
Dimension |
The dimension of a quantity specification satisfies DimensionOf<V> concept. |
QuantitySpec |
The quantity specification satisfies QuantitySpecOf<V> concept. |
quantity_character |
The quantity specification has a character of V. |
Representation<T>¶
Representation concept constraints a type of a number that stores the
value of a quantity.
RepresentationOf<T, Ch>¶
RepresentationOf concept is satisfied by all Representation types that are of a specified
quantity character Ch.
A user can declare a custom representation type to be of a specific character by providing the specialization
with true for one or more of the following variable templates:
is_scalar<T>is_vector<T>is_tensor<T>
Examples
If we want to use scalar types to express vector quantities (e.g. ignoring the "direction" of the vector) the following definition can be provided to enable such a behavior:
Quantity<T>¶
Quantity concept matches every quantity in the library and is
satisfied by all types being or deriving from and instantiation of a quantity class template.
Examples
All of 42 * m, 42 * si::metre, 42 * isq::height[m], and isq::height(42 * m) create a quantity
and thus satisfy a Quantity concept.
A quantity type can also be specified explicitly (i.e. quantity<si::metre, int>,
quantity<isq::height[m]>).
QuantityOf<T, V>¶
QuantityOf concept is satisfied by all the quantities for which a ReferenceOf<V>
is true.
PointOrigin<T>¶
PointOrigin concept matches all quantity point origins in
the library. It is satisfied by either:
- All types derived from an
absolute_point_originclass template. - All types derived from an
relative_point_originclass template.
Examples
The types of both definitions below satisfy a PointOrigin concept:
PointOriginFor<T, V>¶
PointOriginFor concept is satisfied by all PointOrigin types that have quantity type
implicitly convertible from quantity specification V, which means that V must satisfy
QuantitySpecOf<T::quantity_spec>.
Examples
ice_point can serve as a point origin for points of isq::Celsius_temperature because this quantity
type implicitly converts to isq::thermodynamic_temperature.
However, if we define mean_sea_level in the following way:
then it can't be used as a point origin for points of isq::length or isq::width as none of them
is implicitly convertible to isq::altitude:
- not every "length" is an "altitude",
- "width" is not compatible with "altitude".
QuantityPoint<T>¶
QuantityPoint concept is satisfied by all types being either a specialization or derived from quantity_point
class template.
Examples
The following specifies a quantity point defined in terms of an ice_point quantity point origin
provided in the previous example:
QuantityPointOf<T, V>¶
QuantityPointOf concept is satisfied by all the quantity points T that match the following value V:
V |
Condition |
|---|---|
Reference |
The quantity point reference satisfies ReferenceOf<V> concept. |
PointOrigin |
The point and V have the same absolute point origin. |
QuantityLike<T>¶
QuantityLike concept provides interoperability with other libraries and is satisfied by a type T
for which an instantiation of quantity_like_traits type trait yields a valid type that provides:
- Static data member
referencethat matches theReferenceconcept, reptype that matchesRepresentationOfconcept with the character provided inreference,value(T)static member function returning a raw value of the quantity.
Examples
This is how support for std::chrono::seconds can be provided:
QuantityPointLike<T>¶
QuantityPointLike concept provides interoperability with other libraries and is satisfied by a type T
for which an instantiation of quantity_point_like_traits type trait yields a valid type that provides:
- Static data member
referencethat matches theReferenceconcept - Static data member
point_originthat matches thePointOriginconcept reptype that matchesRepresentationOfconcept with the character provided inreferencequantity_from_origin(T)static member function returning thequantitybeing the offset of the point from the origin
Examples
This is how support for a std::chrono::time_point of std::chrono::seconds can be provided:
template<typename C>
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
static constexpr auto reference = si::second;
static constexpr auto point_origin = chrono_point_origin;
using rep = std::chrono::seconds::rep;
[[nodiscard]] static constexpr auto quantity_from_origin(const std::chrono::time_point<C, std::chrono::seconds>& qp)
{
return quantity{std::chrono::duration_cast<std::chrono::seconds>(qp.time_since_epoch())};
}
};
quantity_point qp(time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()));