refactor: perfect forwarding interfaces improved

This commit is contained in:
Mateusz Pusz
2024-09-06 16:02:51 +02:00
parent cbe37cdadf
commit 664d52c0c0
8 changed files with 216 additions and 255 deletions

View File

@@ -91,10 +91,10 @@ struct conversion_value_traits {
* *
* @tparam To a target quantity type to cast to * @tparam To a target quantity type to cast to
*/ */
template<Quantity To, typename FwdFrom, typename From = std::remove_cvref_t<FwdFrom>> template<Quantity To, typename FwdFrom, Quantity From = std::remove_cvref_t<FwdFrom>>
requires Quantity<From> && (castable(From::quantity_spec, To::quantity_spec)) && requires(castable(From::quantity_spec, To::quantity_spec)) &&
((From::unit == To::unit && std::constructible_from<typename To::rep, typename From::rep>) || ((From::unit == To::unit && std::constructible_from<typename To::rep, typename From::rep>) ||
(From::unit != To::unit)) // && scalable_with_<typename To::rep>)) (From::unit != To::unit)) // && scalable_with_<typename To::rep>))
// TODO how to constrain the second part here? // TODO how to constrain the second part here?
[[nodiscard]] constexpr To sudo_cast(FwdFrom&& q) [[nodiscard]] constexpr To sudo_cast(FwdFrom&& q)
{ {
@@ -143,17 +143,17 @@ template<Quantity To, typename FwdFrom, typename From = std::remove_cvref_t<FwdF
* *
* @tparam ToQP a target quantity point type to which to cast to * @tparam ToQP a target quantity point type to which to cast to
*/ */
template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_cvref_t<FwdFromQP>> template<QuantityPoint ToQP, typename FwdFromQP, QuantityPoint FromQP = std::remove_cvref_t<FwdFromQP>>
requires QuantityPoint<FromQP> && (castable(FromQP::quantity_spec, ToQP::quantity_spec)) && requires(castable(FromQP::quantity_spec, ToQP::quantity_spec)) &&
(detail::same_absolute_point_origins(ToQP::point_origin, FromQP::point_origin)) && (detail::same_absolute_point_origins(ToQP::point_origin, FromQP::point_origin)) &&
((FromQP::unit == ToQP::unit && std::constructible_from<typename ToQP::rep, typename FromQP::rep>) || ((FromQP::unit == ToQP::unit && std::constructible_from<typename ToQP::rep, typename FromQP::rep>) ||
(FromQP::unit != ToQP::unit)) (FromQP::unit != ToQP::unit))
[[nodiscard]] constexpr QuantityPoint auto sudo_cast(FwdFromQP&& qp) [[nodiscard]] constexpr QuantityPoint auto sudo_cast(FwdFromQP&& qp)
{ {
if constexpr (is_same_v<std::remove_const_t<decltype(ToQP::point_origin)>, if constexpr (is_same_v<std::remove_const_t<decltype(ToQP::point_origin)>,
std::remove_const_t<decltype(FromQP::point_origin)>>) { std::remove_const_t<decltype(FromQP::point_origin)>>) {
return quantity_point{ return quantity_point{
sudo_cast<typename ToQP::quantity_type>(std::forward<FromQP>(qp).quantity_from(FromQP::point_origin)), sudo_cast<typename ToQP::quantity_type>(std::forward<FwdFromQP>(qp).quantity_from(FromQP::point_origin)),
FromQP::point_origin}; FromQP::point_origin};
} else { } else {
// it's unclear how hard we should try to avoid truncation here. For now, the only corner case we cater for, // it's unclear how hard we should try to avoid truncation here. For now, the only corner case we cater for,
@@ -176,7 +176,7 @@ template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_c
// unit, we obtain the largest possible range while not causing truncation of fractional values. This is optimal // unit, we obtain the largest possible range while not causing truncation of fractional values. This is optimal
// for the offset computation. // for the offset computation.
return sudo_cast<ToQP>( return sudo_cast<ToQP>(
sudo_cast<quantity_point<FromQP::reference, FromQP::point_origin, c_rep_type>>(std::forward<FromQP>(qp)) sudo_cast<quantity_point<FromQP::reference, FromQP::point_origin, c_rep_type>>(std::forward<FwdFromQP>(qp))
.point_for(ToQP::point_origin)); .point_for(ToQP::point_origin));
} else { } else {
// new unit may have a larger unit magnitude; we first need to convert to the new unit (potentially causing // new unit may have a larger unit magnitude; we first need to convert to the new unit (potentially causing
@@ -184,7 +184,7 @@ template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_c
// representation types. Then, we can perform the offset computation. // representation types. Then, we can perform the offset computation.
return sudo_cast<ToQP>( return sudo_cast<ToQP>(
sudo_cast<quantity_point<make_reference(FromQP::quantity_spec, ToQP::unit), FromQP::point_origin, c_rep_type>>( sudo_cast<quantity_point<make_reference(FromQP::quantity_spec, ToQP::unit), FromQP::point_origin, c_rep_type>>(
std::forward<FromQP>(qp)) std::forward<FwdFromQP>(qp))
.point_for(ToQP::point_origin)); .point_for(ToQP::point_origin));
} }
} }

View File

@@ -39,22 +39,19 @@ namespace mp_units {
template<Reference R> template<Reference R>
struct delta_ { struct delta_ {
template<typename Rep> template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character> [[nodiscard]] constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const
[[nodiscard]] constexpr quantity<R{}, std::remove_cvref_t<Rep>> operator()(Rep&& lhs) const
{ {
return quantity{std::forward<Rep>(lhs), R{}}; return quantity{std::forward<FwdRep>(lhs), R{}};
} }
}; };
template<Reference R> template<Reference R>
struct absolute_ { struct absolute_ {
template<typename Rep> template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character> [[nodiscard]] constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const
[[nodiscard]] constexpr quantity_point<R{}, default_point_origin(R{}), std::remove_cvref_t<Rep>> operator()(
Rep&& lhs) const
{ {
return quantity_point{quantity{std::forward<Rep>(lhs), R{}}}; return quantity_point{quantity{std::forward<FwdRep>(lhs), R{}}};
} }
}; };

View File

@@ -168,22 +168,23 @@ public:
quantity(quantity&&) = default; quantity(quantity&&) = default;
~quantity() = default; ~quantity() = default;
template<typename Value, Reference R2> template<typename FwdValue, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep> requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v)) constexpr quantity(FwdValue&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
{ {
} }
template<typename Value, Reference R2> template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>>
requires(!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) && requires(!detail::SameValueAs<R2{}, R, Value, Rep>) &&
detail::QuantityConvertibleTo<quantity<R2{}, std::remove_cvref_t<Value>>, quantity> detail::QuantityConvertibleTo<quantity<R2{}, Value>, quantity>
constexpr quantity(Value&& v, R2) : quantity(quantity<R2{}, std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}}) constexpr quantity(FwdValue&& v, R2) : quantity(quantity<R2{}, Value>{std::forward<FwdValue>(v), R2{}})
{ {
} }
template<detail::ValuePreservingTo<Rep> Value> template<detail::ValuePreservingTo<Rep> FwdValue>
requires(unit == ::mp_units::one) requires(unit == ::mp_units::one)
constexpr explicit(false) quantity(Value&& v) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v)) constexpr explicit(false) quantity(FwdValue&& v) :
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
{ {
} }
@@ -209,11 +210,11 @@ public:
quantity& operator=(const quantity&) = default; quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default; quantity& operator=(quantity&&) = default;
template<detail::ValuePreservingTo<Rep> Value> template<detail::ValuePreservingTo<Rep> FwdValue>
requires(unit == ::mp_units::one) requires(unit == ::mp_units::one)
constexpr quantity& operator=(Value&& v) constexpr quantity& operator=(FwdValue&& v)
{ {
numerical_value_is_an_implementation_detail_ = std::forward<Value>(v); numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(v);
return *this; return *this;
} }
@@ -355,16 +356,16 @@ public:
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference}; return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference};
} }
template<typename Q> template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
friend constexpr decltype(auto) operator++(Q&& q) friend constexpr decltype(auto) operator++(FwdQ&& q)
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) { requires requires(rep v) {
{ {
++v ++v
} -> std::same_as<rep&>; } -> std::same_as<rep&>;
} }
{ {
++q.numerical_value_is_an_implementation_detail_; ++q.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(q); return std::forward<FwdQ>(q);
} }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator++(int) [[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator++(int)
@@ -377,16 +378,16 @@ public:
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference}; return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference};
} }
template<typename Q> template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
friend constexpr decltype(auto) operator--(Q&& q) friend constexpr decltype(auto) operator--(FwdQ&& q)
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) { requires requires(rep v) {
{ {
--v --v
} -> std::same_as<rep&>; } -> std::same_as<rep&>;
} }
{ {
--q.numerical_value_is_an_implementation_detail_; --q.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(q); return std::forward<FwdQ>(q);
} }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator--(int) [[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator--(int)
@@ -400,97 +401,92 @@ public:
} }
// compound assignment operators // compound assignment operators
template<typename Q> template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) { requires requires(rep a, rep b) {
{ {
a += b a += b
} -> std::same_as<rep&>; } -> std::same_as<rep&>;
} }
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs) friend constexpr decltype(auto) operator+=(FwdQ&& lhs, const quantity& rhs)
{ {
lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs); return std::forward<FwdQ>(lhs);
} }
template<typename Q> template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) { requires requires(rep a, rep b) {
{ {
a -= b a -= b
} -> std::same_as<rep&>; } -> std::same_as<rep&>;
} }
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs) friend constexpr decltype(auto) operator-=(FwdQ&& lhs, const quantity& rhs)
{ {
lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs); return std::forward<FwdQ>(lhs);
} }
template<typename Q> template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!treat_as_floating_point<rep>) && requires(!treat_as_floating_point<rep>) && requires(rep a, rep b) {
requires(rep a, rep b) { {
{ a %= b
a %= b } -> std::same_as<rep&>;
} -> std::same_as<rep&>; }
} friend constexpr decltype(auto) operator%=(FwdQ&& lhs, const quantity& rhs)
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs)
{ {
MP_UNITS_EXPECTS_DEBUG(rhs != zero()); MP_UNITS_EXPECTS_DEBUG(rhs != zero());
lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs); return std::forward<FwdQ>(lhs);
} }
template<typename Q, typename Value> template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) && requires(!Quantity<Value>) && requires(rep a, const Value b) {
requires(rep a, const Value b) { {
{ a *= b
a *= b } -> std::same_as<rep&>;
} -> std::same_as<rep&>; }
} friend constexpr decltype(auto) operator*=(FwdQ&& lhs, const Value& v)
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v)
{ {
lhs.numerical_value_is_an_implementation_detail_ *= v; lhs.numerical_value_is_an_implementation_detail_ *= v;
return std::forward<Q>(lhs); return std::forward<FwdQ>(lhs);
} }
template<typename Q1, QuantityOf<dimensionless> Q2> template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) && requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
requires(rep a, const typename Q2::rep b) { {
{ a *= b
a *= b } -> std::same_as<rep&>;
} -> std::same_as<rep&>; }
} friend constexpr decltype(auto) operator*=(FwdQ1&& lhs, const Q2& rhs)
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
{ {
lhs.numerical_value_is_an_implementation_detail_ *= rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ *= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs); return std::forward<FwdQ1>(lhs);
} }
template<typename Q, typename Value> template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) && requires(!Quantity<Value>) && requires(rep a, const Value b) {
requires(rep a, const Value b) { {
{ a /= b
a /= b } -> std::same_as<rep&>;
} -> std::same_as<rep&>; }
} friend constexpr decltype(auto) operator/=(FwdQ&& lhs, const Value& v)
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
{ {
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero()); MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
lhs.numerical_value_is_an_implementation_detail_ /= v; lhs.numerical_value_is_an_implementation_detail_ /= v;
return std::forward<Q>(lhs); return std::forward<FwdQ>(lhs);
} }
template<typename Q1, QuantityOf<dimensionless> Q2> template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) && requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
requires(rep a, const typename Q2::rep b) { {
{ a /= b
a /= b } -> std::same_as<rep&>;
} -> std::same_as<rep&>; }
} friend constexpr decltype(auto) operator/=(FwdQ1&& lhs, const Q2& rhs)
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
{ {
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_; lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs); return std::forward<FwdQ1>(lhs);
} }
// binary operators on quantities // binary operators on quantities

