refactor: numerical_value_ data member now has much less friendly name

This commit is contained in:
Mateusz Pusz
2023-10-17 14:16:22 +02:00
parent 6e7a2fd0bb
commit abafd1d38e
9 changed files with 288 additions and 260 deletions

View File

@@ -51,9 +51,9 @@ template<QuantitySpec auto ToQS, typename Q>
{ {
if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(ToQS)>> && if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(ToQS)>> &&
AssociatedUnit<std::remove_const_t<decltype(Q::unit)>>) AssociatedUnit<std::remove_const_t<decltype(Q::unit)>>)
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_); return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
else else
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_); return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
} }
} // namespace mp_units } // namespace mp_units

View File

@@ -63,7 +63,8 @@ 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 make_quantity<To::reference>(static_cast<MP_UNITS_TYPENAME To::rep>( return make_quantity<To::reference>(static_cast<MP_UNITS_TYPENAME To::rep>(
std::forward<From>(q).numerical_value_)); // this is the only (and recommended) way to do std::forward<From>(q)
.numerical_value_is_an_implementation_detail_)); // 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
@@ -78,8 +79,9 @@ template<Quantity To, typename From>
using multiplier_type = using multiplier_type =
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>; conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); }; constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
return static_cast<MP_UNITS_TYPENAME To::rep>(static_cast<c_rep_type>(std::forward<From>(q).numerical_value_) * return static_cast<MP_UNITS_TYPENAME To::rep>(
val(num) / val(den) * val(irr)) * static_cast<c_rep_type>(std::forward<From>(q).numerical_value_is_an_implementation_detail_) * val(num) /
val(den) * val(irr)) *
To::reference; To::reference;
} }
} }

View File

