Type Introspection¶
The mp-units library provides several class templates that expose public static members to query their properties at compile-time. These members allow users to inspect the metadata of quantities, units, and related types.
Note
Public members with the _XXX_ naming convention (where XXX is surrounded by underscores)
are implementation details and should not be used in user code.
Info
For obtaining textual representations of units and dimensions, see the Text Output chapter.
dimension¶
Base dimensions created with base_dimension do not expose public static members.
quantity_spec¶
The quantity_spec class template and its specializations provide the following public
static members:
| Member | Type | Description |
|---|---|---|
dimension |
Dimension |
The dimension of the quantity specification |
character |
quantity_character |
The character of the quantity (scalar, vector, tensor) |
Example
unit and Reference¶
Units, including specializations of named_unit, prefixed_unit, and derived_unit,
are fundamental building blocks in mp-units. They satisfy the Reference concept,
which is a key abstraction in the library.
The Reference Concept¶
The Reference concept is satisfied by two different types:
- Units - such as
si::metre,si::second, or derived units likesi::metre / si::second referenceclass template - explicitly combining a quantity specification with a unit, such asisq::length[si::metre]
Because the Reference concept is satisfied by different types with different internal
structures, neither units nor explicit references expose public static data members for
metadata access. Instead, the library provides non-member functions to extract metadata
from any Reference:
get_quantity_spec(R)- extracts the quantity specificationget_unit(R)- extracts the unit
Where Reference is Used?
The Reference concept appears as a template parameter in:
quantity<R, Rep>- whereRis aReference(either a unit or explicit reference)quantity_point<R, PO, Rep>- whereRis aReference
Example
Extracting metadata from different Reference types:
// From a unit (satisfies Reference concept)
static_assert(get_quantity_spec(si::metre) == kind_of<isq::length>);
static_assert(get_unit(si::metre) == si::metre);
// From an explicit reference
constexpr auto ref = isq::length[si::metre];
static_assert(get_quantity_spec(ref) == isq::length);
static_assert(get_unit(ref) == si::metre);
// From a derived unit
constexpr auto speed_unit = si::metre / si::second;
static_assert(get_quantity_spec(speed_unit) == kind_of<isq::length / isq::duration>);
static_assert(get_unit(speed_unit) == si::metre / si::second);
quantity¶
The quantity<R, Rep> class template takes a Reference as its first template parameter.
It provides the following public static members:
| Member | Type | Description |
|---|---|---|
reference |
Reference |
The reference used to instantiate this quantity (can be a unit or explicit reference) |
quantity_spec |
QuantitySpec |
The quantity specification (extracted via get_quantity_spec(reference)) |
dimension |
Dimension |
The dimension of the quantity |
unit |
Unit |
The measurement unit (extracted via get_unit(reference)) |
Additionally, quantity provides a public type alias:
rep- the representation type used to store the numerical value
Example
using distance = quantity<isq::length[si::metre], int>;
static_assert(distance::reference == isq::length[si::metre]);
static_assert(distance::quantity_spec == isq::length);
static_assert(distance::dimension == isq::dim_length);
static_assert(distance::unit == si::metre);
static_assert(std::is_same_v<distance::rep, int>);
For dimensionless quantities:
quantity_point¶
The quantity_point<R, PO, Rep> class template takes a Reference as its first template
parameter. It provides the following public static members:
| Member | Type | Description |
|---|---|---|
reference |
Reference |
The reference used to instantiate this quantity point (can be a unit or explicit reference) |
quantity_spec |
QuantitySpec |
The quantity specification (extracted via get_quantity_spec(reference)) |
dimension |
Dimension |
The dimension of the quantity point |
unit |
Unit |
The measurement unit (extracted via get_unit(reference)) |
point_origin |
PointOrigin |
The origin of this quantity point |
absolute_point_origin |
PointOrigin |
The absolute origin in the origin hierarchy |
Additionally, quantity_point provides public type aliases:
rep- the representation type used to store the numerical valuequantity_type- the corresponding quantity type (quantity<reference, rep>)
Example
With default (zeroth) origin:
using length_point = quantity_point<si::metre>;
static_assert(length_point::reference == si::metre);
static_assert(length_point::quantity_spec == kind_of<isq::length>);
static_assert(length_point::dimension == isq::dim_length);
static_assert(length_point::unit == si::metre);
static_assert(std::is_same_v<length_point::rep, double>);
static_assert(std::is_same_v<length_point::quantity_type, quantity<si::metre, double>>);
With explicit origin:
inline constexpr struct mean_sea_level : absolute_point_origin<isq::altitude> {} mean_sea_level;
inline constexpr struct ground_level : relative_point_origin<mean_sea_level + 42 * si::metre> {} ground_level;
using altitude = quantity_point<isq::height[si::metre], mean_sea_level>;
using altitude_agl = quantity_point<isq::height[si::metre], ground_level>;
static_assert(altitude::reference == isq::height[si::metre]);
static_assert(altitude::quantity_spec == isq::height);
static_assert(altitude::dimension == isq::dim_length);
static_assert(altitude::unit == si::metre);
static_assert(std::is_same_v<altitude::rep, double>);
static_assert(std::is_same_v<altitude::quantity_type, quantity<isq::height[si::metre]>>);
static_assert(altitude::point_origin == mean_sea_level);
static_assert(altitude::absolute_point_origin == mean_sea_level);
static_assert(altitude_agl::point_origin == ground_level);
static_assert(altitude_agl::absolute_point_origin == mean_sea_level);
Compile-Time Introspection¶
All these static members can be used in constant expressions, enabling powerful compile-time introspection and type computations:
template<Quantity Q>
constexpr auto get_dimension() { return Q::dimension; }
template<Quantity Q>
constexpr bool is_length_quantity() { return Q::dimension == isq::dim_length; }
static_assert(is_length_quantity<quantity<isq::length[si::metre]>>());
static_assert(!is_length_quantity<quantity<isq::duration[si::second]>>());
Advanced Introspection Examples¶
Checking dimensional relationships between quantities:
template<mp_units::Dimension auto... Ds>
constexpr bool are_time_derivatives = false;
template<mp_units::Dimension auto D>
constexpr bool are_time_derivatives<D> = true;
template<mp_units::Dimension auto D1, mp_units::Dimension auto D2, mp_units::Dimension auto... Ds>
constexpr bool are_time_derivatives<D1, D2, Ds...> =
(D1 / D2 == mp_units::isq::dim_time) && are_time_derivatives<D2, Ds...>;
// Position, velocity, acceleration are time derivatives
static_assert(are_time_derivatives<isq::dim_length, isq::dim_length / isq::dim_time,
isq::dim_length / pow<2>(isq::dim_time)>);
Real-World Application
This pattern of checking time derivatives is particularly useful in Kalman filters, where system states often represent quantities and their derivatives (e.g., position, velocity, and acceleration). See the Kalman Filter Examples for a complete implementation.
Accessing Numerical Values Safely¶
While metadata queries are always safe, accessing the numerical value requires care.
The safest approach is to use .numerical_value_in(unit) with an explicit unit:
quantity<si::metre> distance = 100 * si::metre;
auto value = distance.numerical_value_in(si::metre); // Safe: explicit unit
In generic code, you can use the quantity's own unit, though this bypasses unit safety during refactoring:
template<Quantity Q>
void process(Q q)
{
// This will always compile but won't catch unit changes during refactoring
auto value = q.numerical_value_in(q.unit);
// ...
}
Warning
Using q.numerical_value_in(q.unit) is type-safe but bypasses the unit safety
that would catch accidental unit changes during refactoring. Prefer explicit
units when possible.