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_dimension
class 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_spec
class template instantiated with a base dimension argument. - Derived named quantities defined by a user by
inheriting from the
quantity_spec
class 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_spec
class 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
.
More details
Additionally:
T
should not be a nested quantity specification ofV
- either
T
is quantity kind orV
should 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_unit
class 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_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 defined by a user by inheriting from the
named_unit
class 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.
AssociatedUnit<T>
¶
AssociatedUnit
concept describes a unit with an associated quantity
and is satisfied by:
- All units derived from a
named_unit
class template instantiated with a unique symbol identifier and aQuantitySpec
of a quantity kind. - All units being a result of 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 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
.
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
reference
class template with aQuantitySpec
passed as the first template argument and aUnit
passed 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 (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 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_origin
class template. - All types derived from a
relative_point_origin
class 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>
.
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:
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
reference
that matches theReference
concept, rep
type that matchesRepresentationOf
concept with the character provided inreference
.to_numerical_value(T)
static member function returning a raw value of the quantity packed in eitherconvert_explicitly
orconvert_implicitly
wrapper that enables implicit conversion in the latter case.from_numerical_value(rep)
static member function returningT
packed in eitherconvert_explicitly
orconvert_implicitly
wrapper that enables implicit conversion in the latter case.
Examples
This is how support for std::chrono::seconds
can be provided:
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
reference
that matches theReference
concept. - Static data member
point_origin
that matches thePointOrigin
concept. rep
type that matchesRepresentationOf
concept 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_explicitly
orconvert_implicitly
wrapper that enables implicit conversion in the latter case.from_numerical_value(rep)
static member function returningT
packed in eitherconvert_explicitly
orconvert_implicitly
wrapper that enables implicit conversion in the latter case.
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>> {
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;