feat: quantity_point construction from quantity made private + make_quantity_point added

This commit is contained in:
Mateusz Pusz
2023-08-23 12:49:14 +02:00
parent ed279c43ab
commit fb9f288c56
6 changed files with 69 additions and 58 deletions

View File

@@ -67,8 +67,8 @@ auto get_waypoints()
using namespace geographic::literals; using namespace geographic::literals;
using namespace mp_units::international::unit_symbols; using namespace mp_units::international::unit_symbols;
static const std::array waypoints = { static const std::array waypoints = {
waypoint{"EPPR", {54.24772_N, 18.6745_E}, msl_altitude{16. * ft}}, // N54°14'51.8" E18°40'28.2" waypoint{"EPPR", {54.24772_N, 18.6745_E}, mean_sea_level + 16. * ft}, // N54°14'51.8" E18°40'28.2"
waypoint{"EPGI", {53.52442_N, 18.84947_E}, msl_altitude{115. * ft}} // N53°31'27.9" E18°50'58.1" waypoint{"EPGI", {53.52442_N, 18.84947_E}, mean_sea_level + 115. * ft} // N53°31'27.9" E18°50'58.1"
}; };
return waypoints; return waypoints;
} }

View File

@@ -98,7 +98,7 @@ hae_altitude<M> to_hae(msl_altitude msl, position<long double> pos)
{ {
const auto geoid_undulation = const auto geoid_undulation =
isq::height(GeographicLibWhatsMyOffset(pos.lat.number_in(si::degree), pos.lon.number_in(si::degree)) * si::metre); isq::height(GeographicLibWhatsMyOffset(pos.lat.number_in(si::degree), pos.lon.number_in(si::degree)) * si::metre);
return hae_altitude<M>{msl.absolute() - geoid_undulation}; return height_above_ellipsoid<M> + (msl.absolute() - geoid_undulation);
} }
@@ -130,7 +130,7 @@ struct MP_UNITS_STD_FMT::formatter<hal_altitude> : formatter<hal_altitude::quant
// **** UAV **** // **** UAV ****
class unmanned_aerial_vehicle { class unmanned_aerial_vehicle {
msl_altitude current_{0 * si::metre}; msl_altitude current_ = mean_sea_level + 0 * si::metre;
msl_altitude launch_ = current_; msl_altitude launch_ = current_;
public: public:
void take_off(msl_altitude alt) { launch_ = alt; } void take_off(msl_altitude alt) { launch_ = alt; }
@@ -139,7 +139,7 @@ public:
void current(msl_altitude alt) { current_ = alt; } void current(msl_altitude alt) { current_ = alt; }
msl_altitude current() const { return current_; } msl_altitude current() const { return current_; }
hal_altitude hal() const { return hal_altitude{current_ - launch_}; } hal_altitude hal() const { return height_above_launch + (current_ - launch_); }
}; };
@@ -149,11 +149,11 @@ int main()
using namespace mp_units::international::unit_symbols; using namespace mp_units::international::unit_symbols;
unmanned_aerial_vehicle uav; unmanned_aerial_vehicle uav;
uav.take_off(msl_altitude{6'000 * ft}); uav.take_off(mean_sea_level + 6'000 * ft);
uav.current(msl_altitude{10'000 * ft}); uav.current(mean_sea_level + 10'000 * ft);
std::cout << MP_UNITS_STD_FMT::format("hal = {}\n", uav.hal()); std::cout << MP_UNITS_STD_FMT::format("hal = {}\n", uav.hal());
msl_altitude ground_level{123 * m}; msl_altitude ground_level = mean_sea_level + 123 * m;
std::cout << MP_UNITS_STD_FMT::format("agl = {}\n", uav.current() - ground_level); std::cout << MP_UNITS_STD_FMT::format("agl = {}\n", uav.current() - ground_level);
struct waypoint { struct waypoint {
@@ -162,7 +162,7 @@ int main()
msl_altitude msl_alt; msl_altitude msl_alt;
}; };
waypoint wpt = {"EPPR", {54.24772_N, 18.6745_E}, msl_altitude{16. * ft}}; waypoint wpt = {"EPPR", {54.24772_N, 18.6745_E}, mean_sea_level + 16. * ft};
std::cout << MP_UNITS_STD_FMT::format("{}: {} {}, {:%.2Q %q}, {:%.2Q %q}\n", wpt.name, wpt.pos.lat, wpt.pos.lon, std::cout << MP_UNITS_STD_FMT::format("{}: {} {}, {:%.2Q %q}, {:%.2Q %q}\n", wpt.name, wpt.pos.lat, wpt.pos.lon,
wpt.msl_alt, to_hae<earth_gravity_model::egm2008_1>(wpt.msl_alt, wpt.pos)); wpt.msl_alt, to_hae<earth_gravity_model::egm2008_1>(wpt.msl_alt, wpt.pos));
} }

