mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 20:34:26 +02:00
feat: users are now allowed to inherit their ow types from absolute point origins
This commit is contained in:
@@ -64,9 +64,16 @@ The **absolute point origin** specifies where the "zero" of our measurement's sc
|
||||
specify such an origin by deriving from the `absolute_point_origin` class template:
|
||||
|
||||
```cpp
|
||||
constexpr struct mean_sea_level : absolute_point_origin<isq::altitude> {} mean_sea_level;
|
||||
constexpr struct mean_sea_level : absolute_point_origin<mean_sea_level, isq::altitude> {} mean_sea_level;
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
The `absolute_point_origin` class template uses CRTP idiom to enforce the uniqueness of such a type.
|
||||
You should pass the type of a derived class as the first argument of the template instantiation.
|
||||
|
||||
*[CRTP]: Curiously Recurring Template Parameter
|
||||
|
||||
### `quantity_point`
|
||||
|
||||
The `quantity_point` class template specifies an absolute quantity with respect to an origin:
|
||||
@@ -185,7 +192,7 @@ the distance we will travel. We have to take a taxi to a local airport, fly to D
|
||||
a stopover in FRA, and, in the end, get a cab to the Gaylord Rockies Resort & Convention Center:
|
||||
|
||||
```cpp
|
||||
constexpr struct home : absolute_point_origin<isq::distance> {} home;
|
||||
constexpr struct home : absolute_point_origin<home, isq::distance> {} home;
|
||||
|
||||
quantity_point<isq::distance[km], home> home_airport = home + 15 * km;
|
||||
quantity_point<isq::distance[km], home> fra_airport = home_airport + 829 * km;
|
||||
@@ -246,7 +253,7 @@ two predefined point origins:
|
||||
```cpp
|
||||
namespace mp_units::si {
|
||||
|
||||
inline constexpr struct absolute_zero : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
|
||||
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
|
||||
inline constexpr struct ice_point : relative_point_origin<absolute_zero + 273.15 * kelvin> {} ice_point;
|
||||
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ inline constexpr struct dim_currency : base_dimension<"$"> {} dim_currency;
|
||||
|
||||
QUANTITY_SPEC(currency, dim_currency);
|
||||
|
||||
constexpr struct zero : absolute_point_origin<currency> {} zero;
|
||||
constexpr struct zero : absolute_point_origin<zero, currency> {} zero;
|
||||
|
||||
inline constexpr struct euro : named_unit<"EUR", kind_of<currency>> {} euro;
|
||||
inline constexpr struct us_dollar : named_unit<"USD", kind_of<currency>> {} us_dollar;
|
||||
|
@@ -38,7 +38,7 @@
|
||||
|
||||
namespace geographic {
|
||||
|
||||
inline constexpr struct mean_sea_level : mp_units::absolute_point_origin<mp_units::isq::altitude> {
|
||||
inline constexpr struct mean_sea_level : mp_units::absolute_point_origin<mean_sea_level, mp_units::isq::altitude> {
|
||||
} mean_sea_level;
|
||||
|
||||
using msl_altitude = mp_units::quantity_point<mp_units::isq::altitude[mp_units::si::metre], mean_sea_level>;
|
||||
@@ -64,9 +64,9 @@ struct MP_UNITS_STD_FMT::formatter<geographic::msl_altitude> : formatter<geograp
|
||||
|
||||
namespace geographic {
|
||||
|
||||
inline constexpr struct equator : mp_units::absolute_point_origin<mp_units::isq::angular_measure> {
|
||||
inline constexpr struct equator : mp_units::absolute_point_origin<equator, mp_units::isq::angular_measure> {
|
||||
} equator;
|
||||
inline constexpr struct prime_meridian : mp_units::absolute_point_origin<mp_units::isq::angular_measure> {
|
||||
inline constexpr struct prime_meridian : mp_units::absolute_point_origin<prime_meridian, mp_units::isq::angular_measure> {
|
||||
} prime_meridian;
|
||||
|
||||
|
||||
|
@@ -37,7 +37,7 @@ using namespace geographic;
|
||||
enum class earth_gravity_model { egm84_15, egm95_5, egm2008_1 };
|
||||
|
||||
template<earth_gravity_model M>
|
||||
struct height_above_ellipsoid_t : absolute_point_origin<isq::altitude> {
|
||||
struct height_above_ellipsoid_t : absolute_point_origin<height_above_ellipsoid_t<M>, isq::altitude> {
|
||||
static constexpr earth_gravity_model egm = M;
|
||||
};
|
||||
template<earth_gravity_model M>
|
||||
@@ -107,7 +107,7 @@ hae_altitude<M> to_hae(msl_altitude msl, position<long double> pos)
|
||||
// **** HAL ****
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct height_above_launch : absolute_point_origin<isq::altitude> {} height_above_launch;
|
||||
inline constexpr struct height_above_launch : absolute_point_origin<height_above_launch, isq::altitude> {} height_above_launch;
|
||||
// clang-format on
|
||||
|
||||
using hal_altitude = quantity_point<isq::altitude[si::metre], height_above_launch>;
|
||||
|
@@ -30,7 +30,7 @@
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
template<QuantitySpec auto Q>
|
||||
template<typename Derived, QuantitySpec auto QS>
|
||||
struct absolute_point_origin;
|
||||
|
||||
namespace detail {
|
||||
@@ -41,11 +41,11 @@ inline constexpr bool is_quantity_point = false;
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_absolute_point_origin = false;
|
||||
|
||||
template<auto Q>
|
||||
inline constexpr bool is_specialization_of_absolute_point_origin<absolute_point_origin<Q>> = true;
|
||||
template<typename D, auto Q>
|
||||
inline constexpr bool is_specialization_of_absolute_point_origin<absolute_point_origin<D, Q>> = true;
|
||||
|
||||
template<auto Q>
|
||||
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<Q>*);
|
||||
template<typename D, auto Q>
|
||||
void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin<D, Q>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_absolute_point_origin =
|
||||
@@ -123,18 +123,16 @@ template<typename T>
|
||||
inline constexpr bool is_quantity_point<T> = true;
|
||||
|
||||
template<PointOrigin PO1, PointOrigin PO2>
|
||||
[[nodiscard]] consteval bool same_absolute_point_origins(PO1, PO2)
|
||||
[[nodiscard]] consteval bool same_absolute_point_origins(PO1 po1, PO2 po2)
|
||||
{
|
||||
if constexpr (is_same_v<PO1, PO2>)
|
||||
return true;
|
||||
else if constexpr (is_derived_from_specialization_of_relative_point_origin<PO1> &&
|
||||
is_derived_from_specialization_of_relative_point_origin<PO2>)
|
||||
return is_same_v<std::remove_const_t<decltype(PO1::absolute_point_origin)>,
|
||||
std::remove_const_t<decltype(PO2::absolute_point_origin)>>;
|
||||
else if constexpr (is_derived_from_specialization_of_relative_point_origin<PO1>)
|
||||
return is_same_v<std::remove_const_t<decltype(PO1::absolute_point_origin)>, PO2>;
|
||||
else if constexpr (is_derived_from_specialization_of_relative_point_origin<PO2>)
|
||||
return is_same_v<PO1, std::remove_const_t<decltype(PO2::absolute_point_origin)>>;
|
||||
if constexpr (AbsolutePointOrigin<PO1> && AbsolutePointOrigin<PO2>)
|
||||
return po1 == po2;
|
||||
else if constexpr (RelativePointOrigin<PO1> && RelativePointOrigin<PO2>)
|
||||
return po1.absolute_point_origin == po2.absolute_point_origin;
|
||||
else if constexpr (RelativePointOrigin<PO1>)
|
||||
return po1.absolute_point_origin == po2;
|
||||
else if constexpr (RelativePointOrigin<PO2>)
|
||||
return po1 == po2.absolute_point_origin;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@@ -29,9 +29,25 @@
|
||||
|
||||
namespace mp_units {
|
||||
|
||||
template<QuantitySpec auto QS>
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
requires requires {
|
||||
{
|
||||
T::zero()
|
||||
} -> std::equality_comparable_with<T>;
|
||||
}
|
||||
[[nodiscard]] constexpr bool is_eq_zero(T v)
|
||||
{
|
||||
return v == T::zero();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename Derived, QuantitySpec auto QS>
|
||||
struct absolute_point_origin {
|
||||
static constexpr QuantitySpec auto quantity_spec = QS;
|
||||
using _type_ = absolute_point_origin;
|
||||
};
|
||||
|
||||
template<QuantityPoint auto QP>
|
||||
@@ -47,14 +63,30 @@ struct relative_point_origin {
|
||||
static constexpr PointOrigin auto absolute_point_origin = QP.absolute_point_origin;
|
||||
};
|
||||
|
||||
template<PointOrigin PO1, PointOrigin PO2>
|
||||
[[nodiscard]] consteval bool operator==(PO1 po1, PO2 po2)
|
||||
{
|
||||
if constexpr (detail::AbsolutePointOrigin<PO1> && detail::AbsolutePointOrigin<PO2>)
|
||||
return is_same_v<typename PO1::_type_, typename PO2::_type_>;
|
||||
else if constexpr (detail::RelativePointOrigin<PO1> && detail::RelativePointOrigin<PO2>)
|
||||
return PO1::quantity_point == PO2::quantity_point;
|
||||
else if constexpr (detail::RelativePointOrigin<PO1>)
|
||||
return detail::same_absolute_point_origins(po1, po2) &&
|
||||
detail::is_eq_zero(PO1::quantity_point.quantity_from(PO1::quantity_point.absolute_point_origin));
|
||||
else if constexpr (detail::RelativePointOrigin<PO2>)
|
||||
return detail::same_absolute_point_origins(po1, po2) &&
|
||||
detail::is_eq_zero(PO2::quantity_point.quantity_from(PO2::quantity_point.absolute_point_origin));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
[[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PointOrigin auto po)
|
||||
template<PointOrigin PO>
|
||||
[[nodiscard]] consteval PointOrigin auto get_absolute_point_origin(PO po)
|
||||
{
|
||||
if constexpr (requires { po.quantity_point.absolute_point_origin; })
|
||||
return po.quantity_point.absolute_point_origin;
|
||||
else
|
||||
if constexpr (AbsolutePointOrigin<PO>)
|
||||
return po;
|
||||
else
|
||||
return po.quantity_point.absolute_point_origin;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
@@ -28,8 +28,11 @@
|
||||
namespace mp_units::si {
|
||||
|
||||
// clang-format off
|
||||
inline constexpr struct absolute_zero : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
|
||||
inline constexpr struct absolute_zero : absolute_point_origin<absolute_zero, isq::thermodynamic_temperature> {} absolute_zero;
|
||||
inline constexpr struct zeroth_kelvin : decltype(absolute_zero) {} zeroth_kelvin;
|
||||
|
||||
inline constexpr struct ice_point : relative_point_origin<absolute_zero + 273.15 * kelvin> {} ice_point;
|
||||
inline constexpr struct zeroth_degree_Celsius : decltype(ice_point) {} zeroth_degree_Celsius;
|
||||
// clang-format on
|
||||
|
||||
} // namespace mp_units::si
|
||||
|
@@ -112,7 +112,7 @@ inline constexpr struct inch_of_mercury : named_unit<"inHg", mag<ratio(3'386'389
|
||||
// https://en.wikipedia.org/wiki/United_States_customary_units#Temperature
|
||||
inline constexpr struct degree_Fahrenheit : named_unit<basic_symbol_text{"°F", "`F"}, mag<ratio{5, 9}> * si::degree_Celsius> {} degree_Fahrenheit;
|
||||
|
||||
inline constexpr struct zero_Fahrenheit : relative_point_origin<si::ice_point - 32 * degree_Fahrenheit> {} zero_Fahrenheit;
|
||||
inline constexpr struct zero_Fahrenheit : relative_point_origin<si::zeroth_degree_Celsius - 32 * degree_Fahrenheit> {} zero_Fahrenheit;
|
||||
// clang-format on
|
||||
|
||||
namespace unit_symbols {
|
||||
|
@@ -79,7 +79,7 @@ struct quantity_like_traits<std::chrono::duration<Rep, Period>> {
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct chrono_point_origin_ : absolute_point_origin<isq::time> {
|
||||
struct chrono_point_origin_ : absolute_point_origin<chrono_point_origin_<C>, isq::time> {
|
||||
using clock = C;
|
||||
};
|
||||
template<typename C>
|
||||
|
@@ -38,7 +38,7 @@ namespace {
|
||||
|
||||
using namespace mp_units;
|
||||
|
||||
inline constexpr struct my_origin : absolute_point_origin<isq::length> {
|
||||
inline constexpr struct my_origin : absolute_point_origin<my_origin, isq::length> {
|
||||
} my_origin;
|
||||
inline constexpr struct my_relative_origin : relative_point_origin<my_origin + isq::length(42 * si::metre)> {
|
||||
} my_relative_origin;
|
||||
@@ -358,7 +358,7 @@ static_assert(QuantityPoint<quantity_point<isq::length[si::metre], my_relative_o
|
||||
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_origin>>);
|
||||
static_assert(QuantityPoint<quantity_point<isq::radius[si::metre], my_relative_origin>>);
|
||||
static_assert(!QuantityPoint<std::remove_const_t<decltype(isq::length[si::metre])>>);
|
||||
static_assert(!QuantityPoint<absolute_point_origin<isq::length>>);
|
||||
static_assert(!QuantityPoint<absolute_point_origin<struct my_origin, isq::length>>);
|
||||
static_assert(!QuantityPoint<struct my_origin>);
|
||||
static_assert(!QuantityPoint<struct my_relative_origin>);
|
||||
static_assert(!QuantityPoint<std::chrono::seconds>);
|
||||
@@ -390,7 +390,7 @@ static_assert(QuantityPointOf<quantity_point<isq::radius[si::metre], my_relative
|
||||
// PointOrigin
|
||||
static_assert(PointOrigin<struct my_origin>);
|
||||
static_assert(PointOrigin<struct my_relative_origin>);
|
||||
static_assert(!PointOrigin<absolute_point_origin<isq::length>>);
|
||||
static_assert(!PointOrigin<absolute_point_origin<struct my_origin, isq::length>>);
|
||||
static_assert(!PointOrigin<relative_point_origin<my_origin + 42 * si::metre>>);
|
||||
static_assert(!PointOrigin<quantity_point<si::metre, my_origin>>);
|
||||
static_assert(!PointOrigin<quantity_point<isq::length[si::metre], my_origin>>);
|
||||
|
@@ -36,26 +36,77 @@ using namespace mp_units::si::unit_symbols;
|
||||
using namespace std::chrono_literals;
|
||||
using sys_seconds = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
||||
|
||||
inline constexpr struct mean_sea_level : absolute_point_origin<isq::height> {
|
||||
inline constexpr struct mean_sea_level : absolute_point_origin<mean_sea_level, isq::height> {
|
||||
} mean_sea_level;
|
||||
|
||||
inline constexpr struct my_mean_sea_level : decltype(mean_sea_level) {
|
||||
} my_mean_sea_level;
|
||||
|
||||
inline constexpr struct same_mean_sea_level : relative_point_origin<mean_sea_level + 0 * isq::height[m]> {
|
||||
} same_mean_sea_level;
|
||||
|
||||
inline constexpr struct ground_level : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
|
||||
} ground_level;
|
||||
|
||||
inline constexpr struct my_ground_level : decltype(ground_level) {
|
||||
} my_ground_level;
|
||||
|
||||
inline constexpr struct same_ground_level1 : relative_point_origin<mean_sea_level + 42 * isq::height[m]> {
|
||||
} same_ground_level1;
|
||||
|
||||
inline constexpr struct same_ground_level2 : relative_point_origin<my_mean_sea_level + 42 * isq::height[m]> {
|
||||
} same_ground_level2;
|
||||
|
||||
inline constexpr struct tower_peak : relative_point_origin<ground_level + 42 * isq::height[m]> {
|
||||
} tower_peak;
|
||||
|
||||
inline constexpr struct other_ground_level : relative_point_origin<mean_sea_level + 123 * isq::height[m]> {
|
||||
} other_ground_level;
|
||||
|
||||
inline constexpr struct other_absolute_level : absolute_point_origin<isq::height> {
|
||||
inline constexpr struct other_absolute_level : absolute_point_origin<other_absolute_level, isq::height> {
|
||||
} other_absolute_level;
|
||||
|
||||
inline constexpr struct zero : absolute_point_origin<dimensionless> {
|
||||
inline constexpr struct zero : absolute_point_origin<zero, dimensionless> {
|
||||
} zero;
|
||||
|
||||
QUANTITY_SPEC(special_height, isq::height);
|
||||
|
||||
|
||||
//////////////////
|
||||
// point origins
|
||||
//////////////////
|
||||
|
||||
static_assert(si::absolute_zero == si::zeroth_kelvin);
|
||||
static_assert(si::ice_point == si::zeroth_degree_Celsius);
|
||||
static_assert(si::absolute_zero != si::ice_point);
|
||||
static_assert(si::zeroth_kelvin != si::zeroth_degree_Celsius);
|
||||
|
||||
static_assert(my_mean_sea_level == mean_sea_level);
|
||||
static_assert(my_mean_sea_level == same_mean_sea_level);
|
||||
|
||||
static_assert(my_ground_level == ground_level);
|
||||
static_assert(same_ground_level1 == ground_level);
|
||||
static_assert(same_ground_level2 == my_ground_level);
|
||||
|
||||
static_assert(mean_sea_level != other_absolute_level);
|
||||
static_assert(my_mean_sea_level != other_absolute_level);
|
||||
static_assert(ground_level != other_ground_level);
|
||||
|
||||
template<auto QS>
|
||||
struct absolute_po_ : absolute_point_origin<absolute_po_<QS>, QS> {};
|
||||
template<auto QS>
|
||||
inline constexpr absolute_po_<QS> absolute_po;
|
||||
|
||||
template<auto QP>
|
||||
struct relative_po_ : relative_point_origin<QP> {};
|
||||
template<auto QP>
|
||||
inline constexpr relative_po_<QP> relative_po;
|
||||
|
||||
static_assert(relative_po<absolute_po<isq::length> + isq::height(42 * m)>.quantity_spec == isq::height);
|
||||
static_assert(relative_po<absolute_po<kind_of<isq::length>> + isq::height(42 * m)>.quantity_spec == isq::height);
|
||||
static_assert(relative_po<absolute_po<isq::height> + 42 * m>.quantity_spec == isq::height);
|
||||
|
||||
|
||||
/////////////////////
|
||||
// class invariants
|
||||
/////////////////////
|
||||
@@ -1115,7 +1166,7 @@ static_assert(ground_level - other_ground_level == -81 * m);
|
||||
static_assert(other_ground_level - tower_peak == 39 * m);
|
||||
static_assert(tower_peak - other_ground_level == -39 * m);
|
||||
|
||||
inline constexpr struct zero_m_per_s : absolute_point_origin<kind_of<isq::speed>> {
|
||||
inline constexpr struct zero_m_per_s : absolute_point_origin<zero_m_per_s, kind_of<isq::speed>> {
|
||||
} zero_m_per_s;
|
||||
|
||||
// commutativity and associativity
|
||||
@@ -1159,7 +1210,7 @@ static_assert(
|
||||
is_of_type<(zero_m_per_s + 10 * isq::height[m] / (2 * isq::time[s])) + (10 * isq::height[m] / (2 * isq::time[s])),
|
||||
quantity_point<(isq::height / isq::time)[m / s], zero_m_per_s, int>>);
|
||||
|
||||
inline constexpr struct zero_Hz : absolute_point_origin<kind_of<isq::frequency>> {
|
||||
inline constexpr struct zero_Hz : absolute_point_origin<zero_Hz, kind_of<isq::frequency>> {
|
||||
} zero_Hz;
|
||||
|
||||
static_assert(((zero_Hz + 10 / (2 * isq::period_duration[s])) + 5 * isq::frequency[Hz]).quantity_from(zero_Hz) ==
|
||||
@@ -1209,7 +1260,7 @@ consteval bool invalid_subtraction(Ts... ts)
|
||||
return !requires { (... - ts); };
|
||||
}
|
||||
|
||||
inline constexpr struct zero_Bq : absolute_point_origin<kind_of<isq::activity>> {
|
||||
inline constexpr struct zero_Bq : absolute_point_origin<zero_Bq, kind_of<isq::activity>> {
|
||||
} zero_Bq;
|
||||
|
||||
static_assert(invalid_addition(zero_Bq + 5 * isq::activity[Bq], 5 * isq::frequency[Hz]));
|
||||
@@ -1222,23 +1273,4 @@ static_assert(invalid_addition(5 * isq::activity[Bq], zero_Hz + 10 / (2 * isq::t
|
||||
static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), zero_Hz + 5 * isq::frequency[Hz]));
|
||||
static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz]));
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// relative point origin
|
||||
/////////////////////////
|
||||
|
||||
template<auto QS>
|
||||
struct absolute_po_ : absolute_point_origin<QS> {};
|
||||
template<auto QS>
|
||||
inline constexpr absolute_po_<QS> absolute_po;
|
||||
|
||||
template<auto QP>
|
||||
struct relative_po_ : relative_point_origin<QP> {};
|
||||
template<auto QP>
|
||||
inline constexpr relative_po_<QP> relative_po;
|
||||
|
||||
static_assert(relative_po<absolute_po<isq::length> + isq::height(42 * m)>.quantity_spec == isq::height);
|
||||
static_assert(relative_po<absolute_po<kind_of<isq::length>> + isq::height(42 * m)>.quantity_spec == isq::height);
|
||||
static_assert(relative_po<absolute_po<isq::height> + 42 * m>.quantity_spec == isq::height);
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user