refactor: delta handling improved to produce terser types

This commit is contained in:
Mateusz Pusz
2024-06-25 11:43:23 -05:00
parent 786c1bf7da
commit 57a8b7ecd4
7 changed files with 94 additions and 66 deletions

View File

@@ -97,10 +97,10 @@ template<Quantity To, typename From>
if constexpr (q_unit == To::unit) { if constexpr (q_unit == To::unit) {
// no scaling of the number needed // no scaling of the number needed
return {static_cast<MP_UNITS_TYPENAME To::rep>(std::forward<From>(q).numerical_value_is_an_implementation_detail_), return {static_cast<MP_UNITS_TYPENAME To::rep>(std::forward<From>(q).numerical_value_is_an_implementation_detail_),
delta<To::reference>}; // this is the only (and recommended) way to do make_delta(To::reference)}; // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are // a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler // using static_cast to suppress all the compiler
// warnings on conversions // warnings on conversions
} else { } else {
// scale the number // scale the number
using traits = magnitude_conversion_traits<To, std::remove_reference_t<From>>; using traits = magnitude_conversion_traits<To, std::remove_reference_t<From>>;
@@ -108,13 +108,13 @@ template<Quantity To, typename From>
// this results in great assembly // this results in great assembly
auto res = static_cast<MP_UNITS_TYPENAME To::rep>( auto res = static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<traits::c_type>(q.numerical_value_is_an_implementation_detail_) * traits::ratio); static_cast<traits::c_type>(q.numerical_value_is_an_implementation_detail_) * traits::ratio);
return {res, delta<To::reference>}; return {res, make_delta(To::reference)};
} else { } else {
// this is slower but allows conversions like 2000 m -> 2 km without loosing data // this is slower but allows conversions like 2000 m -> 2 km without loosing data
auto res = static_cast<MP_UNITS_TYPENAME To::rep>( auto res = static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<traits::c_type>(q.numerical_value_is_an_implementation_detail_) * traits::num_mult / static_cast<traits::c_type>(q.numerical_value_is_an_implementation_detail_) * traits::num_mult /
traits::den_mult * traits::irr_mult); traits::den_mult * traits::irr_mult);
return {res, delta<To::reference>}; return {res, make_delta(To::reference)};
} }
} }
} }

View File