View File

@@ -56,13 +56,11 @@ namespace mp_units {
* *
* @tparam ToQS a quantity specification to use for a target quantity * @tparam ToQS a quantity specification to use for a target quantity
*/ */
template<QuantitySpec auto ToQS, typename Q> template<QuantitySpec auto ToQS, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && requires detail::QuantitySpecCastableTo<Q::quantity_spec, ToQS>
detail::QuantitySpecCastableTo<std::remove_reference_t<Q>::quantity_spec, ToQS> [[nodiscard]] constexpr Quantity auto quantity_cast(FwdQ&& q)
[[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, make_reference(ToQS, Q::unit)};
make_reference(ToQS, std::remove_reference_t<Q>::unit)};
} }
/** /**
@@ -82,13 +80,12 @@ template<QuantitySpec auto ToQS, typename Q>
* *
* @tparam ToQS a quantity specification to use for a target quantity point * @tparam ToQS a quantity specification to use for a target quantity point
*/ */
template<QuantitySpec auto ToQS, typename QP> template<QuantitySpec auto ToQS, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires QuantityPoint<std::remove_cvref_t<QP>> && requires detail::QuantitySpecCastableTo<QP::quantity_spec, ToQS>
detail::QuantitySpecCastableTo<std::remove_reference_t<QP>::quantity_spec, ToQS> [[nodiscard]] constexpr QuantityPoint auto quantity_cast(FwdQP&& qp)
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(QP&& qp)
{ {
return QP{quantity_cast<ToQS>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_), return QP{quantity_cast<ToQS>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin}; QP::point_origin};
} }
} // namespace mp_units } // namespace mp_units

