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,8 +91,8 @@ struct conversion_value_traits {
*
* @tparam To a target quantity type to cast to
*/
template<Quantity To, typename FwdFrom, typename From = std::remove_cvref_t<FwdFrom>>
requires Quantity<From> && (castable(From::quantity_spec, To::quantity_spec)) &&
template<Quantity To, typename FwdFrom, Quantity From = std::remove_cvref_t<FwdFrom>>
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)) // && scalable_with_<typename To::rep>))
// TODO how to constrain the second part here?
@@ -143,8 +143,8 @@ template<Quantity To, typename FwdFrom, typename From = std::remove_cvref_t<FwdF
*
* @tparam ToQP a target quantity point type to which to cast to
*/
template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_cvref_t<FwdFromQP>>
requires QuantityPoint<FromQP> && (castable(FromQP::quantity_spec, ToQP::quantity_spec)) &&
template<QuantityPoint ToQP, typename FwdFromQP, QuantityPoint FromQP = std::remove_cvref_t<FwdFromQP>>
requires(castable(FromQP::quantity_spec, ToQP::quantity_spec)) &&
(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))
@@ -153,7 +153,7 @@ template<QuantityPoint ToQP, typename FwdFromQP, typename FromQP = std::remove_c
if constexpr (is_same_v<std::remove_const_t<decltype(ToQP::point_origin)>,
std::remove_const_t<decltype(FromQP::point_origin)>>) {
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};
} else {
// 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
// for the offset computation.
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));
} else {
// 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.
return sudo_cast<ToQP>(
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));
}
}

View File

