mirror of
https://github.com/mpusz/mp-units.git
synced 2025-06-25 01:01:33 +02:00
refactor: constraints refactoring
This commit is contained in:
@ -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;
|
||||
|
@ -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; }
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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_; };
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user