View File

@@ -52,18 +52,16 @@ template<PointOrigin PO>
} }
struct point_origin_interface { struct point_origin_interface {
template<PointOrigin PO, Quantity Q> template<PointOrigin PO, typename FwdQ, QuantityOf<PO::quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec> [[nodiscard]] friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, FwdQ&& q)
[[nodiscard]] friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, Q&& q)
{ {
return quantity_point{std::forward<Q>(q), PO{}}; return quantity_point{std::forward<FwdQ>(q), PO{}};
} }
template<Quantity Q, PointOrigin PO> template<Quantity FwdQ, PointOrigin PO, QuantityOf<PO::quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires ReferenceOf<std::remove_const_t<decltype(Q::reference)>, PO::quantity_spec> [[nodiscard]] friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(FwdQ&& q, PO po)
[[nodiscard]] friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(Q&& q, PO po)
{ {
return po + std::forward<Q>(q); return po + std::forward<FwdQ>(q);
} }
template<PointOrigin PO, Quantity Q> template<PointOrigin PO, Quantity Q>
@@ -206,27 +204,26 @@ public:
quantity_point(quantity_point&&) = default; quantity_point(quantity_point&&) = default;
~quantity_point() = default; ~quantity_point() = default;
template<typename Q> template<typename FwdQ, QuantityOf<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires QuantityOf<std::remove_cvref_t<Q>, quantity_spec> && std::constructible_from<quantity_type, Q> && requires std::constructible_from<quantity_type, FwdQ> && (point_origin == default_point_origin(R)) &&
(point_origin == default_point_origin(R)) && (implicitly_convertible(Q::quantity_spec, quantity_spec)) (implicitly_convertible(Q::quantity_spec, quantity_spec))
constexpr explicit quantity_point(Q&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q)) constexpr explicit quantity_point(FwdQ&& q) : quantity_from_origin_is_an_implementation_detail_(std::forward<FwdQ>(q))
{ {
} }
template<typename Q> template<typename FwdQ, QuantityOf<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires QuantityOf<std::remove_cvref_t<Q>, quantity_spec> && std::constructible_from<quantity_type, Q> requires std::constructible_from<quantity_type, FwdQ>
constexpr quantity_point(Q&& q, decltype(PO)) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q)) constexpr quantity_point(FwdQ&& q, decltype(PO)) :
quantity_from_origin_is_an_implementation_detail_(std::forward<FwdQ>(q))
{ {
} }
template<typename Q, PointOrigin PO2> template<typename FwdQ, PointOrigin PO2, QuantityOf<PO2::quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && std::constructible_from<quantity_type, Q> && requires std::constructible_from<quantity_type, FwdQ> && detail::SameAbsolutePointOriginAs<PO2, PO>
ReferenceOf<std::remove_const_t<decltype(std::remove_reference_t<Q>::reference)>, PO2::quantity_spec> && constexpr quantity_point(FwdQ&& q, PO2) :
detail::SameAbsolutePointOriginAs<PO2, PO>
constexpr quantity_point(Q&& q, PO2) :
quantity_point( quantity_point(
quantity_point<std::remove_reference_t<Q>::reference, PO2{}, typename std::remove_reference_t<Q>::rep>{ quantity_point<std::remove_reference_t<Q>::reference, PO2{}, typename std::remove_reference_t<Q>::rep>{
std::forward<Q>(q), PO2{}}) std::forward<FwdQ>(q), PO2{}})
{ {
} }
@@ -413,13 +410,12 @@ public:
} }
// member unary operators // member unary operators
template<typename QP> template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
friend constexpr decltype(auto) operator++(QP&& qp) friend constexpr decltype(auto) operator++(FwdQP&& qp)
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> && requires requires { ++qp.quantity_from_origin_is_an_implementation_detail_; }
requires { ++qp.quantity_from_origin_is_an_implementation_detail_; }
{ {
++qp.quantity_from_origin_is_an_implementation_detail_; ++qp.quantity_from_origin_is_an_implementation_detail_;
return std::forward<QP>(qp); return std::forward<FwdQP>(qp);
} }
[[nodiscard]] constexpr quantity_point operator++(int) [[nodiscard]] constexpr quantity_point operator++(int)
@@ -428,13 +424,12 @@ public:
return {quantity_from_origin_is_an_implementation_detail_++, PO}; return {quantity_from_origin_is_an_implementation_detail_++, PO};
} }
template<typename QP> template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
friend constexpr decltype(auto) operator--(QP&& qp) friend constexpr decltype(auto) operator--(FwdQP&& qp)
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> && requires requires { --qp.quantity_from_origin_is_an_implementation_detail_; }
requires { --qp.quantity_from_origin_is_an_implementation_detail_; }
{ {
--qp.quantity_from_origin_is_an_implementation_detail_; --qp.quantity_from_origin_is_an_implementation_detail_;
return std::forward<QP>(qp); return std::forward<FwdQP>(qp);
} }
[[nodiscard]] constexpr quantity_point operator--(int) [[nodiscard]] constexpr quantity_point operator--(int)
@@ -444,22 +439,20 @@ public:
} }
// compound assignment operators // compound assignment operators
template<typename QP> template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> && requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; } friend constexpr decltype(auto) operator+=(FwdQP&& qp, const quantity_type& q)
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity_type& q)
{ {
qp.quantity_from_origin_is_an_implementation_detail_ += q; qp.quantity_from_origin_is_an_implementation_detail_ += q;
return std::forward<QP>(qp); return std::forward<FwdQP>(qp);
} }
template<typename QP> template<typename FwdQP, std::derived_from<quantity_point> QP = std::remove_cvref_t<FwdQP>>
requires std::derived_from<std::remove_cvref_t<QP>, quantity_point> && requires requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; } friend constexpr decltype(auto) operator-=(FwdQP&& qp, const quantity_type& q)
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity_type& q)
{ {
qp.quantity_from_origin_is_an_implementation_detail_ -= q; qp.quantity_from_origin_is_an_implementation_detail_ -= q;
return std::forward<QP>(qp); return std::forward<FwdQP>(qp);
} }
// binary operators on quantity points // binary operators on quantity points