@@ -85,7 +85,7 @@ using common_quantity_for = quantity<common_reference(Q1::reference, Q2::referen
template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep = double> template<Reference auto R, RepresentationOf<get_quantity_spec(R).character> Rep = double>
class quantity { class quantity {
public: public:
Rep numerical_value_; // needs to be public for a structural type Rep numerical_value_is_an_implementation_detail_; // needs to be public for a structural type
// member types and values // member types and values
static constexpr Reference auto reference = R; static constexpr Reference auto reference = R;
@@ -126,7 +126,8 @@ public:
template<detail::QuantityConvertibleTo<quantity> Q> template<detail::QuantityConvertibleTo<quantity> Q>
constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) : constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q) :
numerical_value_(detail::sudo_cast<quantity>(q).numerical_value_) numerical_value_is_an_implementation_detail_(
detail::sudo_cast<quantity>(q).numerical_value_is_an_implementation_detail_)
{ {
} }
@@ -163,14 +164,14 @@ public:
requires(U{} == unit) requires(U{} == unit)
[[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept [[nodiscard]] constexpr rep& numerical_value_ref_in(U) & noexcept
{ {
return numerical_value_; return numerical_value_is_an_implementation_detail_;
} }
template<Unit U> template<Unit U>
requires(U{} == unit) requires(U{} == unit)
[[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept [[nodiscard]] constexpr const rep& numerical_value_ref_in(U) const& noexcept
{ {
return numerical_value_; return numerical_value_is_an_implementation_detail_;
} }
template<Unit U> template<Unit U>
@@ -181,39 +182,43 @@ public:
requires requires(quantity q) { q.in(U{}); } requires requires(quantity q) { q.in(U{}); }
[[nodiscard]] constexpr rep numerical_value_in(U) const noexcept [[nodiscard]] constexpr rep numerical_value_in(U) const noexcept
{ {
return (*this).in(U{}).numerical_value_; return (*this).in(U{}).numerical_value_is_an_implementation_detail_;
} }
template<UnitCompatibleWith<unit, quantity_spec> U> template<UnitCompatibleWith<unit, quantity_spec> U>
requires requires(quantity q) { q.force_in(U{}); } requires requires(quantity q) { q.force_in(U{}); }
[[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept [[nodiscard]] constexpr rep force_numerical_value_in(U) const noexcept
{ {
return (*this).force_in(U{}).numerical_value_; return (*this).force_in(U{}).numerical_value_is_an_implementation_detail_;
} }
// conversion operators // conversion operators
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>> template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
requires detail::QuantityConvertibleTo< requires detail::QuantityConvertibleTo<
quantity, quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>> quantity, quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>>
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(numerical_value_)), [[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(
numerical_value_is_an_implementation_detail_)),
convert_explicitly> || convert_explicitly> ||
!std::convertible_to<Rep, typename Q::rep>) constexpr !std::convertible_to<Rep, typename Q::rep>) constexpr
operator Q_() const& noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_)) && operator Q_() const& noexcept(
noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_is_an_implementation_detail_)) &&
std::is_nothrow_copy_constructible_v<rep>) std::is_nothrow_copy_constructible_v<rep>)
{ {
return quantity_like_traits<Q>::from_numerical_value(numerical_value_).value; return quantity_like_traits<Q>::from_numerical_value(numerical_value_is_an_implementation_detail_).value;
} }
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>> template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>>
requires detail::QuantityConvertibleTo< requires detail::QuantityConvertibleTo<
quantity, quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>> quantity, quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>>
[[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(numerical_value_)), [[nodiscard]] explicit(is_specialization_of<decltype(quantity_like_traits<Q>::from_numerical_value(
numerical_value_is_an_implementation_detail_)),
convert_explicitly> || convert_explicitly> ||
!std::convertible_to<Rep, typename Q::rep>) constexpr !std::convertible_to<Rep, typename Q::rep>) constexpr
operator Q_() && noexcept(noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_)) && operator Q_() && noexcept(
noexcept(quantity_like_traits<Q>::from_numerical_value(numerical_value_is_an_implementation_detail_)) &&
std::is_nothrow_move_constructible_v<rep>) std::is_nothrow_move_constructible_v<rep>)
{ {
return quantity_like_traits<Q>::from_numerical_value(std::move(numerical_value_)).value; return quantity_like_traits<Q>::from_numerical_value(std::move(numerical_value_is_an_implementation_detail_)).value;
} }
// member unary operators // member unary operators
@@ -224,7 +229,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return make_quantity<reference>(+numerical_value_); return make_quantity<reference>(+numerical_value_is_an_implementation_detail_);
} }
[[nodiscard]] constexpr Quantity auto operator-() const [[nodiscard]] constexpr Quantity auto operator-() const
@@ -234,7 +239,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return make_quantity<reference>(-numerical_value_); return make_quantity<reference>(-numerical_value_is_an_implementation_detail_);
} }
template<typename Q> template<typename Q>
@@ -245,7 +250,7 @@ public:
} -> std::same_as<rep&>; } -> std::same_as<rep&>;
} }
{ {
++q.numerical_value_; ++q.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(q); return std::forward<Q>(q);
} }
@@ -256,7 +261,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return make_quantity<reference>(numerical_value_++); return make_quantity<reference>(numerical_value_is_an_implementation_detail_++);
} }
template<typename Q> template<typename Q>
@@ -267,7 +272,7 @@ public:
} -> std::same_as<rep&>; } -> std::same_as<rep&>;
} }
{ {
--q.numerical_value_; --q.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(q); return std::forward<Q>(q);
} }
@@ -278,7 +283,7 @@ public:
} -> std::common_with<rep>; } -> std::common_with<rep>;
} }
{ {
return make_quantity<reference>(numerical_value_--); return make_quantity<reference>(numerical_value_is_an_implementation_detail_--);
} }
// compound assignment operators // compound assignment operators
@@ -290,7 +295,7 @@ public:
} }
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs) friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity& rhs)
{ {
lhs.numerical_value_ += rhs.numerical_value_; lhs.numerical_value_is_an_implementation_detail_ += rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs); return std::forward<Q>(lhs);
} }
@@ -302,7 +307,7 @@ public:
} }
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs) friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity& rhs)
{ {
lhs.numerical_value_ -= rhs.numerical_value_; lhs.numerical_value_is_an_implementation_detail_ -= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs); return std::forward<Q>(lhs);
} }
@@ -317,7 +322,7 @@ public:
{ {
gsl_ExpectsAudit(rhs != zero()); gsl_ExpectsAudit(rhs != zero());
lhs.numerical_value_ %= rhs.numerical_value_; lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs); return std::forward<Q>(lhs);
} }
@@ -330,7 +335,7 @@ public:
} }
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v) friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& v)
{ {
lhs.numerical_value_ *= v; lhs.numerical_value_is_an_implementation_detail_ *= v;
return std::forward<Q>(lhs); return std::forward<Q>(lhs);
} }
@@ -343,7 +348,7 @@ public:
} }
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs) friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
{ {
lhs.numerical_value_ *= rhs.numerical_value_; lhs.numerical_value_is_an_implementation_detail_ *= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs); return std::forward<Q1>(lhs);
} }
@@ -357,7 +362,7 @@ public:
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v) friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
{ {
gsl_ExpectsAudit(v != quantity_values<Value>::zero()); gsl_ExpectsAudit(v != quantity_values<Value>::zero());
lhs.numerical_value_ /= v; lhs.numerical_value_is_an_implementation_detail_ /= v;
return std::forward<Q>(lhs); return std::forward<Q>(lhs);
} }
@@ -371,7 +376,7 @@ public:
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs) friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
{ {
gsl_ExpectsAudit(rhs != rhs.zero()); gsl_ExpectsAudit(rhs != rhs.zero());
lhs.numerical_value_ /= rhs.numerical_value_; lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs); return std::forward<Q1>(lhs);
} }
@@ -385,7 +390,7 @@ private:
template<typename Value> template<typename Value>
requires std::constructible_from<rep, Value&&> requires std::constructible_from<rep, Value&&>
constexpr explicit quantity(Value&& v) : numerical_value_(std::forward<Value>(v)) constexpr explicit quantity(Value&& v) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
{ {
} }
}; };
@@ -402,7 +407,10 @@ 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)
{ {
using ret = detail::common_quantity_for<std::plus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>; using ret = detail::common_quantity_for<std::plus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value_ + ret(rhs).numerical_value_); const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return make_quantity<ret::reference>(ret_lhs.numerical_value_ref_in(ret::unit) +
ret_rhs.numerical_value_ref_in(ret::unit));
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -410,7 +418,10 @@ 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)
{ {
using ret = detail::common_quantity_for<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>; using ret = detail::common_quantity_for<std::minus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value_ - ret(rhs).numerical_value_); const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return make_quantity<ret::reference>(ret_lhs.numerical_value_ref_in(ret::unit) -
ret_rhs.numerical_value_ref_in(ret::unit));
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -420,7 +431,10 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
{ {
gsl_ExpectsAudit(rhs != rhs.zero()); gsl_ExpectsAudit(rhs != rhs.zero());
using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>; using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
return make_quantity<ret::reference>(ret(lhs).numerical_value_ % ret(rhs).numerical_value_); const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
return make_quantity<ret::reference>(ret_lhs.numerical_value_ref_in(ret::unit) %
ret_rhs.numerical_value_ref_in(ret::unit));
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -428,7 +442,8 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
Rep2> 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 make_quantity<R1 * R2>(lhs.numerical_value_ * rhs.numerical_value_); return make_quantity<R1 * R2>(lhs.numerical_value_ref_in(quantity<R1, Rep1>::unit) *
rhs.numerical_value_ref_in(quantity<R2, Rep2>::unit));
} }
template<auto R, typename Rep, typename Value> template<auto R, typename Rep, typename Value>
@@ -436,7 +451,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 Quantity auto operator*(const quantity<R, Rep>& q, const Value& v) [[nodiscard]] constexpr Quantity auto operator*(const quantity<R, Rep>& q, const Value& v)
{ {
return make_quantity<R>(q.numerical_value_ * v); return make_quantity<R>(q.numerical_value_ref_in(quantity<R, Rep>::unit) * v);
} }
template<typename Value, auto R, typename Rep> template<typename Value, auto R, typename Rep>
@@ -444,7 +459,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 Quantity auto operator*(const Value& v, const quantity<R, Rep>& q) [[nodiscard]] constexpr Quantity auto operator*(const Value& v, const quantity<R, Rep>& q)
{ {
return make_quantity<R>(v * q.numerical_value_); return make_quantity<R>(v * q.numerical_value_ref_in(quantity<R, Rep>::unit));
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -452,7 +467,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)
{ {
gsl_ExpectsAudit(rhs != rhs.zero()); gsl_ExpectsAudit(rhs != rhs.zero());
return make_quantity<R1 / R2>(lhs.numerical_value_ / rhs.numerical_value_); return make_quantity<R1 / R2>(lhs.numerical_value_ref_in(quantity<R1, Rep1>::unit) /
rhs.numerical_value_ref_in(quantity<R2, Rep2>::unit));
} }
template<auto R, typename Rep, typename Value> template<auto R, typename Rep, typename Value>
@@ -461,7 +477,7 @@ template<auto R, typename Rep, typename Value>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R, Rep>& q, const Value& v) [[nodiscard]] constexpr Quantity auto operator/(const quantity<R, Rep>& q, const Value& v)
{ {
gsl_ExpectsAudit(v != quantity_values<Value>::zero()); gsl_ExpectsAudit(v != quantity_values<Value>::zero());
return make_quantity<R>(q.numerical_value_ / v); return make_quantity<R>(q.numerical_value_ref_in(quantity<R, Rep>::unit) / v);
} }
template<typename Value, auto R, typename Rep> template<typename Value, auto R, typename Rep>
@@ -469,7 +485,7 @@ template<typename Value, auto R, typename Rep>
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep> detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, const Value&, Rep>
[[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity<R, Rep>& q) [[nodiscard]] constexpr Quantity auto operator/(const Value& v, const quantity<R, Rep>& q)
{ {
return make_quantity<::mp_units::one / R>(v / q.numerical_value_); return make_quantity<::mp_units::one / R>(v / q.numerical_value_ref_in(quantity<R, Rep>::unit));
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -478,7 +494,9 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr bool operator==(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs) [[nodiscard]] constexpr bool operator==(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{ {
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>; using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
return ct(lhs).numerical_value_ == ct(rhs).numerical_value_; const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) == ct_rhs.numerical_value_ref_in(ct::unit);
} }
template<auto R1, typename Rep1, auto R2, typename Rep2> template<auto R1, typename Rep1, auto R2, typename Rep2>
@@ -487,7 +505,9 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
[[nodiscard]] constexpr auto operator<=>(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs) [[nodiscard]] constexpr auto operator<=>(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{ {
using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>; using ct = std::common_type_t<quantity<R1, Rep1>, quantity<R2, Rep2>>;
return ct(lhs).numerical_value_ <=> ct(rhs).numerical_value_; const ct ct_lhs(lhs);
const ct ct_rhs(rhs);
return ct_lhs.numerical_value_ref_in(ct::unit) <=> ct_rhs.numerical_value_ref_in(ct::unit);
} }
// make_quantity // make_quantity

View File

@@ -119,7 +119,8 @@ struct quantity_spec_interface {
requires Quantity<std::remove_cvref_t<Q>> && requires Quantity<std::remove_cvref_t<Q>> &&
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, self)) (explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, self))
{ {
return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value_); return make_quantity<reference<self, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
} }
#else #else
template<typename Self_ = Self, UnitOf<Self_{}> U> template<typename Self_ = Self, UnitOf<Self_{}> U>
@@ -133,7 +134,8 @@ struct quantity_spec_interface {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{})) (explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{ {
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value_); return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
} }
#endif #endif
}; };
@@ -309,7 +311,8 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{})) (explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
[[nodiscard]] constexpr Quantity auto operator()(Q&& q) const [[nodiscard]] constexpr Quantity auto operator()(Q&& q) const
{ {
return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(std::forward<Q>(q).numerical_value_); return make_quantity<reference<Self{}, std::remove_cvref_t<Q>::unit>{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
} }
#endif #endif
}; };

View File