View File

@@ -179,10 +179,12 @@ concept QuantityPointLike = requires(T qp) {
requires RepresentationOf<typename quantity_point_like_traits<T>::rep, requires RepresentationOf<typename quantity_point_like_traits<T>::rep,
get_quantity_spec(quantity_point_like_traits<T>::reference).character>; get_quantity_spec(quantity_point_like_traits<T>::reference).character>;
requires Quantity<std::remove_cvref_t<decltype(quantity_point_like_traits<T>::quantity_from_origin(qp))>>; requires Quantity<std::remove_cvref_t<decltype(quantity_point_like_traits<T>::quantity_from_origin(qp))>>;
requires std::constructible_from< {
quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin, make_quantity_point<quantity_point_like_traits<T>::point_origin>(
typename quantity_point_like_traits<T>::rep>, quantity_point_like_traits<T>::quantity_from_origin(qp))
decltype(quantity_point_like_traits<T>::quantity_from_origin(qp))>; }
-> std::same_as<quantity_point<quantity_point_like_traits<T>::reference, quantity_point_like_traits<T>::point_origin,
typename quantity_point_like_traits<T>::rep>>;
}; };
} // namespace mp_units } // namespace mp_units

View File

@@ -29,6 +29,10 @@
namespace mp_units { namespace mp_units {
template<PointOrigin auto PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
[[nodiscard]] constexpr quantity_point<Q::reference, PO, typename Q::rep> make_quantity_point(Q&& q);
template<QuantitySpec auto QS> template<QuantitySpec auto QS>
struct absolute_point_origin { struct absolute_point_origin {
static constexpr QuantitySpec auto quantity_spec = QS; static constexpr QuantitySpec auto quantity_spec = QS;
@@ -37,7 +41,7 @@ struct absolute_point_origin {
template<QuantityPoint auto QP> template<QuantityPoint auto QP>
struct relative_point_origin { struct relative_point_origin {
static constexpr QuantityPoint auto quantity_point = QP; static constexpr QuantityPoint auto quantity_point = QP;
static constexpr QuantitySpec auto quantity_spec = [](){ static constexpr QuantitySpec auto quantity_spec = []() {
// select the strongest of specs // select the strongest of specs
if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(QP.quantity_spec)>>) if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(QP.quantity_spec)>>)
return QP.point_origin.quantity_spec; return QP.point_origin.quantity_spec;
@@ -57,11 +61,6 @@ namespace detail {
return po; return po;
} }
template<QuantityPointLike QP>
using quantity_point_like_type =
quantity_point<quantity_point_like_traits<QP>::reference, quantity_point_like_traits<QP>::point_origin,
typename quantity_point_like_traits<QP>::rep>;
} // namespace detail } // namespace detail
/** /**
@@ -113,13 +112,6 @@ public:
quantity_point(const quantity_point&) = default; quantity_point(const quantity_point&) = default;
quantity_point(quantity_point&&) = default; quantity_point(quantity_point&&) = default;
template<Quantity Q>
requires std::constructible_from<quantity_type, Q> &&
ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
constexpr explicit quantity_point(Q&& q, decltype(point_origin) = point_origin) : q_(std::forward<Q>(q))
{
}
template<QuantityPointOf<absolute_point_origin> QP> template<QuantityPointOf<absolute_point_origin> QP>
requires std::constructible_from<quantity_type, typename QP::quantity_type> requires std::constructible_from<quantity_type, typename QP::quantity_type>
// TODO add perfect forwarding // TODO add perfect forwarding
@@ -141,10 +133,10 @@ public:
template<QuantityPointLike QP> template<QuantityPointLike QP>
requires std::same_as<std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>, requires std::same_as<std::remove_const_t<decltype(quantity_point_like_traits<QP>::point_origin)>,
std::remove_const_t<decltype(point_origin)>> && std::remove_const_t<decltype(point_origin)>> &&
std::convertible_to<typename detail::quantity_point_like_type<QP>::quantity_type, quantity_type> std::convertible_to<
constexpr explicit quantity_point(const QP& qp) : quantity<quantity_point_like_traits<QP>::reference, typename quantity_point_like_traits<QP>::rep>,
q_(typename detail::quantity_point_like_type<QP>::quantity_type{ quantity_type>
quantity_point_like_traits<QP>::quantity_from_origin(qp)}) constexpr explicit quantity_point(const QP& qp) : q_(quantity_point_like_traits<QP>::quantity_from_origin(qp))
{ {
} }
@@ -154,15 +146,12 @@ public:
template<PointOriginFor<quantity_spec> NewPO> template<PointOriginFor<quantity_spec> NewPO>
[[nodiscard]] constexpr QuantityPointOf<NewPO{}> auto point_from(NewPO origin) const [[nodiscard]] constexpr QuantityPointOf<NewPO{}> auto point_from(NewPO origin) const
{ {
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>) { if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>)
return *this; return *this;
} else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<NewPO>) { else if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin<NewPO>)
auto q = absolute(); return make_quantity_point<NewPO{}>(absolute());
return quantity_point<reference, NewPO{}, typename decltype(q)::rep>(std::move(q)); else
} else { return make_quantity_point<NewPO{}>(absolute() - origin.quantity_point.absolute());
auto q = absolute() - origin.quantity_point.absolute();
return quantity_point<reference, NewPO{}, typename decltype(q)::rep>(std::move(q));
}
} }
// data access // data access
@@ -192,7 +181,7 @@ public:
requires detail::QuantityConvertibleTo<quantity_type, quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep>> requires detail::QuantityConvertibleTo<quantity_type, quantity<::mp_units::reference<quantity_spec, U{}>{}, Rep>>
[[nodiscard]] constexpr quantity_point<::mp_units::reference<quantity_spec, U{}>{}, PO, Rep> operator[](U) const [[nodiscard]] constexpr quantity_point<::mp_units::reference<quantity_spec, U{}>{}, PO, Rep> operator[](U) const
{ {
return quantity_point<quantity_spec[U{}], PO, Rep>{*this}; return make_quantity_point<PO>(quantity_from_origin()[U{}]);
} }
// member unary operators // member unary operators
@@ -235,6 +224,18 @@ public:
q_ -= q; q_ -= q;
return *this; return *this;
} }
private:
template<PointOrigin auto PO2, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO2.quantity_spec>
friend constexpr quantity_point<Q::reference, PO2, typename Q::rep> make_quantity_point(Q&&);
template<Quantity Q>
requires std::constructible_from<quantity_type, Q> &&
ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
constexpr explicit quantity_point(Q&& q) : q_(std::forward<Q>(q))
{
}
}; };
// CTAD // CTAD
@@ -250,9 +251,7 @@ template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
const quantity<R2, Rep2>& q) const quantity<R2, Rep2>& q)
requires requires { qp.quantity_from_origin() + q; } requires requires { qp.quantity_from_origin() + q; }
{ {
auto temp = qp.quantity_from_origin() + q; return make_quantity_point<PO1>(qp.quantity_from_origin() + q);
using q_type = decltype(temp);
return quantity_point<q_type::reference, PO1, typename q_type::rep>(std::move(temp));
} }
template<auto R1, typename Rep1, auto R2, auto PO2, typename Rep2> template<auto R1, typename Rep1, auto R2, auto PO2, typename Rep2>
@@ -269,7 +268,7 @@ template<PointOrigin PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec> requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec>
[[nodiscard]] constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, Q&& q) [[nodiscard]] constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, Q&& q)
{ {
return quantity_point<Q::reference, PO{}, typename Q::rep>(std::forward<Q>(q)); return make_quantity_point<PO{}>(std::forward<Q>(q));
} }
template<Quantity Q, PointOrigin PO> template<Quantity Q, PointOrigin PO>
@@ -286,9 +285,7 @@ template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
const quantity<R2, Rep2>& q) const quantity<R2, Rep2>& q)
requires requires { qp.quantity_from_origin() - q; } requires requires { qp.quantity_from_origin() - q; }
{ {
const auto temp = qp.quantity_from_origin() - q; return make_quantity_point<PO1>(qp.quantity_from_origin() - q);
using q_type = decltype(temp);
return quantity_point<q_type::reference, PO1, typename q_type::rep>(std::move(temp));
} }
template<PointOrigin PO, Quantity Q> template<PointOrigin PO, Quantity Q>
@@ -371,4 +368,12 @@ template<QuantityPoint QP1, QuantityPointOf<QP1::absolute_point_origin> QP2>
return lhs.absolute() == rhs.absolute(); return lhs.absolute() == rhs.absolute();
} }
// make_quantity_point
template<PointOrigin auto PO, Quantity Q>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO.quantity_spec>
[[nodiscard]] constexpr quantity_point<Q::reference, PO, typename Q::rep> make_quantity_point(Q&& q)
{
return quantity_point<Q::reference, PO, typename Q::rep>(std::forward<Q>(q));
}
} // namespace mp_units } // namespace mp_units

View File

@@ -40,7 +40,14 @@ template<Unit auto U, typename C, typename Rep = double>
using time_point = quantity_point<U, chrono_point_origin<C>, Rep>; using time_point = quantity_point<U, chrono_point_origin<C>, Rep>;
static_assert(QuantityLike<std::chrono::seconds>); static_assert(QuantityLike<std::chrono::seconds>);
static_assert(!Quantity<std::chrono::seconds>);
static_assert(!QuantityPoint<std::chrono::seconds>);
static_assert(!QuantityPointLike<std::chrono::seconds>);
static_assert(QuantityPointLike<sys_seconds>); static_assert(QuantityPointLike<sys_seconds>);
static_assert(!Quantity<sys_seconds>);
static_assert(!QuantityLike<sys_seconds>);
static_assert(!QuantityPoint<sys_seconds>);
// construction - same rep type // construction - same rep type
static_assert( static_assert(
@@ -108,10 +115,8 @@ static_assert(quantity{std::chrono::years{1}} == 31556952 * s);
static_assert(quantity{1s} + 1 * s == 2 * s); static_assert(quantity{1s} + 1 * s == 2 * s);
static_assert(quantity{1s} + 1 * min == 61 * s); static_assert(quantity{1s} + 1 * min == 61 * s);
static_assert(10 * m / quantity{2s} == 5 * (m / s)); static_assert(10 * m / quantity{2s} == 5 * (m / s));
static_assert(quantity_point{sys_seconds{1s}} + 1 * s == static_assert(quantity_point{sys_seconds{1s}} + 1 * s == chrono_point_origin<std::chrono::system_clock> + 2 * s);
time_point<si::second, std::chrono::system_clock, sys_seconds::rep>{2 * s}); static_assert(quantity_point{sys_seconds{1s}} + 1 * min == chrono_point_origin<std::chrono::system_clock> + 61 * s);
static_assert(quantity_point{sys_seconds{1s}} + 1 * min ==
time_point<si::second, std::chrono::system_clock, sys_seconds::rep>{61 * s});
// to_chrono_duration // to_chrono_duration
static_assert(to_chrono_duration(1 * s) == 1s); static_assert(to_chrono_duration(1 * s) == 1s);

View File

@@ -45,8 +45,7 @@ inline constexpr struct ground_level : relative_point_origin<mean_sea_level + 42
inline constexpr struct tower_peak : relative_point_origin<ground_level + 42 * isq::height[m]> { inline constexpr struct tower_peak : relative_point_origin<ground_level + 42 * isq::height[m]> {
} tower_peak; } tower_peak;
inline constexpr struct other_ground_level : inline constexpr struct other_ground_level : relative_point_origin<mean_sea_level + 123 * isq::height[m]> {
relative_point_origin<mean_sea_level + 123 * isq::height[m]> {
} other_ground_level; } other_ground_level;
inline constexpr struct other_absolute_level : absolute_point_origin<isq::height> { inline constexpr struct other_absolute_level : absolute_point_origin<isq::height> {
@@ -281,22 +280,22 @@ static_assert(!std::convertible_to<int, quantity_point<dimensionless[one], zero,
// construction from a quantity // construction from a quantity
///////////////////////////////// /////////////////////////////////
static_assert(std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<si::metre>>); static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<si::metre>>);
static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<si::metre, mean_sea_level>>); static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<si::metre, mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<isq::height[m]>>); static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::height[m], mean_sea_level>>); static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<si::metre>>); static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<si::metre>>);
static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<isq::height[m], mean_sea_level>>); static_assert(!std::convertible_to<quantity<si::metre>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<isq::height[m]>>); static_assert(!std::constructible_from<quantity_point<si::metre, mean_sea_level>, quantity<isq::height[m]>>);
static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<si::metre, mean_sea_level>>); static_assert(!std::convertible_to<quantity<isq::height[m]>, quantity_point<si::metre, mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<special_height[m]>>); static_assert(!std::constructible_from<quantity_point<isq::height[m], mean_sea_level>, quantity<special_height[m]>>);
static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m], mean_sea_level>>); static_assert(!std::convertible_to<quantity<special_height[m]>, quantity_point<isq::height[m], mean_sea_level>>);
static_assert(std::constructible_from<quantity_point<dimensionless[one], zero>, quantity<dimensionless[one]>>); static_assert(!std::constructible_from<quantity_point<dimensionless[one], zero>, quantity<dimensionless[one]>>);
static_assert(!std::convertible_to<quantity<dimensionless[one]>, quantity_point<dimensionless[one], zero>>); static_assert(!std::convertible_to<quantity<dimensionless[one]>, quantity_point<dimensionless[one], zero>>);
// different dimensions // different dimensions