View File

@@ -159,13 +159,11 @@ struct quantity_spec_interface : quantity_spec_interface_base {
return make_reference(self, u); return make_reference(self, u);
} }
template<typename Self, typename Q> template<typename Self, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && requires QuantitySpecExplicitlyConvertibleTo<Q::quantity_spec, Self{}>
QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, Self{}> [[nodiscard]] constexpr Quantity auto operator()(this Self self, FwdQ&& q)
[[nodiscard]] constexpr Quantity auto operator()(this Self self, Q&& q)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, make_reference(self, Q::unit)};
make_reference(self, std::remove_cvref_t<Q>::unit)};
} }
#else #else
template<typename Self_ = Self, UnitOf<Self_{}> U> template<typename Self_ = Self, UnitOf<Self_{}> U>
@@ -174,13 +172,12 @@ struct quantity_spec_interface : quantity_spec_interface_base {
return make_reference(Self{}, u); return make_reference(Self{}, u);
} }
template<typename Q, typename Self_ = Self> template<typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>, typename Self_ = Self>
requires Quantity<std::remove_cvref_t<Q>> && requires QuantitySpecExplicitlyConvertibleTo<Q::quantity_spec, Self_{}>
QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, Self_{}> [[nodiscard]] constexpr Quantity auto operator()(FwdQ&& q) const
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_,
make_reference(Self{}, std::remove_cvref_t<Q>::unit)}; make_reference(Self{}, Q::unit)};
} }
#endif #endif
}; };
@@ -371,13 +368,12 @@ struct quantity_spec<Self, QS, Args...> : detail::propagate_equation<QS>, detail
return detail::make_reference(Self{}, u); return detail::make_reference(Self{}, u);
} }
template<typename Q, typename Self_ = Self> template<typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>, typename Self_ = Self>
requires Quantity<std::remove_cvref_t<Q>> && requires detail::QuantitySpecExplicitlyConvertibleTo<Q::quantity_spec, Self_{}>
detail::QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, Self_{}> [[nodiscard]] constexpr Quantity auto operator()(FwdQ&& q) const
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_,
detail::make_reference(Self{}, std::remove_cvref_t<Q>::unit)}; detail::make_reference(Self{}, Q::unit)};
} }
#endif #endif
}; };