@@ -203,14 +203,16 @@ template<typename Q, Reference R>
requires Quantity<std::remove_cvref_t<Q>> requires Quantity<std::remove_cvref_t<Q>>
[[nodiscard]] constexpr Quantity auto operator*(Q&& q, R) [[nodiscard]] constexpr Quantity auto operator*(Q&& q, R)
{ {
return make_quantity<std::remove_cvref_t<Q>::reference * R{}>(std::forward<Q>(q).numerical_value_); return make_quantity<std::remove_cvref_t<Q>::reference * R{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
} }
template<typename Q, Reference R> template<typename Q, Reference R>
requires Quantity<std::remove_cvref_t<Q>> requires Quantity<std::remove_cvref_t<Q>>
[[nodiscard]] constexpr Quantity auto operator/(Q&& q, R) [[nodiscard]] constexpr Quantity auto operator/(Q&& q, R)
{ {
return make_quantity<std::remove_cvref_t<Q>::reference / R{}>(std::forward<Q>(q).numerical_value_); return make_quantity<std::remove_cvref_t<Q>::reference / R{}>(
std::forward<Q>(q).numerical_value_is_an_implementation_detail_);
} }
template<Reference R, typename Q> template<Reference R, typename Q>

View File

@@ -118,14 +118,14 @@ TEST_CASE("vector quantity", "[la]")
SECTION("integral") SECTION("integral")
{ {
SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_ == vector<int>{2, 4, 6}); } SECTION("scalar on LHS") { CHECK((2 * v).numerical_value_in(m) == vector<int>{2, 4, 6}); }
SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_ == vector<int>{2, 4, 6}); } SECTION("scalar on RHS") { CHECK((v * 2).numerical_value_in(m) == vector<int>{2, 4, 6}); }
} }
SECTION("floating-point") SECTION("floating-point")
{ {
SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_ == vector<double>{0.5, 1., 1.5}); } SECTION("scalar on LHS") { CHECK((0.5 * v).numerical_value_in(m) == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_ == vector<double>{0.5, 1., 1.5}); } SECTION("scalar on RHS") { CHECK((v * 0.5).numerical_value_in(m) == vector<double>{0.5, 1., 1.5}); }
} }
} }
@@ -133,8 +133,8 @@ TEST_CASE("vector quantity", "[la]")
{ {
const auto v = vector<int>{2, 4, 6} * isq::position_vector[m]; const auto v = vector<int>{2, 4, 6} * isq::position_vector[m];
SECTION("integral") { CHECK((v / 2).numerical_value_ == vector<int>{1, 2, 3}); } SECTION("integral") { CHECK((v / 2).numerical_value_in(m) == vector<int>{1, 2, 3}); }
SECTION("floating-point") { CHECK((v / 0.5).numerical_value_ == vector<double>{4., 8., 12.}); } SECTION("floating-point") { CHECK((v / 0.5).numerical_value_in(m) == vector<double>{4., 8., 12.}); }
} }
SECTION("add") SECTION("add")
@@ -144,12 +144,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("same unit") SECTION("same unit")
{ {
const auto u = vector<int>{3, 2, 1} * isq::position_vector[m]; const auto u = vector<int>{3, 2, 1} * isq::position_vector[m];
CHECK((v + u).numerical_value_ == vector<int>{4, 4, 4}); CHECK((v + u).numerical_value_in(m) == vector<int>{4, 4, 4});
} }
SECTION("different units") SECTION("different units")
{ {
const auto u = vector<int>{3, 2, 1} * isq::position_vector[km]; const auto u = vector<int>{3, 2, 1} * isq::position_vector[km];
CHECK((v + u).numerical_value_ == vector<int>{3001, 2002, 1003}); CHECK((v + u).numerical_value_in(m) == vector<int>{3001, 2002, 1003});
} }
} }
@@ -160,12 +160,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("same unit") SECTION("same unit")
{ {
const auto u = vector<int>{3, 2, 1} * isq::position_vector[m]; const auto u = vector<int>{3, 2, 1} * isq::position_vector[m];
CHECK((v - u).numerical_value_ == vector<int>{-2, 0, 2}); CHECK((v - u).numerical_value_in(m) == vector<int>{-2, 0, 2});
} }
SECTION("different units") SECTION("different units")
{ {
const auto u = vector<int>{3, 2, 1} * isq::position_vector[km]; const auto u = vector<int>{3, 2, 1} * isq::position_vector[km];
CHECK((v - u).numerical_value_ == vector<int>{-2999, -1998, -997}); CHECK((v - u).numerical_value_in(m) == vector<int>{-2999, -1998, -997});
} }
} }
@@ -179,18 +179,18 @@ TEST_CASE("vector quantity", "[la]")
SECTION("derived_quantity_spec") SECTION("derived_quantity_spec")
{ {
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ == vector<int>{2, 4, 6}); } SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_in(kg * m / s) == vector<int>{2, 4, 6}); }
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ == vector<int>{2, 4, 6}); } SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_in(kg * m / s) == vector<int>{2, 4, 6}); }
} }
SECTION("quantity_cast to momentum") SECTION("quantity_cast to momentum")
{ {
SECTION("scalar on LHS") SECTION("scalar on LHS")
{ {
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_ == vector<int>{2, 4, 6}); CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_in(N * s) == vector<int>{2, 4, 6});
} }
SECTION("scalar on RHS") SECTION("scalar on RHS")
{ {
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_ == vector<int>{2, 4, 6}); CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_in(N * s) == vector<int>{2, 4, 6});
} }
} }
SECTION("quantity of momentum") SECTION("quantity of momentum")
@@ -198,12 +198,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("scalar on LHS") SECTION("scalar on LHS")
{ {
const quantity<isq::momentum[N * s], vector<int>> momentum = mass * v; const quantity<isq::momentum[N * s], vector<int>> momentum = mass * v;
CHECK(momentum.numerical_value_ == vector<int>{2, 4, 6}); CHECK(momentum.numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
} }
SECTION("scalar on RHS") SECTION("scalar on RHS")
{ {
const quantity<isq::momentum[N * s], vector<int>> momentum = v * mass; const quantity<isq::momentum[N * s], vector<int>> momentum = v * mass;
CHECK(momentum.numerical_value_ == vector<int>{2, 4, 6}); CHECK(momentum.numerical_value_ref_in(N * s) == vector<int>{2, 4, 6});
} }
} }
} }
@@ -214,18 +214,18 @@ TEST_CASE("vector quantity", "[la]")
SECTION("derived_quantity_spec") SECTION("derived_quantity_spec")
{ {
SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_ == vector<double>{0.5, 1., 1.5}); } SECTION("scalar on LHS") { CHECK((mass * v).numerical_value_in(kg * m / s) == vector<double>{0.5, 1., 1.5}); }
SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_ == vector<double>{0.5, 1., 1.5}); } SECTION("scalar on RHS") { CHECK((v * mass).numerical_value_in(kg * m / s) == vector<double>{0.5, 1., 1.5}); }
} }
SECTION("quantity_cast to momentum") SECTION("quantity_cast to momentum")
{ {
SECTION("scalar on LHS") SECTION("scalar on LHS")
{ {
CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_ == vector<double>{0.5, 1., 1.5}); CHECK(quantity_cast<isq::momentum>(mass * v).numerical_value_in(N * s) == vector<double>{0.5, 1., 1.5});
} }
SECTION("scalar on RHS") SECTION("scalar on RHS")
{ {
CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_ == vector<double>{0.5, 1., 1.5}); CHECK(quantity_cast<isq::momentum>(v * mass).numerical_value_in(N * s) == vector<double>{0.5, 1., 1.5});
} }
} }
SECTION("quantity of momentum") SECTION("quantity of momentum")
@@ -233,12 +233,12 @@ TEST_CASE("vector quantity", "[la]")
SECTION("scalar on LHS") SECTION("scalar on LHS")
{ {
const quantity<isq::momentum[N * s], vector<double>> momentum = mass * v; const quantity<isq::momentum[N * s], vector<double>> momentum = mass * v;
CHECK(momentum.numerical_value_ == vector<double>{0.5, 1., 1.5}); CHECK(momentum.numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
} }
SECTION("scalar on RHS") SECTION("scalar on RHS")
{ {
const quantity<isq::momentum[N * s], vector<double>> momentum = v * mass; const quantity<isq::momentum[N * s], vector<double>> momentum = v * mass;
CHECK(momentum.numerical_value_ == vector<double>{0.5, 1., 1.5}); CHECK(momentum.numerical_value_ref_in(N * s) == vector<double>{0.5, 1., 1.5});
} }
} }
} }
@@ -252,15 +252,15 @@ TEST_CASE("vector quantity", "[la]")
{ {
const auto dur = 2 * isq::duration[h]; const auto dur = 2 * isq::duration[h];
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ == vector<int>{15, 10, 5}); } SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_in(km / h) == vector<int>{15, 10, 5}); }
SECTION("quantity_cast to velocity") SECTION("quantity_cast to velocity")
{ {
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_ == vector<int>{15, 10, 5}); CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_in(km / h) == vector<int>{15, 10, 5});
} }
SECTION("quantity of velocity") SECTION("quantity of velocity")
{ {
const quantity<isq::velocity[km / h], vector<int>> v = pos / dur; const quantity<isq::velocity[km / h], vector<int>> v = pos / dur;
CHECK(v.numerical_value_ == vector<int>{15, 10, 5}); CHECK(v.numerical_value_ref_in(km / h) == vector<int>{15, 10, 5});
} }
} }
@@ -268,15 +268,15 @@ TEST_CASE("vector quantity", "[la]")
{ {
const auto dur = 0.5 * isq::duration[h]; const auto dur = 0.5 * isq::duration[h];
SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_ == vector<double>{60, 40, 20}); } SECTION("derived_quantity_spec") { CHECK((pos / dur).numerical_value_in(km / h) == vector<double>{60, 40, 20}); }
SECTION("quantity_cast to velocity") SECTION("quantity_cast to velocity")
{ {
CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_ == vector<double>{60, 40, 20}); CHECK(quantity_cast<isq::velocity>(pos / dur).numerical_value_in(km / h) == vector<double>{60, 40, 20});
} }
SECTION("quantity of velocity") SECTION("quantity of velocity")
{ {
const quantity<isq::velocity[km / h], vector<double>> v = pos / dur; const quantity<isq::velocity[km / h], vector<double>> v = pos / dur;
CHECK(v.numerical_value_ == vector<double>{60, 40, 20}); CHECK(v.numerical_value_ref_in(km / h) == vector<double>{60, 40, 20});
} }
} }
} }