@@ -133,25 +133,25 @@ public:
[[nodiscard]] static constexpr quantity zero() noexcept [[nodiscard]] static constexpr quantity zero() noexcept
requires requires { quantity_values<rep>::zero(); } requires requires { quantity_values<rep>::zero(); }
{ {
return {quantity_values<rep>::zero(), delta<R>}; return {quantity_values<rep>::zero(), detail::make_delta(R)};
} }
[[nodiscard]] static constexpr quantity one() noexcept [[nodiscard]] static constexpr quantity one() noexcept
requires requires { quantity_values<rep>::one(); } requires requires { quantity_values<rep>::one(); }
{ {
return {quantity_values<rep>::one(), delta<R>}; return {quantity_values<rep>::one(), detail::make_delta(R)};
} }
[[nodiscard]] static constexpr quantity min() noexcept [[nodiscard]] static constexpr quantity min() noexcept
requires requires { quantity_values<rep>::min(); } requires requires { quantity_values<rep>::min(); }
{ {
return {quantity_values<rep>::min(), delta<R>}; return {quantity_values<rep>::min(), detail::make_delta(R)};
} }
[[nodiscard]] static constexpr quantity max() noexcept [[nodiscard]] static constexpr quantity max() noexcept
requires requires { quantity_values<rep>::max(); } requires requires { quantity_values<rep>::max(); }
{ {
return {quantity_values<rep>::max(), delta<R>}; return {quantity_values<rep>::max(), detail::make_delta(R)};
} }
// construction, assignment, destruction // construction, assignment, destruction
@@ -166,12 +166,20 @@ public:
{ {
} }
template<typename Value, DeltaReference R2> template<typename Value, Reference R2>
requires(!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) && requires(!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) &&
detail::QuantityConvertibleTo<quantity<detail::get_original_reference(R2{}), std::remove_cvref_t<Value>>, detail::QuantityConvertibleTo<quantity<R2{}, std::remove_cvref_t<Value>>, quantity>
quantity> constexpr quantity(Value&& v, R2) : quantity(quantity<R2{}, std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}})
{
}
template<typename Value, DeltaReference R2>
requires(!Reference<R2>) && (!detail::SameValueAs<R2{}, R, std::remove_cvref_t<Value>, Rep>) &&
detail::QuantityConvertibleTo<
quantity<detail::remove_reference_specifier(R2{}), std::remove_cvref_t<Value>>, quantity>
constexpr quantity(Value&& v, R2) : constexpr quantity(Value&& v, R2) :
quantity(quantity<detail::get_original_reference(R2{}), std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}}) quantity(
quantity<detail::remove_reference_specifier(R2{}), std::remove_cvref_t<Value>>{std::forward<Value>(v), R2{}})
{ {
} }
@@ -199,7 +207,7 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
!std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>) quantity(const Q& q) : !std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>) quantity(const Q& q) :
quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q).value, quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q).value,
delta<quantity_like_traits<Q>::reference>}) detail::make_delta(quantity_like_traits<Q>::reference)})
{ {
} }
@@ -298,7 +306,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, delta<reference>}; return ::mp_units::quantity{+numerical_value_is_an_implementation_detail_, detail::make_delta(reference)};
} }
[[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator-() const [[nodiscard]] constexpr QuantityOf<quantity_spec> auto operator-() const
@@ -308,7 +316,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, delta<reference>}; return ::mp_units::quantity{-numerical_value_is_an_implementation_detail_, detail::make_delta(reference)};
} }
template<typename Q> template<typename Q>
@@ -330,7 +338,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, delta<reference>}; return ::mp_units::quantity{numerical_value_is_an_implementation_detail_++, detail::make_delta(reference)};
} }
template<typename Q> template<typename Q>
@@ -352,7 +360,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, delta<reference>}; return ::mp_units::quantity{numerical_value_is_an_implementation_detail_--, detail::make_delta(reference)};
} }
// compound assignment operators // compound assignment operators
@@ -451,9 +459,14 @@ public:
}; };
// CTAD // CTAD
template<typename Value, Reference R>
requires RepresentationOf<Value, get_quantity_spec(R{}).character>
quantity(Value v, R) -> quantity<R{}, Value>;
template<typename Value, DeltaReference R> template<typename Value, DeltaReference R>
requires RepresentationOf<Value, get_quantity_spec(detail::get_original_reference(R{})).character> requires(!Reference<R>) &&
quantity(Value v, R) -> quantity<detail::get_original_reference(R{}), Value>; RepresentationOf<Value, get_quantity_spec(detail::remove_reference_specifier(R{})).character>
quantity(Value v, R) -> quantity<detail::remove_reference_specifier(R{}), Value>;
// the below is needed only to fire static_asserts in the constructor // the below is needed only to fire static_asserts in the constructor
template<typename Value, Reference R> template<typename Value, Reference R>
@@ -474,7 +487,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
const ret ret_lhs(lhs); const ret ret_lhs(lhs);
const ret ret_rhs(rhs); const ret ret_rhs(rhs);
return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit), return quantity{ret_lhs.numerical_value_ref_in(ret::unit) + ret_rhs.numerical_value_ref_in(ret::unit),
delta<ret::reference>}; detail::make_delta(ret::reference)};
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -485,7 +498,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
const ret ret_lhs(lhs); const ret ret_lhs(lhs);
const ret ret_rhs(rhs); const ret ret_rhs(rhs);
return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit), return quantity{ret_lhs.numerical_value_ref_in(ret::unit) - ret_rhs.numerical_value_ref_in(ret::unit),
delta<ret::reference>}; detail::make_delta(ret::reference)};
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -498,14 +511,15 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
const ret ret_lhs(lhs); const ret ret_lhs(lhs);
const ret ret_rhs(rhs); const ret ret_rhs(rhs);
return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit), return quantity{ret_lhs.numerical_value_ref_in(ret::unit) % ret_rhs.numerical_value_ref_in(ret::unit),
delta<ret::reference>}; detail::make_delta(ret::reference)};
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvocableQuantities<std::multiplies<>, quantity<R1, Rep1>, quantity<R2, Rep2>> requires detail::InvocableQuantities<std::multiplies<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator*(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs) [[nodiscard]] constexpr Quantity auto operator*(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{ {
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)), delta<R1 * R2>}; return quantity{lhs.numerical_value_ref_in(get_unit(R1)) * rhs.numerical_value_ref_in(get_unit(R2)),
detail::make_delta(R1 * R2)};
} }
template<auto R, typename Rep, typename Value> template<auto R, typename Rep, typename Value>
@@ -513,7 +527,7 @@ template<auto R, typename Rep, typename Value>
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&> detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, Rep, const Value&>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const quantity<R, Rep>& q, const Value& v) [[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const quantity<R, Rep>& q, const Value& v)
{ {
return quantity{q.numerical_value_ref_in(get_unit(R)) * v, delta<R>}; return quantity{q.numerical_value_ref_in(get_unit(R)) * v, detail::make_delta(R)};
} }
template<typename Value, auto R, typename Rep> template<typename Value, auto R, typename Rep>
@@ -521,7 +535,7 @@ template<typename Value, auto R, typename Rep>
detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep> detail::InvokeResultOf<get_quantity_spec(R).character, std::multiplies<>, const Value&, Rep>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const Value& v, const quantity<R, Rep>& q) [[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator*(const Value& v, const quantity<R, Rep>& q)
{ {
return quantity{v * q.numerical_value_ref_in(get_unit(R)), delta<R>}; return quantity{v * q.numerical_value_ref_in(get_unit(R)), detail::make_delta(R)};
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -529,7 +543,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs) [[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{ {
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero()); MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), delta<R1 / R2>}; return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)),
detail::make_delta(R1 / R2)};
} }
template<auto R, typename Rep, typename Value> template<auto R, typename Rep, typename Value>
@@ -538,7 +553,7 @@ template<auto R, typename Rep, typename Value>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator/(const quantity<R, Rep>& q, const Value& v) [[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator/(const quantity<R, Rep>& q, const Value& v)
{ {
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero()); MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
return quantity{q.numerical_value_ref_in(get_unit(R)) / v, delta<R>}; return quantity{q.numerical_value_ref_in(get_unit(R)) / v, detail::make_delta(R)};
} }
template<typename Value, auto R, typename Rep> template<typename Value, auto R, typename Rep>
@@ -547,7 +562,7 @@ template<typename Value, auto R, typename Rep>
[[nodiscard]] constexpr QuantityOf<inverse(get_quantity_spec(R))> auto operator/(const Value& v, [[nodiscard]] constexpr QuantityOf<inverse(get_quantity_spec(R))> auto operator/(const Value& v,
const quantity<R, Rep>& q) const quantity<R, Rep>& q)
{ {
return quantity{v / q.numerical_value_ref_in(get_unit(R)), delta<::mp_units::one / R>}; return quantity{v / q.numerical_value_ref_in(get_unit(R)), detail::make_delta(::mp_units::one / R)};
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>

View File

@@ -58,7 +58,7 @@ template<QuantitySpec auto ToQS, typename Q>
[[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q) [[nodiscard]] constexpr Quantity auto quantity_cast(Q&& q)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
delta<make_reference(ToQS, std::remove_reference_t<Q>::unit)>}; detail::make_delta(make_reference(ToQS, std::remove_reference_t<Q>::unit))};
} }
/** /**

View File

@@ -129,7 +129,7 @@ struct quantity_spec_interface {
detail::QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, self> detail::QuantitySpecExplicitlyConvertibleTo<std::remove_reference_t<Q>::quantity_spec, self>
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
delta<detail::make_reference(self, std::remove_cvref_t<Q>::unit)>}; detail::make_delta(detail::make_reference(self, std::remove_cvref_t<Q>::unit))};
} }
#else #else
template<typename Self_ = Self, UnitOf<Self_{}> U> template<typename Self_ = Self, UnitOf<Self_{}> U>
@@ -144,7 +144,7 @@ struct quantity_spec_interface {
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
delta<detail::make_reference(Self{}, std::remove_cvref_t<Q>::unit)>}; detail::make_delta(detail::make_reference(Self{}, std::remove_cvref_t<Q>::unit))};
} }
#endif #endif
}; };
@@ -341,7 +341,7 @@ struct quantity_spec<Self, QS, Args...> : detail::propagate_equation<QS>, detail
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
delta<detail::make_reference(Self{}, std::remove_cvref_t<Q>::unit)>}; detail::make_delta(detail::make_reference(Self{}, std::remove_cvref_t<Q>::unit))};
} }
#endif #endif
}; };

View File

@@ -43,7 +43,7 @@ using reference_t = reference<MP_UNITS_REMOVE_CONST(decltype(Q)), MP_UNITS_REMOV
template<typename R> template<typename R>
requires DeltaReference<R> || AbsoluteReference<R> requires DeltaReference<R> || AbsoluteReference<R>
[[nodiscard]] consteval Reference auto get_original_reference(R r) [[nodiscard]] consteval Reference auto remove_reference_specifier(R r)
{ {
if constexpr (requires { R::_original_reference_; }) if constexpr (requires { R::_original_reference_; })
return R::_original_reference_; return R::_original_reference_;
@@ -185,38 +185,43 @@ struct reference {
template<typename Rep, DeltaReference R> template<typename Rep, DeltaReference R>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(detail::get_original_reference(R{})).character> requires RepresentationOf<std::remove_cvref_t<Rep>,
[[nodiscard]] constexpr quantity<detail::get_original_reference(R{}), std::remove_cvref_t<Rep>> operator*(Rep&& lhs, R) get_quantity_spec(detail::remove_reference_specifier(R{})).character>
[[nodiscard]] constexpr quantity<detail::remove_reference_specifier(R{}), std::remove_cvref_t<Rep>> operator*(Rep&& lhs,
R)
{ {
return quantity{std::forward<Rep>(lhs), R{}}; return quantity{std::forward<Rep>(lhs), R{}};
} }
template<typename Rep, DeltaReference R> template<typename Rep, DeltaReference R>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(detail::get_original_reference(R{})).character> requires RepresentationOf<std::remove_cvref_t<Rep>,
[[nodiscard]] constexpr quantity<inverse(detail::get_original_reference(R{})), std::remove_cvref_t<Rep>> operator/( get_quantity_spec(detail::remove_reference_specifier(R{})).character>
[[nodiscard]] constexpr quantity<inverse(detail::remove_reference_specifier(R{})), std::remove_cvref_t<Rep>> operator/(
Rep&& lhs, R) Rep&& lhs, R)
{ {
return quantity{std::forward<Rep>(lhs), delta<inverse(detail::get_original_reference(R{}))>}; return quantity{std::forward<Rep>(lhs), detail::make_delta(inverse(detail::remove_reference_specifier(R{})))};
} }
template<typename Rep, AbsoluteReference R> template<typename Rep, AbsoluteReference R>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(detail::get_original_reference(R{})).character> requires RepresentationOf<std::remove_cvref_t<Rep>,
[[nodiscard]] constexpr quantity_point<detail::get_original_reference(R{}), get_quantity_spec(detail::remove_reference_specifier(R{})).character>
default_point_origin(detail::get_original_reference(R{})), [[nodiscard]] constexpr quantity_point<detail::remove_reference_specifier(R{}),
default_point_origin(detail::remove_reference_specifier(R{})),
std::remove_cvref_t<Rep>> std::remove_cvref_t<Rep>>
operator*(Rep&& lhs, R) operator*(Rep&& lhs, R)
{ {
return quantity_point{std::forward<Rep>(lhs) * delta<detail::get_original_reference(R{})>}; return quantity_point{std::forward<Rep>(lhs) * detail::make_delta(detail::remove_reference_specifier(R{}))};
} }
template<typename Rep, AbsoluteReference R> template<typename Rep, AbsoluteReference R>
requires RepresentationOf<std::remove_cvref_t<Rep>, get_quantity_spec(detail::get_original_reference(R{})).character> requires RepresentationOf<std::remove_cvref_t<Rep>,
[[nodiscard]] constexpr quantity_point<inverse(detail::get_original_reference(R{})), get_quantity_spec(detail::remove_reference_specifier(R{})).character>
default_point_origin(detail::get_original_reference(R{})), [[nodiscard]] constexpr quantity_point<inverse(detail::remove_reference_specifier(R{})),
default_point_origin(detail::remove_reference_specifier(R{})),
std::remove_cvref_t<Rep>> std::remove_cvref_t<Rep>>
operator/(Rep&& lhs, R) operator/(Rep&& lhs, R)
{ {
return quantity_point{std::forward<Rep>(lhs) * delta<inverse(detail::get_original_reference(R{}))>}; return quantity_point{std::forward<Rep>(lhs) * detail::make_delta(inverse(detail::remove_reference_specifier(R{})))};
} }
template<typename Rep, Reference R> template<typename Rep, Reference R>
@@ -262,7 +267,7 @@ template<typename Q, Reference R>
[[nodiscard]] constexpr Quantity auto operator*(Q&& q, R) [[nodiscard]] constexpr Quantity auto operator*(Q&& q, R)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
delta<std::remove_cvref_t<Q>::reference * R{}>}; detail::make_delta(std::remove_cvref_t<Q>::reference * R{})};
} }
template<typename Q, Reference R> template<typename Q, Reference R>
@@ -270,7 +275,7 @@ template<typename Q, Reference R>
[[nodiscard]] constexpr Quantity auto operator/(Q&& q, R) [[nodiscard]] constexpr Quantity auto operator/(Q&& q, R)
{ {
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_, return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
delta<std::remove_cvref_t<Q>::reference / R{}>}; detail::make_delta(std::remove_cvref_t<Q>::reference / R{})};
} }
template<Reference R, typename Q> template<Reference R, typename Q>

View File

@@ -82,7 +82,7 @@ MP_UNITS_EXPORT_END
// reference specifiers // reference specifiers
template<Reference R> template<Reference R>
struct relative_ final { struct delta_ final {
static constexpr Reference auto _original_reference_ = R{}; static constexpr Reference auto _original_reference_ = R{};
}; };
@@ -94,14 +94,13 @@ struct absolute_ final {
MP_UNITS_EXPORT_BEGIN MP_UNITS_EXPORT_BEGIN
template<Reference auto R> template<Reference auto R>
inline constexpr relative_<MP_UNITS_REMOVE_CONST(decltype(R))> delta{}; inline constexpr delta_<MP_UNITS_REMOVE_CONST(decltype(R))> delta{};
template<Reference auto R> template<Reference auto R>
inline constexpr absolute_<MP_UNITS_REMOVE_CONST(decltype(R))> absolute{}; inline constexpr absolute_<MP_UNITS_REMOVE_CONST(decltype(R))> absolute{};
template<typename T> template<typename T>
concept DeltaReference = concept DeltaReference = (Reference<T> && !requires { get_unit(T{}).point_origin; }) || is_specialization_of<T, delta_>;
(Reference<T> && !requires { get_unit(T{}).point_origin; }) || is_specialization_of<T, relative_>;
template<typename T> template<typename T>
concept AbsoluteReference = is_specialization_of<T, absolute_>; concept AbsoluteReference = is_specialization_of<T, absolute_>;
@@ -110,6 +109,15 @@ MP_UNITS_EXPORT_END
namespace detail { namespace detail {
template<Reference R>
[[nodiscard]] consteval DeltaReference auto make_delta(R r)
{
if constexpr (requires { get_unit(R{}).point_origin; })
return delta<R{}>;
else
return r;
}
template<auto R1, auto R2> template<auto R1, auto R2>
concept SameReference = concept SameReference =
Reference<MP_UNITS_REMOVE_CONST(decltype(R1))> && Reference<MP_UNITS_REMOVE_CONST(decltype(R2))> && (R1 == R2); Reference<MP_UNITS_REMOVE_CONST(decltype(R1))> && Reference<MP_UNITS_REMOVE_CONST(decltype(R2))> && (R1 == R2);

View File

@@ -114,8 +114,8 @@ template<ReferenceOf<dimensionless> auto R, typename Rep>
[[nodiscard]] constexpr quantity<R, Rep> exp(const quantity<R, Rep>& q) [[nodiscard]] constexpr quantity<R, Rep> exp(const quantity<R, Rep>& q)
{ {
using std::exp; using std::exp;
return value_cast<get_unit(R)>( return value_cast<get_unit(R)>(quantity{static_cast<Rep>(exp(q.force_numerical_value_in(q.unit))),
quantity{static_cast<Rep>(exp(q.force_numerical_value_in(q.unit))), delta<detail::clone_reference_with<one>(R)>}); detail::make_delta(detail::clone_reference_with<one>(R))});
} }
/** /**
@@ -236,7 +236,7 @@ template<auto R, auto S, auto T, typename Rep1, typename Rep2, typename Rep3>
using std::fma; using std::fma;
return quantity{ return quantity{
fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)), fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), b.numerical_value_ref_in(b.unit)),
delta<common_reference(R * S, T)>}; detail::make_delta(common_reference(R * S, T))};
} }
/** /**
@@ -260,7 +260,7 @@ template<auto R, auto S, auto T, auto Origin, typename Rep1, typename Rep2, type
using std::fma; using std::fma;
return Origin + quantity{fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), return Origin + quantity{fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit),
b.quantity_ref_from(b.point_origin).numerical_value_ref_in(b.unit)), b.quantity_ref_from(b.point_origin).numerical_value_ref_in(b.unit)),
delta<common_reference(R * S, T)>}; detail::make_delta(common_reference(R * S, T))};
} }
/** /**
@@ -277,7 +277,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
constexpr auto ref = common_reference(R1, R2); constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref); constexpr auto unit = get_unit(ref);
using std::fmod; using std::fmod;
return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta<ref>}; return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), detail::make_delta(ref)};
} }
/** /**
@@ -294,7 +294,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
constexpr auto ref = common_reference(R1, R2); constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref); constexpr auto unit = get_unit(ref);
using std::remainder; using std::remainder;
return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta<ref>}; return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), detail::make_delta(ref)};
} }
@@ -338,8 +338,8 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (To == get_unit(R)) { if constexpr (To == get_unit(R)) {
return {static_cast<Rep>(floor(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)}; return {static_cast<Rep>(floor(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)};
} else { } else {
return handle_signed_results( return handle_signed_results(quantity{static_cast<Rep>(floor(q.force_numerical_value_in(To))),
quantity{static_cast<Rep>(floor(q.force_numerical_value_in(To))), delta<detail::clone_reference_with<To>(R)>}); detail::make_delta(detail::clone_reference_with<To>(R))});
} }
} else { } else {
if constexpr (To == get_unit(R)) { if constexpr (To == get_unit(R)) {
@@ -375,8 +375,8 @@ template<Unit auto To, auto R, typename Rep>
if constexpr (To == get_unit(R)) { if constexpr (To == get_unit(R)) {
return {static_cast<Rep>(ceil(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)}; return {static_cast<Rep>(ceil(q.numerical_value_ref_in(q.unit))), detail::clone_reference_with<To>(R)};
} else { } else {
return handle_signed_results( return handle_signed_results(quantity{static_cast<Rep>(ceil(q.force_numerical_value_in(To))),
quantity{static_cast<Rep>(ceil(q.force_numerical_value_in(To))), delta<detail::clone_reference_with<To>(R)>}); detail::make_delta(detail::clone_reference_with<To>(R))});
} }
} else { } else {
if constexpr (To == get_unit(R)) { if constexpr (To == get_unit(R)) {
@@ -456,7 +456,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
constexpr auto ref = common_reference(R1, R2); constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref); constexpr auto unit = get_unit(ref);
using std::hypot; using std::hypot;
return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), delta<ref>}; return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), detail::make_delta(ref)};
} }
/** /**
@@ -475,7 +475,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2, auto R3, typename Rep3>
constexpr auto unit = get_unit(ref); constexpr auto unit = get_unit(ref);
using std::hypot; using std::hypot;
return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)),
delta<ref>}; detail::make_delta(ref)};
} }
} // namespace mp_units } // namespace mp_units