# Concepts This chapter enumerates all the user-facing concepts in the **mp-units** library. ## `Dimension` { #Dimension } `Dimension` concept matches a [dimension](../../appendix/glossary.md#dimension) of either a base or derived [quantity](../../appendix/glossary.md#quantity): - [Base dimensions](../../appendix/glossary.md#base-dimension) are explicitly defined by the user by inheriting from the instantiation of a `base_dimension` class template. It should be instantiated with a unique symbol identifier describing this dimension in a specific [system of quantities](../../appendix/glossary.md#system-of-quantities). - [Derived dimensions](../../appendix/glossary.md#derived-dimension) are implicitly created by the library's framework based on the [quantity equation](../../appendix/glossary.md#quantity-equation) provided in the [quantity specification](../../appendix/glossary.md#quantity_spec). ### `DimensionOf` { #DimensionOf } `DimensionOf` concept is satisfied when both arguments satisfy a [`Dimension`](#Dimension) concept and when they compare equal. ## `QuantitySpec` { #QuantitySpec } `QuantitySpec` concept matches all the [quantity specifications](../../appendix/glossary.md#quantity_spec) including: - [Base quantities](../../appendix/glossary.md#base-quantity) defined by a user by inheriting from the `quantity_spec` class template instantiated with a [base dimension](../../appendix/glossary.md#base-dimension) argument. - [Derived named quantities](../../appendix/glossary.md#derived-quantity) defined by a user by inheriting from the `quantity_spec` class template instantiated with a result of a [quantity equation](../../appendix/glossary.md#quantity-equation) passed as an argument. - Other named quantities forming a [hierarchy of quantities](../../appendix/glossary.md#quantity-hierarchy) of the same [kind](../../appendix/glossary.md#kind) defined by a user by inheriting from the `quantity_spec` class template instantiated with another "parent" quantity specification passed as an argument. - [Quantity kinds](../../appendix/glossary.md#kind) describing a family of mutually comparable quantities. - Intermediate [derived quantity](../../appendix/glossary.md#derived-quantity) specifications being a result of a [quantity equations](../../appendix/glossary.md#quantity-equation) on other specifications. ### `QuantitySpecOf` { #QuantitySpecOf } `QuantitySpecOf` concept is satisfied when both arguments satisfy a [`QuantitySpec`](#QuantitySpec) concept and when `T` is implicitly convertible to `V`. ??? info "More details" Additionally: - `T` should not be a [nested quantity specification of `V`](dimensionless_quantities.md/#nested-quantity-kinds) - either `T` is quantity kind or `V` should not be a [nested quantity specification of `T`](dimensionless_quantities.md/#nested-quantity-kinds) Those additional conditions are required to make the following work: ```cpp static_assert(ReferenceOf); static_assert(!ReferenceOf); static_assert(!ReferenceOf); static_assert(ReferenceOf); static_assert(!ReferenceOf); ``` ## `Unit` { #Unit } `Unit` concept matches all the [units](../../appendix/glossary.md#unit) in the library including: - [Base units](../../appendix/glossary.md#base-unit) defined by a user by inheriting from the `named_unit` class template instantiated with a unique symbol identifier describing this unit in a specific [system of units](../../appendix/glossary.md#system-of-units). - Named scaled units defined by a user by inheriting from the `named_unit` class 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_unit` class template instantiated with a prefix symbol, a magnitude, and a unit to be prefixed. - [Derived named units](../../appendix/glossary.md#derived-unit) defined by a user by inheriting from the `named_unit` class template instantiated with a unique symbol identifier and a result of [unit equation](../../appendix/glossary.md#unit-equation) passed as an argument. - [Derived unnamed units](../../appendix/glossary.md#derived-unit) being a result of a [unit equations](../../appendix/glossary.md#unit-equation) on other units. !!! note In the **mp-units** library, [physical constants are also implemented as units](faster_than_lightspeed_constants.md). ### `AssociatedUnit` { #AssociatedUnit } `AssociatedUnit` concept describes a [unit with an associated quantity](../../appendix/glossary.md#associated-unit) and is satisfied by: - All units derived from a `named_unit` class template instantiated with a unique symbol identifier and a [`QuantitySpec`](#quantityspec) of a [quantity kind](../../appendix/glossary.md#kind). - All units being a result of [unit equations](../../appendix/glossary.md#unit-equation) on other associated units. ??? abstract "Examples" All units in the [SI](../../appendix/glossary.md#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 have a unit of `one`. ### `PrefixableUnit` { #PrefixableUnit } `PrefixableUnit` concept is satisfied by all units derived from a `named_unit` class template for which a customization point `unit_can_be_prefixed` was not explicitly set to `false`. Such units can be passed as an argument to a `prefixed_unit` class template. ??? abstract "Examples" All units in the [SI](../../appendix/glossary.md#si) can be prefixed with SI-defined prefixes. Some [off-system units](../../appendix/glossary.md#off-system-unit) like `non_si::day` can't be prefixed. To enforce that, the following has to be provided: ```cpp template<> inline constexpr bool unit_can_be_prefixed = false; ``` ### `UnitOf` { #UnitOf } `UnitOf` concept is satisfied for all units `T` matching an [`AssociatedUnit`](#AssociatedUnit) concept with an associated quantity type implicitly convertible to `V`. ??? info "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](dimensionless_quantities.md/#nested-quantity-kinds). ### `UnitCompatibleWith` { #UnitCompatibleWith } `UnitCompatibleWith` concept is satisfied for all units `T` when: - `V1` is a [`Unit`](#Unit), - `V2` is a [`QuantitySpec`](#QuantitySpec), - `T` and `V1` are defined in terms of the same reference unit, - if `T` is an [`AssociatedUnit`](#AssociatedUnit) it should satisfy [`UnitOf`](#UnitOf). ## `Reference` { #Reference } `Reference` concept is satisfied by all [quantity reference](../../appendix/glossary.md#reference) types. Such types provide all the meta-information required to create a [`Quantity`](#Quantity). A `Reference` can either be: - An [`AssociatedUnit`](#AssociatedUnit). - The instantiation of a `reference` class template with a [`QuantitySpec`](#QuantitySpec) passed as the first template argument and a [`Unit`](#Unit) passed as the second one. ### `ReferenceOf` { #ReferenceOf } `ReferenceOf` concept is satisfied by references `T` which have a quantity specification that satisfies [`QuantitySpecOf`](#QuantitySpecOf) concept. | ## `Representation` { #Representation } `Representation` concept constraints a type of a number that stores the [value of a quantity](../../appendix/glossary.md#quantity-value). ### `RepresentationOf` { #RepresentationOf } `RepresentationOf` concept is satisfied by all `Representation` types that are of a specified [quantity character](../../appendix/glossary.md#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` - `is_vector` - `is_tensor` ??? tip If we want to use scalar types to also express [vector quantities](character_of_a_quantity.md#defining-vector-and-tensor-quantities) (e.g., ignoring the "direction" of the vector) the following definition can be provided to enable such a behavior: ```cpp template requires mp_units::is_scalar inline constexpr bool mp_units::is_vector = true; ``` ## `Quantity` { #Quantity } `Quantity` concept matches every [quantity](../../appendix/glossary.md#quantity) in the library and is satisfied by all types being or deriving from an instantiation of a `quantity` class template. ### `QuantityOf` { #QuantityOf } `QuantityOf` concept is satisfied by all the quantities for which a [`QuantitySpecOf`](#QuantitySpecOf) is `true`. ## `PointOrigin` { #PointOrigin } `PointOrigin` concept matches all [quantity point origins](../../appendix/glossary.md#point-origin) in the library. It is satisfied by either: - All types derived from an `absolute_point_origin` class template. - All types derived from a `relative_point_origin` class template. ### `PointOriginFor` { #PointOriginFor } `PointOriginFor` concept is satisfied by all [`PointOrigin`](#PointOrigin) types that have quantity type implicitly convertible from quantity specification `V`, which means that `V` must satisfy [`QuantitySpecOf`](#QuantitySpecOf). ??? abstract "Examples" `si::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: ```cpp inline constexpr struct mean_sea_level : absolute_point_origin {} mean_sea_level; ``` 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` { #QuantityPoint } `QuantityPoint` concept is satisfied by all types being either a specialization or derived from `quantity_point` class template. ### `QuantityPointOf` { #QuantityPointOf } `QuantityPointOf` concept is satisfied by all the quantity points `T` that match the following value `V`: | `V` | Condition | |----------------|-----------------------------------------------------------------------------------------------------| | `QuantitySpec` | The quantity point quantity specification satisfies [`QuantitySpecOf`](#QuantitySpecOf) concept. | | `PointOrigin` | The _point_ and `V` have the same absolute point origin. | ## `QuantityLike` { #QuantityLike } `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 `reference` that matches the [`Reference`](#Reference) concept, - `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided in `reference`. - `to_numerical_value(T)` static member function returning a raw value of the quantity packed in either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in the latter case. - `from_numerical_value(rep)` static member function returning `T` packed in either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in the latter case. ??? abstract "Examples" This is how support for `std::chrono::seconds` can be provided: ```cpp template<> struct mp_units::quantity_like_traits { static constexpr auto reference = si::second; using rep = std::chrono::seconds::rep; [[nodiscard]] static constexpr convert_implicitly to_numerical_value(const std::chrono::seconds& q) { return q.count(); } [[nodiscard]] static constexpr convert_implicitly from_numerical_value(const rep& v) { return std::chrono::seconds(v); } }; quantity q = 42s; std::chrono::seconds dur = 42 * s; ``` ## `QuantityPointLike` { #QuantityPointLike } `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 `reference` that matches the [`Reference`](#Reference) concept. - Static data member `point_origin` that matches the [`PointOrigin`](#PointOrigin) concept. - `rep` type that matches [`RepresentationOf`](#RepresentationOf) concept with the character provided in `reference`. - `to_quantity(T)` static member function returning the `quantity` being the offset of the point from the origin packed in either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in the latter case. - `from_quantity(quantity)` static member function returning `T` packed in either `convert_explicitly` or `convert_implicitly` wrapper that enables implicit conversion in the latter case. ??? abstract "Examples" This is how support for a `std::chrono::time_point` of `std::chrono::seconds` can be provided: ```cpp template struct mp_units::quantity_point_like_traits> { using T = std::chrono::time_point; static constexpr auto reference = si::second; static constexpr struct point_origin : absolute_point_origin {} point_origin{}; using rep = std::chrono::seconds::rep; [[nodiscard]] static constexpr convert_implicitly> to_quantity(const T& qp) { return quantity{qp.time_since_epoch()}; } [[nodiscard]] static constexpr convert_implicitly from_quantity(const quantity& q) { return T(q); } }; quantity_point qp = time_point_cast(std::chrono::system_clock::now()); std::chrono::sys_seconds q = qp + 42 * s; ```