View File

@@ -90,12 +90,12 @@ TEST_CASE("numeric_limits functions", "[limits]")
{ {
SECTION("'epsilon' works as expected using default floating type") SECTION("'epsilon' works as expected using default floating type")
{ {
REQUIRE(epsilon<double>(isq::length[m]).numerical_value_ == REQUIRE(epsilon<double>(isq::length[m]).numerical_value_in(m) ==
std::numeric_limits<decltype(1. * isq::length[m])::rep>::epsilon()); std::numeric_limits<decltype(1. * isq::length[m])::rep>::epsilon());
} }
SECTION("'epsilon' works as expected using integers") SECTION("'epsilon' works as expected using integers")
{ {
REQUIRE(epsilon<int>(isq::length[m]).numerical_value_ == REQUIRE(epsilon<int>(isq::length[m]).numerical_value_in(m) ==
std::numeric_limits<decltype(1 * isq::length[m])::rep>::epsilon()); std::numeric_limits<decltype(1 * isq::length[m])::rep>::epsilon());
} }
} }

View File

@@ -240,14 +240,14 @@ static_assert(
// static member functions // static member functions
//////////////////////////// ////////////////////////////
static_assert(quantity_point<isq::height[m], mean_sea_level>::min().quantity_from_origin_.numerical_value_ == static_assert(quantity_point<isq::height[m], mean_sea_level>::min().quantity_from_origin_.numerical_value_in(m) ==
std::numeric_limits<double>::lowest()); std::numeric_limits<double>::lowest());
static_assert(quantity_point<isq::height[m], mean_sea_level>::max().quantity_from_origin_.numerical_value_ == static_assert(quantity_point<isq::height[m], mean_sea_level>::max().quantity_from_origin_.numerical_value_in(m) ==
std::numeric_limits<double>::max()); std::numeric_limits<double>::max());
static_assert(quantity_point<isq::height[m], ground_level, int>::min().quantity_from_origin_.numerical_value_ == static_assert(quantity_point<isq::height[m], ground_level, int>::min().quantity_from_origin_.numerical_value_in(m) ==
std::numeric_limits<int>::lowest()); std::numeric_limits<int>::lowest());
static_assert(quantity_point<isq::height[m], ground_level, int>::max().quantity_from_origin_.numerical_value_ == static_assert(quantity_point<isq::height[m], ground_level, int>::max().quantity_from_origin_.numerical_value_in(m) ==
std::numeric_limits<int>::max()); std::numeric_limits<int>::max());
@@ -573,15 +573,15 @@ static_assert(is_of_type<(ground_level + isq::height(short(42) * m)).point_for(m
// converting to a different unit // converting to a different unit
/////////////////////////////////// ///////////////////////////////////
static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin_.numerical_value_ == 2.); static_assert((mean_sea_level + 2. * km).in(km).quantity_from_origin_.numerical_value_in(km) == 2.);
static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin_.numerical_value_ == 2000.); static_assert((mean_sea_level + 2. * km).in(m).quantity_from_origin_.numerical_value_in(m) == 2000.);
static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin_.numerical_value_ == 2.); static_assert((mean_sea_level + 2000. * m).in(km).quantity_from_origin_.numerical_value_in(km) == 2.);
static_assert((ground_level + 2. * km).in(km).quantity_from_origin_.numerical_value_ == 2.); static_assert((ground_level + 2. * km).in(km).quantity_from_origin_.numerical_value_in(km) == 2.);
static_assert((ground_level + 2. * km).in(m).quantity_from_origin_.numerical_value_ == 2000.); static_assert((ground_level + 2. * km).in(m).quantity_from_origin_.numerical_value_in(m) == 2000.);
static_assert((ground_level + 2000. * m).in(km).quantity_from_origin_.numerical_value_ == 2.); static_assert((ground_level + 2000. * m).in(km).quantity_from_origin_.numerical_value_in(km) == 2.);
static_assert((tower_peak + 2. * km).in(km).quantity_from_origin_.numerical_value_ == 2.); static_assert((tower_peak + 2. * km).in(km).quantity_from_origin_.numerical_value_in(km) == 2.);
static_assert((tower_peak + 2. * km).in(m).quantity_from_origin_.numerical_value_ == 2000.); static_assert((tower_peak + 2. * km).in(m).quantity_from_origin_.numerical_value_in(m) == 2000.);
static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin_.numerical_value_ == 2.); static_assert((tower_peak + 2000. * m).in(km).quantity_from_origin_.numerical_value_in(km) == 2.);
template<template<auto, auto, typename> typename QP> template<template<auto, auto, typename> typename QP>
concept invalid_unit_conversion = requires { concept invalid_unit_conversion = requires {
@@ -652,14 +652,14 @@ static_assert([](auto v) {
//////////////////////// ////////////////////////
// same type // same type
static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin_.numerical_value_ == 2); static_assert((mean_sea_level + 1 * m += 1 * m).quantity_from_origin_.numerical_value_in(m) == 2);
static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin_.numerical_value_ == 1); static_assert((mean_sea_level + 2 * m -= 1 * m).quantity_from_origin_.numerical_value_in(m) == 1);
// different types // different types
static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin_.numerical_value_ == 5.5); static_assert((mean_sea_level + 2.5 * m += 3 * m).quantity_from_origin_.numerical_value_in(m) == 5.5);
static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin_.numerical_value_ == 1123); static_assert((mean_sea_level + 123 * m += 1 * km).quantity_from_origin_.numerical_value_in(m) == 1123);
static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin_.numerical_value_ == 2.5); static_assert((mean_sea_level + 5.5 * m -= 3 * m).quantity_from_origin_.numerical_value_in(m) == 2.5);
static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin_.numerical_value_ == 123); static_assert((mean_sea_level + 1123 * m -= 1 * km).quantity_from_origin_.numerical_value_in(m) == 123);
template<template<auto, auto, typename> typename QP> template<template<auto, auto, typename> typename QP>
@@ -931,24 +931,24 @@ static_assert(is_of_type<(1 * m + tower_peak) - (1 * m + other_ground_level), qu
// check for integral types promotion // check for integral types promotion
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) + std::uint8_t(0) * m) static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) + std::uint8_t(0) * m)
.quantity_from_origin_.numerical_value_), .quantity_from_origin_.numerical_value_in(m)),
int>); int>);
static_assert(is_same_v<decltype((std::uint8_t(0) * m + (mean_sea_level + std::uint8_t(0) * m)) static_assert(is_same_v<decltype((std::uint8_t(0) * m + (mean_sea_level + std::uint8_t(0) * m))
.quantity_from_origin_.numerical_value_), .quantity_from_origin_.numerical_value_in(m)),
int>); int>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(0) * m) static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(0) * m)
.quantity_from_origin_.numerical_value_), .quantity_from_origin_.numerical_value_in(m)),
int>);
static_assert(is_same_v<decltype(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(0) * m))
.numerical_value_in(m)),
int>); int>);
static_assert(
is_same_v<
decltype(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(0) * m)).numerical_value_), int>);
static_assert(((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m) static_assert(((mean_sea_level + std::uint8_t(128) * m) + std::uint8_t(128) * m)
.quantity_from_origin_.numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); .quantity_from_origin_.numerical_value_in(m) == std::uint8_t(128) + std::uint8_t(128));
static_assert((std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m)) static_assert((std::uint8_t(128) * m + (mean_sea_level + std::uint8_t(128) * m))
.quantity_from_origin_.numerical_value_ == std::uint8_t(128) + std::uint8_t(128)); .quantity_from_origin_.numerical_value_in(m) == std::uint8_t(128) + std::uint8_t(128));
static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m).quantity_from_origin_.numerical_value_ == static_assert(((mean_sea_level + std::uint8_t(0) * m) - std::uint8_t(1) * m)
std::uint8_t(0) - std::uint8_t(1)); .quantity_from_origin_.numerical_value_in(m) == std::uint8_t(0) - std::uint8_t(1));
static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value_ == static_assert(((mean_sea_level + std::uint8_t(0) * m) - (mean_sea_level + std::uint8_t(1) * m)).numerical_value_in(m) ==
std::uint8_t(0) - std::uint8_t(1)); std::uint8_t(0) - std::uint8_t(1));
// different representation types // different representation types
@@ -1003,39 +1003,39 @@ static_assert(is_of_type<(mean_sea_level + 1 * km) - (mean_sea_level + 1. * m),
static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity<si::metre, double>>); static_assert(is_of_type<(mean_sea_level + 1. * km) - (mean_sea_level + 1. * m), quantity<si::metre, double>>);
static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin_.numerical_value_ == 2); static_assert(((mean_sea_level + 1 * m) + 1 * m).quantity_from_origin_.numerical_value_in(m) == 2);
static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 2); static_assert((1 * m + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_in(m) == 2);
static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin_.numerical_value_ == 1001); static_assert(((mean_sea_level + 1 * m) + 1 * km).quantity_from_origin_.numerical_value_in(m) == 1001);
static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin_.numerical_value_ == 1001); static_assert((1 * m + (mean_sea_level + 1 * km)).quantity_from_origin_.numerical_value_in(m) == 1001);
static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin_.numerical_value_ == 1001); static_assert(((mean_sea_level + 1 * km) + 1 * m).quantity_from_origin_.numerical_value_in(m) == 1001);
static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 1001); static_assert((1 * km + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_in(m) == 1001);
static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin_.numerical_value_ == 1); static_assert(((mean_sea_level + 2 * m) - 1 * m).quantity_from_origin_.numerical_value_in(m) == 1);
static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin_.numerical_value_ == 999); static_assert(((mean_sea_level + 1 * km) - 1 * m).quantity_from_origin_.numerical_value_in(m) == 999);
static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin_.numerical_value_ == 2.5); static_assert(((mean_sea_level + 1.5 * m) + 1 * m).quantity_from_origin_.numerical_value_in(m) == 2.5);
static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 2.5); static_assert((1.5 * m + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_in(m) == 2.5);
static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin_.numerical_value_ == 1001.5); static_assert(((mean_sea_level + 1.5 * m) + 1 * km).quantity_from_origin_.numerical_value_in(m) == 1001.5);
static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin_.numerical_value_ == 1001.5); static_assert((1.5 * m + (mean_sea_level + 1 * km)).quantity_from_origin_.numerical_value_in(m) == 1001.5);
static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin_.numerical_value_ == 1501); static_assert(((mean_sea_level + 1.5 * km) + 1 * m).quantity_from_origin_.numerical_value_in(m) == 1501);
static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_ == 1501); static_assert((1.5 * km + (mean_sea_level + 1 * m)).quantity_from_origin_.numerical_value_in(m) == 1501);
static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin_.numerical_value_ == 1.5); static_assert(((mean_sea_level + 2.5 * m) - 1 * m).quantity_from_origin_.numerical_value_in(m) == 1.5);
static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin_.numerical_value_ == 1499); static_assert(((mean_sea_level + 1.5 * km) - 1 * m).quantity_from_origin_.numerical_value_in(m) == 1499);
static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin_.numerical_value_ == 2.5); static_assert(((mean_sea_level + 1 * m) + 1.5 * m).quantity_from_origin_.numerical_value_in(m) == 2.5);
static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin_.numerical_value_ == 2.5); static_assert((1 * m + (mean_sea_level + 1.5 * m)).quantity_from_origin_.numerical_value_in(m) == 2.5);
static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin_.numerical_value_ == 1501); static_assert(((mean_sea_level + 1 * m) + 1.5 * km).quantity_from_origin_.numerical_value_in(m) == 1501);
static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin_.numerical_value_ == 1501); static_assert((1 * m + (mean_sea_level + 1.5 * km)).quantity_from_origin_.numerical_value_in(m) == 1501);
static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin_.numerical_value_ == 1001.5); static_assert(((mean_sea_level + 1 * km) + 1.5 * m).quantity_from_origin_.numerical_value_in(m) == 1001.5);
static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin_.numerical_value_ == 1001.5); static_assert((1 * km + (mean_sea_level + 1.5 * m)).quantity_from_origin_.numerical_value_in(m) == 1001.5);
static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin_.numerical_value_ == 0.5); static_assert(((mean_sea_level + 2 * m) - 1.5 * m).quantity_from_origin_.numerical_value_in(m) == 0.5);
static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin_.numerical_value_ == 998.5); static_assert(((mean_sea_level + 1 * km) - 1.5 * m).quantity_from_origin_.numerical_value_in(m) == 998.5);
static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_ == 1); static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 1);
static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_ == 999); static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 999);
static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_ == 1.5); static_assert(((mean_sea_level + 2.5 * m) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 1.5);
static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_ == 1499); static_assert(((mean_sea_level + 1.5 * km) - (mean_sea_level + 1 * m)).numerical_value_in(m) == 1499);
static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_ == 0.5); static_assert(((mean_sea_level + 2 * m) - (mean_sea_level + 1.5 * m)).numerical_value_in(m) == 0.5);
static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_ == 998.5); static_assert(((mean_sea_level + 1 * km) - (mean_sea_level + 1.5 * m)).numerical_value_in(m) == 998.5);
static_assert((mean_sea_level + 42 * m) - (ground_level + 42 * m) == -42 * m); static_assert((mean_sea_level + 42 * m) - (ground_level + 42 * m) == -42 * m);
static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m); static_assert((ground_level + 42 * m) - (mean_sea_level + 42 * m) == 42 * m);