@@ -39,22 +39,19 @@ namespace mp_units {
template<Reference R>
struct delta_ {
template<typename Rep>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
[[nodiscard]] constexpr quantity<R{}, std::remove_cvref_t<Rep>> operator()(Rep&& lhs) const
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const
{
return quantity{std::forward<Rep>(lhs), R{}};
return quantity{std::forward<FwdRep>(lhs), R{}};
}
};
template<Reference R>
struct absolute_ {
template<typename Rep>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(R{}).character>
[[nodiscard]] constexpr quantity_point<R{}, default_point_origin(R{}), std::remove_cvref_t<Rep>> operator()(
Rep&& lhs) const
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{}).character> Rep = std::remove_cvref_t<FwdRep>>
[[nodiscard]] constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& 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() = default;
template<typename Value, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>
constexpr quantity(Value&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
template<typename FwdValue, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(FwdValue&& v, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(v))
{
}
template<typename Value, Reference R2>
requires(!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) &&
detail::QuantityConvertibleTo<quantity<R2{}, std::remove_cvref_t<Value>>, quantity>
constexpr quantity(Value&& v, R2) : quantity(quantity<R2{}, std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}})
template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>>
requires(!detail::SameValueAs<R2{}, R, Value, Rep>) &&
detail::QuantityConvertibleTo<quantity<R2{}, Value>, quantity>
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)
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=(quantity&&) = default;
template<detail::ValuePreservingTo<Rep> Value>
template<detail::ValuePreservingTo<Rep> FwdValue>
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;
}
@@ -355,16 +356,16 @@ public:
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, reference};
}
template<typename Q>
friend constexpr decltype(auto) operator++(Q&& q)
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
friend constexpr decltype(auto) operator++(FwdQ&& q)
requires requires(rep v) {
{
++v
} -> std::same_as<rep&>;
}
{
++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)
@@ -377,16 +378,16 @@ public:
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, reference};
}
template<typename Q>
friend constexpr decltype(auto) operator--(Q&& q)
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep v) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
friend constexpr decltype(auto) operator--(FwdQ&& q)
requires requires(rep v) {
{
--v
} -> std::same_as<rep&>;
}
{
--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)
@@ -400,97 +401,92 @@ public:
}
// compound assignment operators
template<typename Q>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires requires(rep a, rep b) {
{
a += b
} -> 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_;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}
template<typename Q>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && requires(rep a, rep b) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires requires(rep a, rep b) {
{
a -= b
} -> 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_;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}
template<typename Q>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!treat_as_floating_point<rep>) &&
requires(rep a, rep b) {
template<typename FwdQ, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires(!treat_as_floating_point<rep>) && requires(rep a, rep b) {
{
a %= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs)
friend constexpr decltype(auto) operator%=(FwdQ&& lhs, const quantity& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != zero());
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>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) &&
requires(rep a, const Value b) {
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires(!Quantity<Value>) && requires(rep a, const Value b) {
{
a *= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v)
friend constexpr decltype(auto) operator*=(FwdQ&& lhs, const Value& 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>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
requires(rep a, const typename Q2::rep b) {
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
{
a *= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
friend constexpr decltype(auto) operator*=(FwdQ1&& lhs, const Q2& rhs)
{
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>
requires std::derived_from<std::remove_cvref_t<Q>, quantity> && (!Quantity<Value>) &&
requires(rep a, const Value b) {
template<typename FwdQ, typename Value, std::derived_from<quantity> Q = std::remove_cvref_t<FwdQ>>
requires(!Quantity<Value>) && requires(rep a, const Value b) {
{
a /= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
friend constexpr decltype(auto) operator/=(FwdQ&& lhs, const Value& v)
{
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
lhs.numerical_value_is_an_implementation_detail_ /= v;
return std::forward<Q>(lhs);
return std::forward<FwdQ>(lhs);
}
template<typename Q1, QuantityOf<dimensionless> Q2>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
requires(rep a, const typename Q2::rep b) {
template<typename FwdQ1, QuantityOf<dimensionless> Q2, std::derived_from<quantity> Q1 = std::remove_cvref_t<FwdQ1>>
requires(Q2::unit == ::mp_units::one) && requires(rep a, const typename Q2::rep b) {
{
a /= b
} -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
friend constexpr decltype(auto) operator/=(FwdQ1&& lhs, const Q2& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
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

View File

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

View File

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

View File

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

View File

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

View File

@@ -44,13 +44,12 @@ namespace mp_units {
*
* @tparam ToU a unit to use for a target quantity
*/
template<Unit auto ToU, typename Q>
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToU))
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
template<Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires(convertible(Q::reference, ToU))
[[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_type::quantity_spec, ToU), typename q_type::rep>>(
std::forward<Q>(q));
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), typename Q::rep>>(
std::forward<FwdQ>(q));
}
/**
@@ -63,13 +62,11 @@ template<Unit auto ToU, typename Q>
*
* @tparam ToRep a representation type to use for a target quantity
*/
template<Representation ToRep, typename Q>
requires Quantity<std::remove_cvref_t<Q>> &&
RepresentationOf<ToRep, std::remove_reference_t<Q>::quantity_spec.character> &&
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)
template<Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires RepresentationOf<ToRep, Q::quantity_spec.character> && std::constructible_from<ToRep, typename Q::rep>
[[nodiscard]] constexpr quantity<Q::reference, ToRep> value_cast(FwdQ&& 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 ToRep a representation type to use for the target quantity
*/
template<Unit auto ToU, Representation ToRep, typename Q>
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToU)) &&
RepresentationOf<ToRep, std::remove_reference_t<Q>::quantity_spec.character> &&
std::constructible_from<ToRep, typename std::remove_reference_t<Q>::rep>
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
template<Unit auto ToU, Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires(convertible(Q::reference, ToU)) && RepresentationOf<ToRep, Q::quantity_spec.character> &&
std::constructible_from<ToRep, typename Q::rep>
[[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_type::quantity_spec, ToU), ToRep>>(std::forward<Q>(q));
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), ToRep>>(std::forward<FwdQ>(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
*/
template<Quantity ToQ, typename Q>
requires Quantity<std::remove_cvref_t<Q>> && (convertible(std::remove_reference_t<Q>::reference, ToQ::unit)) &&
(ToQ::quantity_spec == std::remove_reference_t<Q>::quantity_spec) &&
std::constructible_from<typename ToQ::rep, typename std::remove_reference_t<Q>::rep>
[[nodiscard]] constexpr Quantity auto value_cast(Q&& q)
template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires(convertible(Q::reference, ToQ::unit)) &&
(ToQ::quantity_spec == Q::quantity_spec) && std::constructible_from<typename ToQ::rep, typename Q::rep>
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& 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
*/
template<Unit auto ToU, typename QP>
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToU))
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
template<Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToU))
[[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_),
std::remove_reference_t<QP>::point_origin};
return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
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
*/
template<Representation ToRep, typename QP>
requires QuantityPoint<std::remove_cvref_t<QP>> &&
RepresentationOf<ToRep, std::remove_reference_t<QP>::quantity_spec.character> &&
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)
template<Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires RepresentationOf<ToRep, QP::quantity_spec.character> && std::constructible_from<ToRep, typename QP::rep>
[[nodiscard]] constexpr quantity_point<QP::reference, QP::point_origin, ToRep> value_cast(FwdQP&& qp)
{
return {value_cast<ToRep>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin};
return {value_cast<ToRep>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
QP::point_origin};
}
/**
@@ -168,14 +158,14 @@ value_cast(QP&& qp)
* @tparam ToU a unit 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>
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToU)) &&
RepresentationOf<ToRep, std::remove_reference_t<QP>::quantity_spec.character> &&
std::constructible_from<ToRep, typename std::remove_reference_t<QP>::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
template<Unit auto ToU, Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToU)) && RepresentationOf<ToRep, QP::quantity_spec.character> &&
std::constructible_from<ToRep, typename QP::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return quantity_point{value_cast<ToU, ToRep>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin};
return quantity_point{
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
*/
template<Quantity ToQ, typename QP>
requires QuantityPoint<std::remove_cvref_t<QP>> && (convertible(std::remove_reference_t<QP>::reference, ToQ::unit)) &&
(ToQ::quantity_spec == std::remove_reference_t<QP>::quantity_spec) &&
std::constructible_from<typename ToQ::rep, typename std::remove_reference_t<QP>::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToQ::unit)) &&
(ToQ::quantity_spec == QP::quantity_spec) && std::constructible_from<typename ToQ::rep, typename QP::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return quantity_point{value_cast<ToQ>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
std::remove_reference_t<QP>::point_origin};
return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
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
*/
template<QuantityPoint ToQP, typename QP>
requires QuantityPoint<std::remove_cvref_t<QP>> &&
(convertible(std::remove_reference_t<QP>::reference, ToQP::unit)) &&
(ToQP::quantity_spec == std::remove_reference_t<QP>::quantity_spec) &&
(detail::same_absolute_point_origins(ToQP::point_origin, std::remove_reference_t<QP>::point_origin)) &&
std::constructible_from<typename ToQP::rep, typename std::remove_reference_t<QP>::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(QP&& qp)
template<QuantityPoint ToQP, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToQP::unit)) && (ToQP::quantity_spec == QP::quantity_spec) &&
(detail::same_absolute_point_origins(ToQP::point_origin, QP::point_origin)) &&
std::constructible_from<typename ToQP::rep, typename QP::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return detail::sudo_cast<ToQP>(std::forward<QP>(qp));
return detail::sudo_cast<ToQP>(std::forward<FwdQP>(qp));
}
} // namespace mp_units