View File

@@ -178,36 +178,36 @@ struct reference {
}; };
template<typename Rep, Reference R> template<typename FwdRep, Reference R,
requires(!detail::OffsetUnit<decltype(get_unit(R{}))>) && RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character> requires(!detail::OffsetUnit<decltype(get_unit(R{}))>)
[[nodiscard]] constexpr quantity<R{}, std::remove_cvref_t<Rep>> operator*(Rep&& lhs, R) [[nodiscard]] constexpr quantity<R{}, Rep> operator*(FwdRep&& lhs, R)
{ {
return quantity{std::forward<Rep>(lhs), R{}}; return quantity{std::forward<FwdRep>(lhs), R{}};
} }
template<typename Rep, Reference R> template<typename FwdRep, Reference R,
requires(!detail::OffsetUnit<decltype(get_unit(R{}))>) && RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character> requires(!detail::OffsetUnit<decltype(get_unit(R{}))>)
[[nodiscard]] constexpr quantity<inverse(R{}), std::remove_cvref_t<Rep>> operator/(Rep&& lhs, R) [[nodiscard]] constexpr quantity<inverse(R{}), Rep> operator/(FwdRep&& lhs, R)
{ {
return quantity{std::forward<Rep>(lhs), inverse(R{})}; return quantity{std::forward<FwdRep>(lhs), inverse(R{})};
} }
template<typename Rep, Reference R> template<typename FwdRep, Reference R,
requires detail::OffsetUnit<decltype(get_unit(R{}))> && RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character> requires detail::OffsetUnit<decltype(get_unit(R{}))>
[[noreturn]] constexpr auto operator*(Rep&&, R) [[noreturn]] constexpr auto operator*(FwdRep&&, R)
{ {
static_assert(!detail::OffsetUnit<decltype(get_unit(R{}))>, static_assert(!detail::OffsetUnit<decltype(get_unit(R{}))>,
"References using offset units (e.g., temperatures) may be constructed only with the `delta` or " "References using offset units (e.g., temperatures) may be constructed only with the `delta` or "
"`absolute` helpers"); "`absolute` helpers");
} }
template<typename Rep, Reference R> template<typename FwdRep, Reference R,
requires detail::OffsetUnit<decltype(get_unit(R{}))> && RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character> requires detail::OffsetUnit<decltype(get_unit(R{}))>
[[noreturn]] constexpr auto operator/(Rep&&, R) [[noreturn]] constexpr auto operator/(FwdRep&&, R)
{ {
static_assert(!detail::OffsetUnit<decltype(get_unit(R{}))>, static_assert(!detail::OffsetUnit<decltype(get_unit(R{}))>,
"References using offset units (e.g., temperatures) may be constructed only with the `delta` or " "References using offset units (e.g., temperatures) may be constructed only with the `delta` or "
@@ -234,20 +234,16 @@ constexpr auto operator/(R, Rep&&)
= delete; = delete;
#endif #endif
template<typename Q, Reference R> template<typename FwdQ, Reference R, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> [[nodiscard]] constexpr Quantity auto operator*(FwdQ&& q, R)
[[nodiscard]] constexpr Quantity auto operator*(Q&& q, R)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, Q::reference * R{}};
std::remove_cvref_t<Q>::reference * R{}};
} }
template<typename Q, Reference R> template<typename FwdQ, Reference R, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> [[nodiscard]] constexpr Quantity auto operator/(FwdQ&& q, R)
[[nodiscard]] constexpr Quantity auto operator/(Q&& q, R)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, Q::reference / R{}};
std::remove_cvref_t<Q>::reference / R{}};
} }
template<Reference R, typename Q> template<Reference R, typename Q>