View File

@@ -108,14 +108,14 @@ static_assert(is_same_v<quantity<isq::length[m], int>::rep, int>);
// static member functions // static member functions
//////////////////////////// ////////////////////////////
static_assert(quantity<isq::length[m], int>::zero().numerical_value_ == 0); static_assert(quantity<isq::length[m], int>::zero().numerical_value_in(m) == 0);
static_assert(quantity<isq::length[m], int>::one().numerical_value_ == 1); static_assert(quantity<isq::length[m], int>::one().numerical_value_in(m) == 1);
static_assert(quantity<isq::length[m], int>::min().numerical_value_ == std::numeric_limits<int>::lowest()); static_assert(quantity<isq::length[m], int>::min().numerical_value_in(m) == std::numeric_limits<int>::lowest());
static_assert(quantity<isq::length[m], int>::max().numerical_value_ == std::numeric_limits<int>::max()); static_assert(quantity<isq::length[m], int>::max().numerical_value_in(m) == std::numeric_limits<int>::max());
static_assert(quantity<isq::length[m], double>::zero().numerical_value_ == 0.0); static_assert(quantity<isq::length[m], double>::zero().numerical_value_in(m) == 0.0);
static_assert(quantity<isq::length[m], double>::one().numerical_value_ == 1.0); static_assert(quantity<isq::length[m], double>::one().numerical_value_in(m) == 1.0);
static_assert(quantity<isq::length[m], double>::min().numerical_value_ == std::numeric_limits<double>::lowest()); static_assert(quantity<isq::length[m], double>::min().numerical_value_in(m) == std::numeric_limits<double>::lowest());
static_assert(quantity<isq::length[m], double>::max().numerical_value_ == std::numeric_limits<double>::max()); static_assert(quantity<isq::length[m], double>::max().numerical_value_in(m) == std::numeric_limits<double>::max());
////////////////////////////// //////////////////////////////
@@ -186,10 +186,10 @@ static_assert(std::convertible_to<quantity<isq::length[m], int>, quantity<isq::l
// obtaining a number // obtaining a number
/////////////////////// ///////////////////////
static_assert(quantity<isq::length[m], int>(123 * m).numerical_value_ == 123); static_assert(quantity<isq::length[m], int>(123 * m).numerical_value_in(m) == 123);
static_assert(quantity<isq::length[m], int>(2 * km).numerical_value_ == 2000); static_assert(quantity<isq::length[m], int>(2 * km).numerical_value_in(m) == 2000);
static_assert(quantity<isq::length[km], int>(2 * km).numerical_value_ == 2); static_assert(quantity<isq::length[km], int>(2 * km).numerical_value_in(km) == 2);
static_assert(quantity<isq::length[km]>(1500 * m).numerical_value_ == 1.5); static_assert(quantity<isq::length[km]>(1500 * m).numerical_value_in(km) == 1.5);
/////////////////////////////////// ///////////////////////////////////
@@ -200,22 +200,22 @@ static_assert(is_of_type<(2. * km).in(m), quantity<si::metre>>);
static_assert(is_of_type<isq::length(2. * km).in(m), quantity<isq::length[m]>>); static_assert(is_of_type<isq::length(2. * km).in(m), quantity<isq::length[m]>>);
static_assert(is_of_type<isq::height(2. * km).in(m), quantity<isq::height[m]>>); static_assert(is_of_type<isq::height(2. * km).in(m), quantity<isq::height[m]>>);
static_assert(quantity<isq::length[km]>(2. * km).in(km).numerical_value_ == 2.); static_assert(quantity<isq::length[km]>(2. * km).in(km).numerical_value_in(km) == 2.);
static_assert(quantity<isq::length[km]>(2. * km).in(m).numerical_value_ == 2000.); static_assert(quantity<isq::length[km]>(2. * km).in(m).numerical_value_in(m) == 2000.);
static_assert(quantity<isq::length[m]>(2000. * m).in(km).numerical_value_ == 2.); static_assert(quantity<isq::length[m]>(2000. * m).in(km).numerical_value_in(km) == 2.);
static_assert(quantity<isq::length[km], int>(2 * km).in(km).numerical_value_ == 2); static_assert(quantity<isq::length[km], int>(2 * km).in(km).numerical_value_in(km) == 2);
static_assert(quantity<isq::length[km], int>(2 * km).in(m).numerical_value_ == 2000); static_assert(quantity<isq::length[km], int>(2 * km).in(m).numerical_value_in(m) == 2000);
static_assert(is_of_type<(2. * km).force_in(m), quantity<si::metre>>); static_assert(is_of_type<(2. * km).force_in(m), quantity<si::metre>>);
static_assert(is_of_type<isq::length(2. * km).force_in(m), quantity<isq::length[m]>>); static_assert(is_of_type<isq::length(2. * km).force_in(m), quantity<isq::length[m]>>);
static_assert(is_of_type<isq::height(2. * km).force_in(m), quantity<isq::height[m]>>); static_assert(is_of_type<isq::height(2. * km).force_in(m), quantity<isq::height[m]>>);
static_assert(quantity<isq::length[km]>(2. * km).force_in(km).numerical_value_ == 2.); static_assert(quantity<isq::length[km]>(2. * km).force_in(km).numerical_value_in(km) == 2.);
static_assert(quantity<isq::length[km]>(2. * km).force_in(m).numerical_value_ == 2000.); static_assert(quantity<isq::length[km]>(2. * km).force_in(m).numerical_value_in(m) == 2000.);
static_assert(quantity<isq::length[m]>(2000. * m).force_in(km).numerical_value_ == 2.); static_assert(quantity<isq::length[m]>(2000. * m).force_in(km).numerical_value_in(km) == 2.);
static_assert(quantity<isq::length[km], int>(2 * km).force_in(km).numerical_value_ == 2); static_assert(quantity<isq::length[km], int>(2 * km).force_in(km).numerical_value_in(km) == 2);
static_assert(quantity<isq::length[km], int>(2 * km).force_in(m).numerical_value_ == 2000); static_assert(quantity<isq::length[km], int>(2 * km).force_in(m).numerical_value_in(m) == 2000);
static_assert(quantity<isq::length[m], int>(2000 * m).force_in(km).numerical_value_ == 2); static_assert(quantity<isq::length[m], int>(2000 * m).force_in(km).numerical_value_in(km) == 2);
template<template<auto, typename> typename Q> template<template<auto, typename> typename Q>
concept invalid_unit_conversion = requires { concept invalid_unit_conversion = requires {
@@ -317,28 +317,28 @@ static_assert([] {
auto l1(1 * m), l2(2 * m); auto l1(1 * m), l2(2 * m);
return l2 = l1; return l2 = l1;
}() }()
.numerical_value_ == 1); .numerical_value_in(m) == 1);
static_assert([] { static_assert([] {
const auto l1(1 * m); const auto l1(1 * m);
auto l2(2 * m); auto l2(2 * m);
return l2 = l1; return l2 = l1;
}() }()
.numerical_value_ == 1); .numerical_value_in(m) == 1);
static_assert([]() { static_assert([]() {
auto l1(1 * m), l2(2 * m); auto l1(1 * m), l2(2 * m);
return l2 = std::move(l1); return l2 = std::move(l1);
}() }()
.numerical_value_ == 1); .numerical_value_in(m) == 1);
//////////////////// ////////////////////
// unary operators // unary operators
//////////////////// ////////////////////
static_assert((+123 * m).numerical_value_ == 123); static_assert((+123 * m).numerical_value_in(m) == 123);
static_assert((-123 * m).numerical_value_ == -123); static_assert((-123 * m).numerical_value_in(m) == -123);
static_assert((+(-123 * m)).numerical_value_ == -123); static_assert((+(-123 * m)).numerical_value_in(m) == -123);
static_assert((-(-123 * m)).numerical_value_ == 123); static_assert((-(-123 * m)).numerical_value_in(m) == 123);
static_assert([](auto v) { static_assert([](auto v) {
auto vv = v++; auto vv = v++;
@@ -357,7 +357,7 @@ static_assert([](auto v) {
return std::pair(v, vv); return std::pair(v, vv);
}(123 * m) == std::pair(122 * m, 122 * m)); }(123 * m) == std::pair(122 * m, 122 * m));
static_assert(is_same_v<decltype((+(short{0} * m)).numerical_value_), int>); static_assert(is_same_v<decltype((+(short{0} * m)).numerical_value_in(m)), int>);
//////////////////////// ////////////////////////
@@ -365,31 +365,31 @@ static_assert(is_same_v<decltype((+(short{0} * m)).numerical_value_), int>);
//////////////////////// ////////////////////////
// same type // same type
static_assert((1 * m += 1 * m).numerical_value_ == 2); static_assert((1 * m += 1 * m).numerical_value_in(m) == 2);
static_assert((2 * m -= 1 * m).numerical_value_ == 1); static_assert((2 * m -= 1 * m).numerical_value_in(m) == 1);
static_assert((1 * m *= 2).numerical_value_ == 2); static_assert((1 * m *= 2).numerical_value_in(m) == 2);
static_assert((2 * m /= 2).numerical_value_ == 1); static_assert((2 * m /= 2).numerical_value_in(m) == 1);
static_assert((1 * m *= 2 * one).numerical_value_ == 2); static_assert((1 * m *= 2 * one).numerical_value_in(m) == 2);
static_assert((2 * m /= 2 * one).numerical_value_ == 1); static_assert((2 * m /= 2 * one).numerical_value_in(m) == 1);
static_assert((7 * m %= 2 * m).numerical_value_ == 1); static_assert((7 * m %= 2 * m).numerical_value_in(m) == 1);
// different types // different types
static_assert((2.5 * m += 3 * m).numerical_value_ == 5.5); static_assert((2.5 * m += 3 * m).numerical_value_in(m) == 5.5);
static_assert((123 * m += 1 * km).numerical_value_ == 1123); static_assert((123 * m += 1 * km).numerical_value_in(m) == 1123);
static_assert((5.5 * m -= 3 * m).numerical_value_ == 2.5); static_assert((5.5 * m -= 3 * m).numerical_value_in(m) == 2.5);
static_assert((1123 * m -= 1 * km).numerical_value_ == 123); static_assert((1123 * m -= 1 * km).numerical_value_in(m) == 123);
static_assert((2.5 * m *= 3).numerical_value_ == 7.5); static_assert((2.5 * m *= 3).numerical_value_in(m) == 7.5);
static_assert((7.5 * m /= 3).numerical_value_ == 2.5); static_assert((7.5 * m /= 3).numerical_value_in(m) == 2.5);
static_assert((2.5 * m *= 3 * one).numerical_value_ == 7.5); static_assert((2.5 * m *= 3 * one).numerical_value_in(m) == 7.5);
static_assert((7.5 * m /= 3 * one).numerical_value_ == 2.5); static_assert((7.5 * m /= 3 * one).numerical_value_in(m) == 2.5);
static_assert((3500 * m %= 1 * km).numerical_value_ == 500); static_assert((3500 * m %= 1 * km).numerical_value_in(m) == 500);
// static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value_ == [] { // static_assert((std::uint8_t(255) * m %= 256 * m).numerical_value_in(m) == [] {
// std::uint8_t ui(255); // std::uint8_t ui(255);
// return ui %= 256; // return ui %= 256;
// }()); // UB // }()); // UB
// TODO: Fix // TODO: Fix
static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value_ != [] { static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value_in(m) != [] {
std::uint8_t ui(255); std::uint8_t ui(255);
return ui %= 257; return ui %= 257;
}()); }());
@@ -399,10 +399,10 @@ static_assert((std::uint8_t(255) * m %= 257 * m).numerical_value_ != [] {
#ifndef MP_UNITS_COMP_MSVC #ifndef MP_UNITS_COMP_MSVC
// next two lines trigger conversions warnings // next two lines trigger conversions warnings
// (warning disabled in CMake for this file) // (warning disabled in CMake for this file)
static_assert((22 * m *= 33.33).numerical_value_ == 733); static_assert((22 * m *= 33.33).numerical_value_in(m) == 733);
static_assert((22 * m /= 3.33).numerical_value_ == 6); static_assert((22 * m /= 3.33).numerical_value_in(m) == 6);
static_assert((22 * m *= 33.33 * one).numerical_value_ == 733); static_assert((22 * m *= 33.33 * one).numerical_value_in(m) == 733);
static_assert((22 * m /= 3.33 * one).numerical_value_ == 6); static_assert((22 * m /= 3.33 * one).numerical_value_in(m) == 6);
#endif #endif
template<template<auto, typename> typename Q> template<template<auto, typename> typename Q>
@@ -530,9 +530,9 @@ static_assert(is_of_type<4 * one % (2 * one), quantity<one, int>>);
// check for integral types promotion // check for integral types promotion
static_assert(is_same_v<decltype(std::uint8_t(0) * m + std::uint8_t(0) * m)::rep, int>); static_assert(is_same_v<decltype(std::uint8_t(0) * m + std::uint8_t(0) * m)::rep, int>);
static_assert(is_same_v<decltype(std::uint8_t(0) * m - std::uint8_t(0) * m)::rep, int>); static_assert(is_same_v<decltype(std::uint8_t(0) * m - std::uint8_t(0) * m)::rep, int>);
static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_ == static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).numerical_value_in(m) ==
std::uint8_t(128) + std::uint8_t(128)); std::uint8_t(128) + std::uint8_t(128));
static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_ == std::uint8_t(0) - std::uint8_t(1)); static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).numerical_value_in(m) == std::uint8_t(0) - std::uint8_t(1));
static_assert( static_assert(
is_same_v<decltype((std::uint8_t(0) * m) % (std::uint8_t(0) * m))::rep, decltype(std::uint8_t(0) % std::uint8_t(0))>); is_same_v<decltype((std::uint8_t(0) * m) % (std::uint8_t(0) * m))::rep, decltype(std::uint8_t(0) % std::uint8_t(0))>);
@@ -612,67 +612,67 @@ static_assert(is_of_type<1 * m / (1 * s), quantity<derived_unit<struct si::metre
static_assert(is_of_type<1 * m / (1 * min), quantity<derived_unit<struct si::metre, per<struct si::minute>>{}, int>>); static_assert(is_of_type<1 * m / (1 * min), quantity<derived_unit<struct si::metre, per<struct si::minute>>{}, int>>);
static_assert(is_of_type<1 * min / (1 * m), quantity<derived_unit<struct si::minute, per<struct si::metre>>{}, int>>); static_assert(is_of_type<1 * min / (1 * m), quantity<derived_unit<struct si::minute, per<struct si::metre>>{}, int>>);
static_assert((1 * m + 1 * m).numerical_value_ == 2); static_assert((1 * m + 1 * m).numerical_value_in(m) == 2);
static_assert((1 * m + 1 * km).numerical_value_ == 1001); static_assert((1 * m + 1 * km).numerical_value_in(m) == 1001);
static_assert((1 * km + 1 * m).numerical_value_ == 1001); static_assert((1 * km + 1 * m).numerical_value_in(m) == 1001);
static_assert((2 * m - 1 * m).numerical_value_ == 1); static_assert((2 * m - 1 * m).numerical_value_in(m) == 1);
static_assert((1 * km - 1 * m).numerical_value_ == 999); static_assert((1 * km - 1 * m).numerical_value_in(m) == 999);
static_assert((2 * m * 2).numerical_value_ == 4); static_assert((2 * m * 2).numerical_value_in(m) == 4);
static_assert((2 * m * (2 * one)).numerical_value_ == 4); static_assert((2 * m * (2 * one)).numerical_value_in(m) == 4);
static_assert((2 * m * (2 * percent)).numerical_value_ == 4); static_assert((2 * m * (2 * percent)).numerical_value_in(percent * m) == 4);
static_assert((3 * 3 * m).numerical_value_ == 9); static_assert((3 * 3 * m).numerical_value_in(m) == 9);
static_assert(((3 * one) * (3 * m)).numerical_value_ == 9); static_assert(((3 * one) * (3 * m)).numerical_value_in(m) == 9);
static_assert(((3 * percent) * (3 * m)).numerical_value_ == 9); static_assert(((3 * percent) * (3 * m)).numerical_value_in(percent * m) == 9);
static_assert((4 * m / 2).numerical_value_ == 2); static_assert((4 * m / 2).numerical_value_in(m) == 2);
static_assert((4 * m / (2 * one)).numerical_value_ == 2); static_assert((4 * m / (2 * one)).numerical_value_in(m) == 2);
static_assert((4 * m / (2 * percent)).numerical_value_ == 2); static_assert((4 * m / (2 * percent)).numerical_value_in(m / percent) == 2);
static_assert((4 * km / (2 * m)).numerical_value_ == 2); static_assert((4 * km / (2 * m)).numerical_value_in(km / m) == 2);
static_assert((4000 * m / (2 * m)).numerical_value_ == 2000); static_assert((4000 * m / (2 * m)).numerical_value_in(one) == 2000);
static_assert((1.5 * m + 1 * m).numerical_value_ == 2.5); static_assert((1.5 * m + 1 * m).numerical_value_in(m) == 2.5);
static_assert((1.5 * m + 1 * km).numerical_value_ == 1001.5); static_assert((1.5 * m + 1 * km).numerical_value_in(m) == 1001.5);
static_assert((1.5 * km + 1 * m).numerical_value_ == 1501); static_assert((1.5 * km + 1 * m).numerical_value_in(m) == 1501);
static_assert((2.5 * m - 1 * m).numerical_value_ == 1.5); static_assert((2.5 * m - 1 * m).numerical_value_in(m) == 1.5);
static_assert((1.5 * km - 1 * m).numerical_value_ == 1499); static_assert((1.5 * km - 1 * m).numerical_value_in(m) == 1499);
static_assert((2.5 * m * 2).numerical_value_ == 5); static_assert((2.5 * m * 2).numerical_value_in(m) == 5);
static_assert((2.5 * m * (2 * one)).numerical_value_ == 5); static_assert((2.5 * m * (2 * one)).numerical_value_in(m) == 5);
static_assert((2.5 * m * (2 * percent)).numerical_value_ == 5); static_assert((2.5 * m * (2 * percent)).numerical_value_in(m * percent) == 5);
static_assert((2.5L * (2 * m)).numerical_value_ == 5); static_assert((2.5L * (2 * m)).numerical_value_in(m) == 5);
static_assert((2.5L * one * (2 * m)).numerical_value_ == 5); static_assert((2.5L * one * (2 * m)).numerical_value_in(m) == 5);
static_assert((2.5L * percent * (2 * m)).numerical_value_ == 5); static_assert((2.5L * percent * (2 * m)).numerical_value_in(m * percent) == 5);
static_assert((5. * m / 2).numerical_value_ == 2.5); static_assert((5. * m / 2).numerical_value_in(m) == 2.5);
static_assert((5. * m / (2 * one)).numerical_value_ == 2.5); static_assert((5. * m / (2 * one)).numerical_value_in(m) == 2.5);
static_assert((5. * m / (2 * percent)).numerical_value_ == 2.5); static_assert((5. * m / (2 * percent)).numerical_value_in(m / percent) == 2.5);
static_assert((5. * km / (2 * m)).numerical_value_ == 2.5); static_assert((5. * km / (2 * m)).numerical_value_in(km / m) == 2.5);
static_assert((5000. * m / (2 * m)).numerical_value_ == 2500); static_assert((5000. * m / (2 * m)).numerical_value_in(one) == 2500);
static_assert((1 * m + 1.5 * m).numerical_value_ == 2.5); static_assert((1 * m + 1.5 * m).numerical_value_in(m) == 2.5);
static_assert((1 * m + 1.5 * km).numerical_value_ == 1501); static_assert((1 * m + 1.5 * km).numerical_value_in(m) == 1501);
static_assert((1 * km + 1.5 * m).numerical_value_ == 1001.5); static_assert((1 * km + 1.5 * m).numerical_value_in(m) == 1001.5);
static_assert((2 * m - 1.5 * m).numerical_value_ == 0.5); static_assert((2 * m - 1.5 * m).numerical_value_in(m) == 0.5);
static_assert((1 * km - 1.5 * m).numerical_value_ == 998.5); static_assert((1 * km - 1.5 * m).numerical_value_in(m) == 998.5);
static_assert((2 * m * 2.5L).numerical_value_ == 5); static_assert((2 * m * 2.5L).numerical_value_in(m) == 5);
static_assert((2 * m * (2.5L * one)).numerical_value_ == 5); static_assert((2 * m * (2.5L * one)).numerical_value_in(m) == 5);
static_assert((2 * m * (2.5L * percent)).numerical_value_ == 5); static_assert((2 * m * (2.5L * percent)).numerical_value_in(m * percent) == 5);
static_assert((2 * 2.5 * m).numerical_value_ == 5); static_assert((2 * 2.5 * m).numerical_value_in(m) == 5);
static_assert((2 * one * (2.5 * m)).numerical_value_ == 5); static_assert((2 * one * (2.5 * m)).numerical_value_in(m) == 5);
static_assert((2 * percent * (2.5 * m)).numerical_value_ == 5); static_assert((2 * percent * (2.5 * m)).numerical_value_in(m * percent) == 5);
static_assert((5 * m / 2.5L).numerical_value_ == 2); static_assert((5 * m / 2.5L).numerical_value_in(m) == 2);
static_assert((5 * m / (2.5L * one)).numerical_value_ == 2); static_assert((5 * m / (2.5L * one)).numerical_value_in(m) == 2);
static_assert((5 * m / (2.5L * percent)).numerical_value_ == 2); static_assert((5 * m / (2.5L * percent)).numerical_value_in(m / percent) == 2);
static_assert((5 * km / (2.5 * m)).numerical_value_ == 2); static_assert((5 * km / (2.5 * m)).numerical_value_in(km / m) == 2);
static_assert((5000 * m / (2.5 * m)).numerical_value_ == 2000); static_assert((5000 * m / (2.5 * m)).numerical_value_in(one) == 2000);
static_assert((7 * m % (2 * m)).numerical_value_ == 1); static_assert((7 * m % (2 * m)).numerical_value_in(m) == 1);
static_assert((7 * km % (2000 * m)).numerical_value_ == 1000); static_assert((7 * km % (2000 * m)).numerical_value_in(m) == 1000);
static_assert((1300 * m % (1 * km)).numerical_value_ == 300); static_assert((1300 * m % (1 * km)).numerical_value_in(m) == 300);
static_assert((7 * one % (2 * one)).numerical_value_ == 1); static_assert((7 * one % (2 * one)).numerical_value_in(one) == 1);
static_assert((10 * m2 * (10 * m2)) / (50 * m2) == 2 * m2); static_assert((10 * m2 * (10 * m2)) / (50 * m2) == 2 * m2);
static_assert((10 * km / (5 * m)).numerical_value_ == 2); static_assert((10 * km / (5 * m)).numerical_value_in(km / m) == 2);
static_assert((10 * km / (5 * m)).numerical_value_in(one) == 2000); static_assert((10 * km / (5 * m)).numerical_value_in(one) == 2000);
static_assert((10 * s * (2 * kHz)).numerical_value_ == 20); static_assert((10 * s * (2 * kHz)).numerical_value_in(s * kHz) == 20);
// commutativity and associativity // commutativity and associativity
static_assert(10 * isq::length[si::metre] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]); static_assert(10 * isq::length[si::metre] / (2 * isq::time[s]) + 5 * isq::speed[m / s] == 10 * isq::speed[m / s]);
@@ -758,9 +758,10 @@ static_assert(1 * one + 30 * percent == (100 + 30) * percent);
static_assert(is_same_v<decltype(std::uint8_t(0) * one + std::uint8_t(0) * one)::rep, int>); static_assert(is_same_v<decltype(std::uint8_t(0) * one + std::uint8_t(0) * one)::rep, int>);
static_assert(is_same_v<decltype(std::uint8_t(0) * one - std::uint8_t(0) * one)::rep, int>); static_assert(is_same_v<decltype(std::uint8_t(0) * one - std::uint8_t(0) * one)::rep, int>);
static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_ == static_assert((std::uint8_t(128) * one + std::uint8_t(128) * one).numerical_value_in(one) ==
std::uint8_t(128) + std::uint8_t(128)); std::uint8_t(128) + std::uint8_t(128));
static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_ == std::uint8_t(0) - std::uint8_t(1)); static_assert((std::uint8_t(0) * one - std::uint8_t(1) * one).numerical_value_in(one) ==
std::uint8_t(0) - std::uint8_t(1));
static_assert(is_same_v<decltype(std::uint8_t(0) * one % (std::uint8_t(0) * one))::rep, static_assert(is_same_v<decltype(std::uint8_t(0) * one % (std::uint8_t(0) * one))::rep,
decltype(std::uint8_t(0) % std::uint8_t(0))>); decltype(std::uint8_t(0) % std::uint8_t(0))>);
@@ -905,14 +906,14 @@ static_assert((50. * percent).numerical_value_in(one) == 0.5);
// value_cast // value_cast
////////////////// //////////////////
static_assert(value_cast<m>(2 * km).numerical_value_ == 2000); static_assert(value_cast<m>(2 * km).numerical_value_in(m) == 2000);
static_assert(value_cast<km>(2000 * m).numerical_value_ == 2); static_assert(value_cast<km>(2000 * m).numerical_value_in(km) == 2);
static_assert(value_cast<int>(1.23 * m).numerical_value_ == 1); static_assert(value_cast<int>(1.23 * m).numerical_value_in(m) == 1);
static_assert(value_cast<km / h>(2000.0 * m / (3600.0 * s)).numerical_value_ == 2); static_assert(value_cast<km / h>(2000.0 * m / (3600.0 * s)).numerical_value_in(km / h) == 2);
static_assert((2 * km).force_in(m).numerical_value_ == 2000); static_assert((2 * km).force_in(m).numerical_value_in(m) == 2000);
static_assert((2000 * m).force_in(km).numerical_value_ == 2); static_assert((2000 * m).force_in(km).numerical_value_in(km) == 2);
static_assert((2000.0 * m / (3600.0 * s)).force_in(km / h).numerical_value_ == 2); static_assert((2000.0 * m / (3600.0 * s)).force_in(km / h).numerical_value_in(km / h) == 2);
////////////////// //////////////////
// quantity_cast // quantity_cast