14 KiB
Concepts
This chapter enumerates all the user-facing concepts in the mp-units library.
Dimension<T>
Dimension concept matches a dimension of either a base
or derived quantity:
- Base dimensions are explicitly defined by the 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.
All of the above dimensions have to be marked as final.
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.
All of the above quantity specifications have to be marked as final.
QuantitySpecOf<T, V>
QuantitySpecOf concept is satisfied when both arguments satisfy a 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<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.
All of the above units have to be marked as final.
!!! note
In the **mp-units** library, [physical constants are also implemented as units](faster_than_lightspeed_constants.md).
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 aQuantitySpecof a quantity kind. - All units being a result of unit equations 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<T>
PrefixableUnit concept is satisfied by all units derived from a named_unit class template.
Such units can be passed as an argument to a prefixed_unit class template.
UnitOf<T, V>
UnitOf concept is satisfied for all units T matching an 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).
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.
ReferenceOf<T, V>
ReferenceOf concept is satisfied by references T which have a quantity specification that satisfies
QuantitySpecOf<V> concept. |
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>
??? 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<class T>
requires mp_units::is_scalar<T>
constexpr bool mp_units::is_vector<T> = true;
```
Quantity<T>
Quantity concept matches every quantity in the library and is
satisfied by all types being or deriving from an instantiation of a quantity class template.
QuantityOf<T, V>
QuantityOf concept is satisfied by all the quantities for which a QuantitySpecOf<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 a
relative_point_originclass template.
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>.
??? 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 final : absolute_point_origin<isq::altitude> {} 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<T>
QuantityPoint concept is satisfied by all types being either a specialization or derived from quantity_point
class template.
QuantityPointOf<T, V>
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<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.to_numerical_value(T)static member function returning a raw value of the quantity packed in eitherconvert_explicitlyorconvert_implicitlywrapper that enables implicit conversion in the latter case.from_numerical_value(rep)static member function returningTpacked in eitherconvert_explicitlyorconvert_implicitlywrapper 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<std::chrono::seconds> {
static constexpr auto reference = si::second;
using rep = std::chrono::seconds::rep;
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(const std::chrono::seconds& d)
{
return d.count();
}
[[nodiscard]] static constexpr convert_implicitly<std::chrono::seconds> from_numerical_value(const rep& v)
{
return std::chrono::seconds(v);
}
};
quantity q = 42s;
std::chrono::seconds dur = 42 * s;
```
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 inreference.to_numerical_value(T)static member function returning a raw value of the quantity being the offset of the point from the origin packed in eitherconvert_explicitlyorconvert_implicitlywrapper that enables implicit conversion in the latter case.from_numerical_value(rep)static member function returningTpacked in eitherconvert_explicitlyorconvert_implicitlywrapper 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<typename C>
struct mp_units::quantity_point_like_traits<std::chrono::time_point<C, std::chrono::seconds>> {
using T = std::chrono::time_point<C, std::chrono::seconds>;
static constexpr auto reference = si::second;
static constexpr struct point_origin_ final : absolute_point_origin<isq::time> {} point_origin{};
using rep = std::chrono::seconds::rep;
[[nodiscard]] static constexpr convert_implicitly<rep> to_numerical_value(const T& tp)
{
return tp.time_since_epoch().count();
}
[[nodiscard]] static constexpr convert_implicitly<T> from_numerical_value(const rep& v)
{
return T(std::chrono::seconds(v));
}
};
quantity_point qp = time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now());
std::chrono::sys_seconds q = qp + 42 * s;
```