View File

@@ -44,13 +44,12 @@ namespace mp_units {
* *
* @tparam ToU a unit to use for a target quantity * @tparam ToU a unit to use for a target quantity
*/ */
template<Unit auto ToU, typename Q> template<Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToU)) requires(convertible(Q::reference, ToU))
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q) [[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
{ {
using q_type = std::remove_reference_t<Q>; return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), typename Q::rep>>(
return detail::sudo_cast<quantity<detail::make_reference(q_type::quantity_spec, ToU), typename q_type::rep>>( std::forward<FwdQ>(q));
std::forward<Q>(q));
} }
/** /**
@@ -63,13 +62,11 @@ template<Unit auto ToU, typename Q>
* *
* @tparam ToRep a representation type to use for a target quantity * @tparam ToRep a representation type to use for a target quantity
*/ */
template<Representation ToRep, typename Q> template<Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && requires RepresentationOf<ToRep, Q::quantity_spec.character> && std::constructible_from<ToRep, typename Q::rep>
RepresentationOf<ToRep, std::remove_reference_t<Q>::quantity_spec.character> && [[nodiscard]] constexpr quantity<Q::reference, ToRep> value_cast(FwdQ&& q)
std::constructible_from<ToRep, typename std::remove_reference_t<Q>::rep>
[[nodiscard]] constexpr quantity<std::remove_reference_t<Q>::reference, ToRep> value_cast(Q&& q)
{ {
return detail::sudo_cast<quantity<std::remove_reference_t<Q>::reference, ToRep>>(std::forward<Q>(q)); return detail::sudo_cast<quantity<Q::reference, ToRep>>(std::forward<FwdQ>(q));
} }
/** /**
@@ -83,14 +80,12 @@ template<Representation ToRep, typename Q>
* @tparam ToU a unit to use for the target quantity * @tparam ToU a unit to use for the target quantity
* @tparam ToRep a representation type to use for the target quantity * @tparam ToRep a representation type to use for the target quantity
*/ */
template<Unit auto ToU, Representation ToRep, typename Q> template<Unit auto ToU, Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToU)) && requires(convertible(Q::reference, ToU)) && RepresentationOf<ToRep, Q::quantity_spec.character> &&
RepresentationOf<ToRep, std::remove_reference_t<Q>::quantity_spec.character> && std::constructible_from<ToRep, typename Q::rep>
std::constructible_from<ToRep, typename std::remove_reference_t<Q>::rep> [[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
{ {
using q_type = std::remove_reference_t<Q>; return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), ToRep>>(std::forward<FwdQ>(q));
return detail::sudo_cast<quantity<detail::make_reference(q_type::quantity_spec, ToU), ToRep>>(std::forward<Q>(q));
} }
@@ -108,13 +103,12 @@ template<Unit auto ToU, Representation ToRep, typename Q>
* *
* @tparam ToQ a target quantity type to which to cast the representation * @tparam ToQ a target quantity type to which to cast the representation
*/ */
template<Quantity ToQ, typename Q> template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToQ::unit)) && requires(convertible(Q::reference, ToQ::unit)) &&
(ToQ::quantity_spec == std::remove_reference_t<Q>::quantity_spec) && (ToQ::quantity_spec == Q::quantity_spec) && std::constructible_from<typename ToQ::rep, typename Q::rep>
std::constructible_from<typename ToQ::rep, typename std::remove_reference_t<Q>::rep> [[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
{ {
return detail::sudo_cast<ToQ>(std::forward<Q>(q)); return detail::sudo_cast<ToQ>(std::forward<FwdQ>(q));
} }
/** /**
@@ -127,12 +121,12 @@ template<Quantity ToQ, typename Q>
* *
* @tparam ToU a unit to use for a target quantity point * @tparam ToU a unit to use for a target quantity point
*/ */
template<Unit auto ToU, typename QP> template<Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToU)) requires(convertible(QP::reference, ToU))
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp) [[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{ {
return quantity_point{value_cast<ToU>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_), return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin}; QP::point_origin};
} }
/** /**
@@ -145,16 +139,12 @@ template<Unit auto ToU, typename QP>
* *
* @tparam ToRep a representation type to use for a target quantity point * @tparam ToRep a representation type to use for a target quantity point
*/ */
template<Representation ToRep, typename QP> template<Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires QuantityPoint<std::remove_cvref_t<QP>> && requires RepresentationOf<ToRep, QP::quantity_spec.character> && std::constructible_from<ToRep, typename QP::rep>
RepresentationOf<ToRep, std::remove_reference_t<QP>::quantity_spec.character> && [[nodiscard]] constexpr quantity_point<QP::reference, QP::point_origin, ToRep> value_cast(FwdQP&& qp)
std::constructible_from<ToRep, typename std::remove_reference_t<QP>::rep>
[[nodiscard]] constexpr quantity_point<std::remove_reference_t<QP>::reference,
std::remove_reference_t<QP>::point_origin, ToRep>
value_cast(QP&& qp)
{ {
return {value_cast<ToRep>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_), return {value_cast<ToRep>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin}; QP::point_origin};
} }
/** /**
@@ -168,14 +158,14 @@ value_cast(QP&& qp)
* @tparam ToU a unit to use for the target quantity * @tparam ToU a unit to use for the target quantity
* @tparam ToRep a representation type to use for the target quantity * @tparam ToRep a representation type to use for the target quantity
*/ */
template<Unit auto ToU, Representation ToRep, typename QP> template<Unit auto ToU, Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToU)) && requires(convertible(QP::reference, ToU)) && RepresentationOf<ToRep, QP::quantity_spec.character> &&
RepresentationOf<ToRep, std::remove_reference_t<QP>::quantity_spec.character> && std::constructible_from<ToRep, typename QP::rep>
std::constructible_from<ToRep, typename std::remove_reference_t<QP>::rep> [[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
{ {
return quantity_point{value_cast<ToU, ToRep>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_), return quantity_point{
std::remove_reference_t<QP>::point_origin}; value_cast<ToU, ToRep>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
QP::point_origin};
} }
/** /**
@@ -194,14 +184,13 @@ template<Unit auto ToU, Representation ToRep, typename QP>
* *
* @tparam ToQ a target quantity type to which to cast the representation of the point * @tparam ToQ a target quantity type to which to cast the representation of the point
*/ */
template<Quantity ToQ, typename QP> template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToQ::unit)) && requires(convertible(QP::reference, ToQ::unit)) &&
(ToQ::quantity_spec == std::remove_reference_t<QP>::quantity_spec) && (ToQ::quantity_spec == QP::quantity_spec) && std::constructible_from<typename ToQ::rep, typename QP::rep>
std::constructible_from<typename ToQ::rep, typename std::remove_reference_t<QP>::rep> [[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
{ {
return quantity_point{value_cast<ToQ>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_), return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin}; QP::point_origin};
} }
/** /**
@@ -232,16 +221,13 @@ template<Quantity ToQ, typename QP>
* *
* @tparam ToQP a target quantity point type to which to cast the representation of the point * @tparam ToQP a target quantity point type to which to cast the representation of the point
*/ */
template<QuantityPoint ToQP, typename QP> template<QuantityPoint ToQP, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires QuantityPoint<std::remove_cvref_t<QP>> && requires(convertible(QP::reference, ToQP::unit)) && (ToQP::quantity_spec == QP::quantity_spec) &&
(convertible(std::remove_reference_t<QP>::reference, ToQP::unit)) && (detail::same_absolute_point_origins(ToQP::point_origin, QP::point_origin)) &&
(ToQP::quantity_spec == std::remove_reference_t<QP>::quantity_spec) && std::constructible_from<typename ToQP::rep, typename QP::rep>
(detail::same_absolute_point_origins(ToQP::point_origin, std::remove_reference_t<QP>::point_origin)) && [[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
std::constructible_from<typename ToQP::rep, typename std::remove_reference_t<QP>::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
{ {
return detail::sudo_cast<ToQP>(std::forward<QP>(qp)); return detail::sudo_cast<ToQP>(std::forward<FwdQP>(qp));
} }
} // namespace mp_units } // namespace mp_units