refactor: constraints refactoring

This commit is contained in:
Mateusz Pusz
2025-04-29 13:26:27 +02:00
parent d441a90164
commit 2d1bf8a689
7 changed files with 182 additions and 210 deletions

View File

@ -61,31 +61,40 @@ template<Unit UFrom, Unit UTo>
return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag);
}
template<typename FromRep, typename ToRep, auto FromUnit, auto ToUnit>
concept ValuePreservingTo =
Unit<MP_UNITS_REMOVE_CONST(decltype(FromUnit))> && Unit<MP_UNITS_REMOVE_CONST(decltype(ToUnit))> &&
std::assignable_from<ToRep&, FromRep> &&
template<typename T, typename Arg>
concept ValuePreservingConstruction =
std::constructible_from<T, Arg> && is_value_preserving<std::remove_cvref_t<Arg>, T>;
template<typename T, typename Arg>
concept ValuePreservingAssignment = std::assignable_from<T&, Arg> && is_value_preserving<std::remove_cvref_t<Arg>, T>;
template<auto FromUnit, auto ToUnit, typename Rep>
concept ValuePreservingScaling1Rep = SaneScaling<FromUnit, ToUnit, Rep> &&
(treat_as_floating_point<Rep> || (integral_conversion_factor(FromUnit, ToUnit)));
template<auto FromUnit, typename FromRep, auto ToUnit, typename ToRep>
concept ValuePreservingScaling2Reps =
// TODO consider providing constraints of sudo_cast to check if representation types can be scaled between each other
// CastableReps<FromRep, ToRep, FromUnit, ToUnit> &&
SaneScaling<FromUnit, ToUnit, ToRep> &&
(treat_as_floating_point<ToRep> ||
(!treat_as_floating_point<std::remove_cvref_t<FromRep>> && integral_conversion_factor(FromUnit, ToUnit) &&
!overflows_non_zero_values<ToRep>(FromUnit, ToUnit)));
(!treat_as_floating_point<FromRep> && integral_conversion_factor(FromUnit, ToUnit)));
template<typename FromRep, typename ToRep, auto QS>
concept RepresentationValuePreservingTo =
QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && RepresentationOf<std::remove_cvref_t<FromRep>, QS> &&
ValuePreservingTo<FromRep, ToRep, one, one>;
template<typename QTo, typename QFrom>
concept QuantityConstructibleFrom =
Quantity<QTo> && Quantity<QFrom> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
ValuePreservingConstruction<typename QTo::rep, typename QFrom::rep> &&
ValuePreservingScaling2Reps<QFrom::unit, typename QFrom::rep, QTo::unit, typename QTo::rep>;
template<typename FromRep, typename ToRep>
concept ScalarRepresentationValuePreservingTo =
ScalarRepresentation<std::remove_cvref_t<FromRep>> && ValuePreservingTo<FromRep, ToRep, one, one>;
template<typename T, typename Rep>
concept ScalarValuePreservingTo = (!Quantity<T>) && Scalar<T> && is_value_preserving<T, Rep>;
template<typename QFrom, typename QTo>
concept QuantityConvertibleTo =
Quantity<QFrom> && Quantity<QTo> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
(interconvertible(QFrom::unit, QTo::unit)) &&
ValuePreservingTo<typename QFrom::rep, typename QTo::rep, QFrom::unit, QTo::unit> &&
// TODO consider providing constraints of sudo_cast here rather than testing if it can be called (its return type is
// deduced thus the function is evaluated here and may emit truncating conversion or other warnings)
requires(QFrom q) { sudo_cast<QTo>(q); };
template<auto R>
concept NumberLike = Reference<MP_UNITS_REMOVE_CONST(decltype(R))> &&
(implicitly_convertible(get_quantity_spec(R), dimensionless)) && (equivalent(get_unit(R), one));
template<typename Q>
concept NumberLikeQuantity = Quantity<Q> && NumberLike<Q::reference>;
template<auto QS, typename Func, typename T, typename U>
concept InvokeResultOf = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && std::regular_invocable<Func, T, U> &&
@ -97,13 +106,8 @@ template<typename Func, typename Q1, typename Q2,
concept InvocableQuantities = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && Quantity<Q1> && Quantity<Q2> &&
InvokeResultOf<QS, Func, typename Q1::rep, typename Q2::rep>;
// TODO remove the following when clang diagnostics improve
// https://github.com/llvm/llvm-project/issues/96660
template<auto R1, auto R2>
concept HaveCommonReferenceImpl = requires { get_common_reference(R1, R2); };
template<auto R1, auto R2>
concept HaveCommonReference = HaveCommonReferenceImpl<R1, R2>;
concept HaveCommonReference = requires { get_common_reference(R1, R2); };
template<typename Func, Quantity Q1, Quantity Q2>
using common_quantity_for = quantity<get_common_reference(Q1::reference, Q2::reference),
@ -113,7 +117,7 @@ template<typename Rep, Unit U1, Unit U2>
[[nodiscard]] consteval bool overflows_non_zero_common_values(U1 u1, U2 u2)
{
constexpr Unit auto cu = get_common_unit(U1{}, U2{});
return overflows_non_zero_values<Rep>(u1, cu) || overflows_non_zero_values<Rep>(u2, cu);
return scaling_overflows_non_zero_values<Rep>(u1, cu) || scaling_overflows_non_zero_values<Rep>(u2, cu);
}
template<typename Func, typename Q1, typename Q2>
@ -125,20 +129,12 @@ concept CommonlyInvocableQuantities =
(!overflows_non_zero_common_values<std::invoke_result_t<Func, typename Q1::rep, typename Q2::rep>>(Q1::unit,
Q2::unit));
template<auto R1, auto R2, typename Rep1, typename Rep2>
concept SameValueAs = (equivalent(get_unit(R1), get_unit(R2))) && std::convertible_to<Rep1, Rep2>;
template<typename T>
using quantity_like_type = quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;
template<typename T, typename U, typename TT = std::remove_reference_t<T>>
concept Mutable = (!std::is_const_v<TT>) && std::derived_from<TT, U>;
template<auto R>
concept ConvertibleWithNumber =
Reference<MP_UNITS_REMOVE_CONST(decltype(R))> && (implicitly_convertible(get_quantity_spec(R), dimensionless)) &&
(equivalent(get_unit(R), one));
} // namespace detail
MP_UNITS_EXPORT_BEGIN
@ -168,19 +164,19 @@ public:
[[nodiscard]] static constexpr quantity zero() noexcept
requires requires { representation_values<rep>::zero(); }
{
return {representation_values<rep>::zero(), R};
return {representation_values<rep>::zero(), reference};
}
[[nodiscard]] static constexpr quantity min() noexcept
requires requires { representation_values<rep>::min(); }
{
return {representation_values<rep>::min(), R};
return {representation_values<rep>::min(), reference};
}
[[nodiscard]] static constexpr quantity max() noexcept
requires requires { representation_values<rep>::max(); }
{
return {representation_values<rep>::max(), R};
return {representation_values<rep>::max(), reference};
}
// construction, assignment, destruction
@ -190,34 +186,35 @@ public:
~quantity() = default;
template<typename FwdValue, Reference R2>
requires detail::SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
requires(equivalent(unit, get_unit(R2{}))) && detail::ValuePreservingConstruction<rep, FwdValue>
constexpr quantity(FwdValue&& val, R2) : numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(val))
{
}
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&& val, R2) : quantity(quantity<R2{}, Value>{std::forward<FwdValue>(val), R2{}})
template<typename FwdValue, Reference R2>
requires(!equivalent(unit, get_unit(R2{}))) &&
detail::QuantityConstructibleFrom<quantity, quantity<R2{}, std::remove_cvref_t<FwdValue>>>
constexpr quantity(FwdValue&& val, R2) : quantity(::mp_units::quantity{std::forward<FwdValue>(val), R2{}})
{
}
template<detail::RepresentationValuePreservingTo<Rep, quantity_spec> FwdValue>
requires detail::ConvertibleWithNumber<reference>
constexpr explicit(false) quantity(FwdValue&& val) :
template<typename FwdValue>
requires detail::NumberLike<reference> && detail::ValuePreservingConstruction<rep, FwdValue>
constexpr explicit(!std::convertible_to<FwdValue, rep>) quantity(FwdValue&& val) :
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(val))
{
}
template<detail::QuantityConvertibleTo<quantity> Q>
template<auto R2, typename Rep2>
requires detail::QuantityConstructibleFrom<quantity, quantity<R2, Rep2>>
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) :
constexpr explicit(!std::convertible_to<Rep2, rep>) quantity(const quantity<R2, Rep2>& q) :
quantity(detail::sudo_cast<quantity>(q))
{
}
template<QuantityLike Q>
requires detail::QuantityConvertibleTo<detail::quantity_like_type<Q>, quantity>
requires detail::QuantityConstructibleFrom<quantity, detail::quantity_like_type<Q>>
constexpr explicit(quantity_like_traits<Q>::explicit_import ||
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
!std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>) quantity(const Q& q) :
@ -228,52 +225,52 @@ public:
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;
template<detail::RepresentationValuePreservingTo<Rep, quantity_spec> FwdValue>
requires detail::ConvertibleWithNumber<reference>
template<typename FwdValue>
requires detail::NumberLike<reference> && detail::ValuePreservingAssignment<rep, FwdValue>
constexpr quantity& operator=(FwdValue&& val)
{
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(val);
return *this;
}
// unit conversions
template<detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, ToU{}), Rep>>
template<detail::WeakUnitOf<quantity_spec> ToU>
requires detail::ValuePreservingScaling1Rep<unit, ToU{}, rep>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in(ToU) const
{
return quantity<detail::make_reference(quantity_spec, ToU{}), Rep>{*this};
}
template<RepresentationOf<quantity_spec> ToRep>
requires detail::QuantityConvertibleTo<quantity, quantity<reference, ToRep>>
requires detail::ValuePreservingConstruction<ToRep, rep>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in() const
{
return quantity<reference, ToRep>{*this};
}
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
template<RepresentationOf<quantity_spec> ToRep, detail::WeakUnitOf<quantity_spec> ToU>
requires detail::ValuePreservingConstruction<ToRep, rep> &&
detail::ValuePreservingScaling2Reps<unit, rep, ToU{}, ToRep>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto in(ToU) const
{
return quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>{*this};
}
template<detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(const quantity q) { value_cast<ToU{}>(q); }
template<detail::WeakUnitOf<quantity_spec> ToU>
requires detail::SaneScaling<unit, ToU{}, rep>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in(ToU) const
{
return value_cast<ToU{}>(*this);
}
template<RepresentationOf<quantity_spec> ToRep>
requires requires(const quantity q) { value_cast<ToRep>(q); }
requires std::constructible_from<ToRep, rep>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in() const
{
return value_cast<ToRep>(*this);
}
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); }
template<RepresentationOf<quantity_spec> ToRep, detail::WeakUnitOf<quantity_spec> ToU>
requires std::constructible_from<ToRep, rep> && detail::SaneScaling<unit, ToU{}, rep>
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto force_in(ToU) const
{
return value_cast<ToU{}, ToRep>(*this);
@ -303,32 +300,32 @@ public:
= delete;
#endif
template<detail::UnitCompatibleWith<unit, quantity_spec> U>
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
template<detail::WeakUnitOf<quantity_spec> U>
requires detail::ValuePreservingScaling1Rep<unit, U{}, rep>
[[nodiscard]] constexpr rep numerical_value_in(U) const noexcept
{
return (*this).in(U{}).numerical_value_is_an_implementation_detail_;
return in(U{}).numerical_value_is_an_implementation_detail_;
}
template<detail::UnitCompatibleWith<unit, quantity_spec> U>
requires requires(const quantity q) { value_cast<U{}>(q); }
template<detail::WeakUnitOf<quantity_spec> U>
requires detail::SaneScaling<unit, U{}, rep>
[[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept
{
return (*this).force_in(U{}).numerical_value_is_an_implementation_detail_;
return force_in(U{}).numerical_value_is_an_implementation_detail_;
}
// conversion operators
template<typename V_, std::constructible_from<Rep> Value = std::remove_cvref_t<V_>>
requires detail::ConvertibleWithNumber<reference>
template<typename V_, std::constructible_from<rep> Value = std::remove_cvref_t<V_>>
requires detail::NumberLike<reference>
[[nodiscard]] explicit operator V_() const& noexcept
{
return numerical_value_is_an_implementation_detail_;
}
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
requires detail::QuantityConvertibleTo<quantity, detail::quantity_like_type<Q>>
requires detail::QuantityConstructibleFrom<detail::quantity_like_type<Q>, quantity>
[[nodiscard]] explicit(quantity_like_traits<Q>::explicit_export ||
!std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>) constexpr
!std::convertible_to<rep, typename quantity_like_traits<Q>::rep>) constexpr
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
operator Q_() const
noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_is_an_implementation_detail_)) &&
@ -393,9 +390,10 @@ public:
// compound assignment operators
template<detail::Mutable<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity> && requires(rep& a, const Rep2 b) {
{ a += b } -> std::same_as<rep&>;
}
requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> && requires(rep& a, const Rep2 b) {
{ a += b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{
if constexpr (equivalent(unit, get_unit(R2)))
@ -406,9 +404,10 @@ public:
}
template<detail::Mutable<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity> && requires(rep& a, const Rep2 b) {
{ a -= b } -> std::same_as<rep&>;
}
requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> && requires(rep& a, const Rep2 b) {
{ a -= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{
if constexpr (equivalent(unit, get_unit(R2)))
@ -419,10 +418,10 @@ public:
}
template<detail::Mutable<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity> && (!treat_as_floating_point<rep>) &&
requires(rep& a, const Rep2 b) {
{ a %= b } -> std::same_as<rep&>;
}
requires(!treat_as_floating_point<rep>) && (implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> && requires(rep& a, const Rep2 b) {
{ a %= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{
@ -434,8 +433,8 @@ public:
return std::forward<Q>(lhs);
}
template<detail::Mutable<quantity> Q, detail::ScalarRepresentationValuePreservingTo<Rep> Value>
requires(!Quantity<Value>) && requires(rep& a, const Value b) {
template<detail::Mutable<quantity> Q, detail::ScalarValuePreservingTo<rep> Value>
requires requires(rep& a, const Value b) {
{ a *= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& val)
@ -444,18 +443,17 @@ public:
return std::forward<Q>(lhs);
}
template<detail::Mutable<quantity> Q1, QuantityOf<dimensionless> Q2>
requires detail::ConvertibleWithNumber<Q2::reference> &&
detail::ScalarRepresentationValuePreservingTo<typename Q2::rep, Rep> && requires(rep& a, const Q2::rep b) {
{ a *= b } -> std::same_as<rep&>;
}
template<detail::Mutable<quantity> Q1, detail::NumberLikeQuantity Q2>
requires detail::ScalarValuePreservingTo<typename Q2::rep, rep> && requires(rep& a, const Q2::rep b) {
{ a *= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
{
return std::forward<Q1>(lhs) *= rhs.numerical_value_is_an_implementation_detail_;
}
template<detail::Mutable<quantity> Q, detail::ScalarRepresentationValuePreservingTo<Rep> Value>
requires(!Quantity<Value>) && requires(rep& a, const Value b) {
template<detail::Mutable<quantity> Q, detail::ScalarValuePreservingTo<rep> Value>
requires requires(rep& a, const Value b) {
{ a /= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& val)
@ -465,11 +463,10 @@ public:
return std::forward<Q>(lhs);
}
template<detail::Mutable<quantity> Q1, QuantityOf<dimensionless> Q2>
requires detail::ConvertibleWithNumber<Q2::reference> &&
detail::ScalarRepresentationValuePreservingTo<typename Q2::rep, Rep> && requires(rep& a, const Q2::rep b) {
{ a /= b } -> std::same_as<rep&>;
}
template<detail::Mutable<quantity> Q1, detail::NumberLikeQuantity Q2>
requires detail::ScalarValuePreservingTo<typename Q2::rep, rep> && requires(rep& a, const Q2::rep b) {
{ a /= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
{
return std::forward<Q1>(lhs) /= rhs.numerical_value_is_an_implementation_detail_;
@ -488,16 +485,14 @@ public:
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> &&
detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
requires detail::NumberLike<Q::reference> && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs)
{
return lhs + ::mp_units::quantity{rhs};
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> &&
detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
requires detail::NumberLike<Q::reference> && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} + rhs;
@ -515,16 +510,14 @@ public:
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> &&
detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
requires detail::NumberLike<Q::reference> && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs)
{
return lhs - ::mp_units::quantity{rhs};
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> &&
detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
requires detail::NumberLike<Q::reference> && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs)
{
return ::mp_units::quantity{lhs} - rhs;
@ -544,7 +537,7 @@ public:
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> &&
requires detail::NumberLike<Q::reference> &&
detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs)
{
@ -552,7 +545,7 @@ public:
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> &&
requires detail::NumberLike<Q::reference> &&
detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
[[nodiscard]] friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs)
{
@ -568,7 +561,7 @@ public:
template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, Rep, const Value&>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& q, const Value& val)
{
return ::mp_units::quantity{q.numerical_value_ref_in(unit) * val, R};
@ -576,7 +569,7 @@ public:
template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, Rep>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, rep>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& val, const Q& q)
{
return ::mp_units::quantity{val * q.numerical_value_ref_in(unit), R};
@ -592,7 +585,7 @@ public:
template<std::derived_from<quantity> Q, typename Value>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, Rep, const Value&>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, rep, const Value&>
[[nodiscard]] friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& q, const Value& val)
{
MP_UNITS_EXPECTS_DEBUG(val != representation_values<Value>::zero());
@ -601,7 +594,7 @@ public:
template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep>
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, const Value&, rep>
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& val, const Q& q)
{
MP_UNITS_EXPECTS_DEBUG(is_neq_zero(q));
@ -620,7 +613,7 @@ public:
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> && std::equality_comparable_with<Rep, Value>
requires detail::NumberLike<Q::reference> && std::equality_comparable_with<rep, Value>
[[nodiscard]] friend constexpr bool operator==(const Q& lhs, const Value& rhs)
{
return lhs.numerical_value_ref_in(unit) == rhs;
@ -638,7 +631,7 @@ public:
}
template<std::derived_from<quantity> Q, RepresentationOf<quantity_spec> Value>
requires detail::ConvertibleWithNumber<Q::reference> && std::three_way_comparable_with<Rep, Value>
requires detail::NumberLike<Q::reference> && std::three_way_comparable_with<rep, Value>
[[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const Value& rhs)
{
return lhs.numerical_value_ref_in(unit) <=> rhs;

View File

@ -330,43 +330,44 @@ public:
}
// unit conversions
template<detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), Rep>>
template<detail::WeakUnitOf<quantity_spec> ToU>
requires detail::ValuePreservingScaling1Rep<unit, ToU{}, rep>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).in(ToU{}), point_origin};
}
template<RepresentationOf<quantity_spec> ToRep>
requires detail::QuantityConvertibleTo<quantity_type, quantity<reference, ToRep>>
requires detail::ValuePreservingConstruction<ToRep, rep>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in() const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in<ToRep>(), point_origin};
}
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), ToRep>>
template<RepresentationOf<quantity_spec> ToRep, detail::WeakUnitOf<quantity_spec> ToU>
requires detail::ValuePreservingConstruction<ToRep, rep> &&
detail::ValuePreservingScaling2Reps<unit, rep, ToU{}, ToRep>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template in<ToRep>(ToU{}), point_origin};
}
template<detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(const quantity_type q) { value_cast<ToU{}>(q); }
template<detail::WeakUnitOf<quantity_spec> ToU>
requires detail::SaneScaling<unit, ToU{}, rep>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).force_in(ToU{}), point_origin};
}
template<RepresentationOf<quantity_spec> ToRep>
requires requires(const quantity_type q) { value_cast<ToRep>(q); }
requires std::constructible_from<ToRep, rep>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in() const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in<ToRep>(), point_origin};
}
template<RepresentationOf<quantity_spec> ToRep, detail::UnitCompatibleWith<unit, quantity_spec> ToU>
requires requires(const quantity_type q) { value_cast<ToU{}, ToRep>(q); }
template<RepresentationOf<quantity_spec> ToRep, detail::WeakUnitOf<quantity_spec> ToU>
requires std::constructible_from<ToRep, rep> && detail::SaneScaling<unit, ToU{}, rep>
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
{
return ::mp_units::quantity_point{quantity_ref_from(point_origin).template force_in<ToRep>(ToU{}), point_origin};
@ -440,8 +441,9 @@ public:
// compound assignment operators
template<detail::Mutable<quantity_point> QP, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity_type> &&
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> &&
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q)
{
qp.quantity_from_origin_is_an_implementation_detail_ += q;
@ -449,8 +451,9 @@ public:
}
template<detail::Mutable<quantity_point> QP, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity_type> &&
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
requires(implicitly_convertible(get_quantity_spec(R2), quantity_spec)) &&
detail::ValuePreservingScaling2Reps<get_unit(R2), Rep2, unit, rep> &&
requires(const quantity_type q) { quantity_from_origin_is_an_implementation_detail_ -= q; }
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity<R2, Rep2>& q)
{
qp.quantity_from_origin_is_an_implementation_detail_ -= q;
@ -458,27 +461,21 @@ public:
}
// binary operators on quantity points
template<std::derived_from<quantity_point> QP, auto R2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO._quantity_spec_>
template<std::derived_from<quantity_point> QP, ReferenceOf<PO._quantity_spec_> auto R2, typename Rep2>
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const QP& qp, const quantity<R2, Rep2>& q)
requires requires { qp.quantity_ref_from(PO) + q; }
{
return detail::make_quantity_point(qp.quantity_ref_from(PO) + q, PO);
}
template<auto R1, typename Rep1, std::derived_from<quantity_point> QP>
// TODO simplify when gcc catches up
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R1)), PO._quantity_spec_>
template<ReferenceOf<PO._quantity_spec_> auto R1, typename Rep1, std::derived_from<quantity_point> QP>
[[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity<R1, Rep1>& q, const QP& qp)
requires requires { q + qp.quantity_ref_from(PO); }
{
return qp + q;
}
template<std::derived_from<quantity_point> QP, auto R2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO._quantity_spec_>
template<std::derived_from<quantity_point> QP, ReferenceOf<PO._quantity_spec_> auto R2, typename Rep2>
[[nodiscard]] friend constexpr QuantityPoint auto operator-(const QP& qp, const quantity<R2, Rep2>& q)
requires requires { qp.quantity_ref_from(PO) - q; }
{

View File

@ -65,8 +65,7 @@ struct system_reference {
static constexpr auto quantity_spec = Q;
static constexpr auto coherent_unit = CoU;
template<Unit U>
requires(interconvertible(coherent_unit, U{}))
template<detail::UnitConvertibleTo<coherent_unit> U>
#if MP_UNITS_COMP_MSVC
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
#else

View File

@ -124,27 +124,6 @@ constexpr auto get_canonical_unit_result = get_canonical_unit_impl(U{}, U{});
// Even though it is not exported, it is visible to the other module via ADL
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return detail::get_canonical_unit_result<decltype(u)>; }
namespace detail {
// We are using a helper concept to benefit from short-circuiting
template<typename U1, typename U2>
concept PotentiallyInterConvertibleTo = Unit<U1> && Unit<U2> &&
(!AssociatedUnit<U1> || !AssociatedUnit<U2> ||
explicitly_convertible(get_quantity_spec(U1{}), get_quantity_spec(U2{})));
} // namespace detail
// interconvertible
template<Unit U1, Unit U2>
[[nodiscard]] consteval bool interconvertible(U1 u1, U2 u2)
{
if constexpr (is_same_v<U1, U2>)
return true;
else if constexpr (detail::PotentiallyInterConvertibleTo<U1, U2>)
return is_same_v<decltype(get_canonical_unit(u1).reference_unit), decltype(get_canonical_unit(u2).reference_unit)>;
else
return false;
}
template<UnitMagnitude auto M, Unit U>
requires(M != detail::unit_magnitude<>{} && M != mag<1>)
struct scaled_unit;
@ -427,8 +406,7 @@ struct prefixed_unit : decltype(M * U)::_base_type_ {
namespace detail {
template<Unit U1, Unit U2>
requires(interconvertible(U1{}, U2{}))
template<Unit U1, UnitConvertibleTo<U1{}> U2>
[[nodiscard]] consteval Unit auto get_common_scaled_unit(U1, U2)
{
constexpr auto canonical_lhs = get_canonical_unit(U1{});
@ -671,8 +649,7 @@ inline constexpr auto ppm = parts_per_million;
// Common unit
[[nodiscard]] consteval Unit auto get_common_unit(Unit auto u) { return u; }
template<Unit U1, Unit U2>
requires(interconvertible(U1{}, U2{}))
template<Unit U1, detail::UnitConvertibleTo<U1{}> U2>
[[nodiscard]] consteval Unit auto get_common_unit(U1 u1, U2 u2)
{
if constexpr (is_same_v<U1, U2>)
@ -732,8 +709,7 @@ using collapse_common_unit = type_list_unique<
} // namespace detail
template<Unit... Us, Unit NewUnit>
requires(interconvertible(common_unit<Us...>{}, NewUnit{}))
template<Unit... Us, detail::UnitConvertibleTo<common_unit<Us...>{}> NewUnit>
[[nodiscard]] consteval Unit auto get_common_unit(common_unit<Us...>, NewUnit)
{
using type = detail::collapse_common_unit<NewUnit, Us...>;
@ -743,15 +719,14 @@ template<Unit... Us, Unit NewUnit>
return detail::type_list_map<type, common_unit>{};
}
template<Unit... Us, Unit NewUnit>
requires(interconvertible(common_unit<Us...>{}, NewUnit{}))
template<Unit... Us, detail::UnitConvertibleTo<common_unit<Us...>{}> NewUnit>
[[nodiscard]] consteval Unit auto get_common_unit(NewUnit nu, common_unit<Us...> cu)
{
return get_common_unit(cu, nu);
}
template<Unit Front, Unit... Rest, Unit... Us>
requires(interconvertible(common_unit<Front, Rest...>{}, common_unit<Us...>{}))
requires(detail::UnitConvertibleTo<common_unit<Front, Rest...>, common_unit<Us...>{}>)
[[nodiscard]] consteval Unit auto get_common_unit(common_unit<Front, Rest...>, common_unit<Us...>)
{
if constexpr (sizeof...(Rest) == 1)

View File

@ -100,25 +100,27 @@ MP_UNITS_EXPORT template<typename U, auto QS>
concept UnitOf = AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
(implicitly_convertible(get_quantity_spec(U{}), QS));
MP_UNITS_EXPORT template<Unit U1, Unit U2>
[[nodiscard]] consteval bool interconvertible(U1 u1, U2 u2);
namespace detail {
template<typename U, auto QS>
concept UnitOf = UnitOf<U, QS>;
template<typename U, auto QS>
concept WeakUnitOf =
Unit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && ((!AssociatedUnit<U>) || UnitOf<U, QS>);
/**
* @brief A concept matching all units compatible with the provided unit and quantity spec
*
* Satisfied by all units that have the same canonical reference as `U2` and in case they
* have associated quantity specification it should satisfy `UnitOf<QS>`.
*/
template<typename U, auto FromU, auto QS>
concept UnitCompatibleWith =
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(FromU))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
WeakUnitOf<U, QS> && (interconvertible(FromU, U{}));
template<auto U1, auto U2>
concept UnitsOfCompatibleQuantities = explicitly_convertible(get_quantity_spec(U1), get_quantity_spec(U2));
template<auto U1, auto U2>
concept ConvertibleUnits = (get_canonical_unit(U1).reference_unit == get_canonical_unit(U2).reference_unit);
template<typename U1, auto U2>
concept UnitConvertibleTo =
Unit<U1> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> &&
((U1{} == U2) || ((!AssociatedUnit<U1> || !AssociatedUnit<MP_UNITS_REMOVE_CONST(decltype(U2))> ||
UnitsOfCompatibleQuantities<U1{}, U2>) &&
ConvertibleUnits<U1{}, U2>));
template<typename T>
concept OffsetUnit = Unit<T> && requires { T::_point_origin_; };

View File

@ -38,7 +38,7 @@ namespace mp_units {
namespace detail {
template<typename Rep, Unit UFrom, Unit UTo>
[[nodiscard]] consteval bool overflows_non_zero_values(UFrom from, UTo to)
[[nodiscard]] consteval bool scaling_overflows_non_zero_values(UFrom from, UTo to)
{
if constexpr (is_same_v<UFrom, UTo> || treat_as_floating_point<Rep>)
return false;
@ -56,6 +56,10 @@ template<typename Rep, Unit UFrom, Unit UTo>
return false;
}
template<auto FromU, auto ToU, typename Rep>
concept SaneScaling = UnitConvertibleTo<MP_UNITS_REMOVE_CONST(decltype(FromU)), ToU> &&
(!detail::scaling_overflows_non_zero_values<Rep>(FromU, ToU));
} // namespace detail
/**
@ -69,8 +73,8 @@ template<typename Rep, Unit UFrom, Unit UTo>
* @tparam ToU a unit to use for a target quantity
*/
template<auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::unit, Q::quantity_spec> &&
(!detail::overflows_non_zero_values<typename Q::rep>(Q::unit, ToU))
requires detail::WeakUnitOf<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::quantity_spec> &&
detail::SaneScaling<Q::unit, ToU, typename Q::rep>
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
{
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), typename Q::rep>>(
@ -106,18 +110,18 @@ template<typename ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
* @tparam ToRep a representation type to use for the target quantity
*/
template<Unit auto ToU, typename ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::unit, Q::quantity_spec> &&
(!detail::overflows_non_zero_values<ToRep>(Q::unit, ToU)) &&
RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep>
requires detail::WeakUnitOf<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::quantity_spec> &&
RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep> &&
detail::SaneScaling<Q::unit, ToU, ToRep>
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
{
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), ToRep>>(std::forward<FwdQ>(q));
}
template<typename ToRep, Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::unit, Q::quantity_spec> &&
(!detail::overflows_non_zero_values<ToRep>(Q::unit, ToU)) &&
RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep>
requires detail::WeakUnitOf<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::quantity_spec> &&
RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep> &&
detail::SaneScaling<Q::unit, ToU, ToRep>
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
{
return value_cast<ToU, ToRep>(std::forward<FwdQ>(q));
@ -139,9 +143,10 @@ template<typename ToRep, Unit auto ToU, typename FwdQ, Quantity Q = std::remove_
* @tparam ToQ a target quantity type to which to cast the representation
*/
template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
requires detail::UnitCompatibleWith<MP_UNITS_NONCONST_TYPE(ToQ::unit), Q::unit, Q::quantity_spec> &&
(!detail::overflows_non_zero_values<typename ToQ::rep>(Q::unit, ToQ::unit)) &&
(ToQ::quantity_spec == Q::quantity_spec) && std::constructible_from<typename ToQ::rep, typename Q::rep>
requires(ToQ::quantity_spec == Q::quantity_spec) &&
detail::WeakUnitOf<MP_UNITS_NONCONST_TYPE(ToQ::unit), Q::quantity_spec> &&
std::constructible_from<typename ToQ::rep, typename Q::rep> &&
detail::SaneScaling<Q::unit, ToQ::unit, typename ToQ::rep>
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
{
return detail::sudo_cast<ToQ>(std::forward<FwdQ>(q));
@ -158,8 +163,8 @@ template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
* @tparam ToU a unit to use for a target quantity point
*/
template<Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::unit, QP::quantity_spec> &&
(!detail::overflows_non_zero_values<typename QP::rep>(QP::unit, ToU))
requires detail::WeakUnitOf<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::quantity_spec> &&
detail::SaneScaling<QP::unit, ToU, typename QP::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
@ -196,9 +201,9 @@ template<typename ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<
* @tparam ToRep a representation type to use for the target quantity
*/
template<Unit auto ToU, typename ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::unit, QP::quantity_spec> &&
(!detail::overflows_non_zero_values<ToRep>(QP::unit, ToU)) &&
RepresentationOf<ToRep, QP::quantity_spec> && std::constructible_from<ToRep, typename QP::rep>
requires detail::WeakUnitOf<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::quantity_spec> &&
RepresentationOf<ToRep, QP::quantity_spec> && std::constructible_from<ToRep, typename QP::rep> &&
detail::SaneScaling<QP::unit, ToU, ToRep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return quantity_point{
@ -207,9 +212,9 @@ template<Unit auto ToU, typename ToRep, typename FwdQP, QuantityPoint QP = std::
}
template<typename ToRep, Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::unit, QP::quantity_spec> &&
(!detail::overflows_non_zero_values<ToRep>(QP::unit, ToU)) &&
RepresentationOf<ToRep, QP::quantity_spec> && std::constructible_from<ToRep, typename QP::rep>
requires detail::WeakUnitOf<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::quantity_spec> &&
RepresentationOf<ToRep, QP::quantity_spec> && std::constructible_from<ToRep, typename QP::rep> &&
detail::SaneScaling<QP::unit, ToU, ToRep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return value_cast<ToU, ToRep>(std::forward<FwdQP>(qp));
@ -232,9 +237,10 @@ template<typename ToRep, Unit auto ToU, typename FwdQP, QuantityPoint QP = std::
* @tparam ToQ a target quantity type to which to cast the representation of the point
*/
template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires detail::UnitCompatibleWith<MP_UNITS_NONCONST_TYPE(ToQ::unit), QP::unit, QP::quantity_spec> &&
(!detail::overflows_non_zero_values<typename ToQ::rep>(QP::unit, ToQ::unit)) &&
(ToQ::quantity_spec == QP::quantity_spec) && std::constructible_from<typename ToQ::rep, typename QP::rep>
requires(ToQ::quantity_spec == QP::quantity_spec) &&
detail::WeakUnitOf<MP_UNITS_NONCONST_TYPE(ToQ::unit), QP::quantity_spec> &&
std::constructible_from<typename ToQ::rep, typename QP::rep> &&
detail::SaneScaling<QP::unit, ToQ::unit, typename ToQ::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
@ -270,11 +276,11 @@ template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<Fw
* @tparam ToQP a target quantity point type to which to cast the representation of the point
*/
template<QuantityPoint ToQP, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
requires detail::UnitCompatibleWith<MP_UNITS_NONCONST_TYPE(ToQP::unit), QP::unit, QP::quantity_spec> &&
(!detail::overflows_non_zero_values<typename ToQP::rep>(QP::unit, 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>
requires(ToQP::quantity_spec == QP::quantity_spec) &&
detail::WeakUnitOf<MP_UNITS_NONCONST_TYPE(ToQP::unit), QP::quantity_spec> &&
(detail::same_absolute_point_origins(ToQP::point_origin, QP::point_origin)) &&
std::constructible_from<typename ToQP::rep, typename QP::rep> &&
detail::SaneScaling<QP::unit, ToQP::unit, typename ToQP::rep>
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
{
return detail::sudo_cast<ToQP>(std::forward<FwdQP>(qp));

View File

@ -406,7 +406,7 @@ template<Unit auto To, auto R, typename Rep>
*/
template<Unit auto To, auto R, typename Rep>
[[nodiscard]] constexpr Quantity auto inverse(const quantity<R, Rep>& q)
requires(!detail::overflows_non_zero_values<Rep>(one / get_unit(R), To)) && requires {
requires(!detail::scaling_overflows_non_zero_values<Rep>(one / get_unit(R), To)) && requires {
representation_values<Rep>::one();
value_cast<To>(representation_values<Rep>::one() / q);
}