mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +02:00
feat: ConvertibleWithNumber
introduced to improve convertibility of unit one
with raw numbers
Resolves #675
This commit is contained in:
@ -166,7 +166,8 @@ inline constexpr auto ppm = parts_per_million;
|
|||||||
|
|
||||||
### Superpowers of the unit `one`
|
### Superpowers of the unit `one`
|
||||||
|
|
||||||
Quantities of the unit `one` are the only ones that are:
|
Quantities implicitly convertible to `dimensionless` with the unit equivalent to `one` are the only
|
||||||
|
ones that are:
|
||||||
|
|
||||||
- implicitly constructible from the raw value,
|
- implicitly constructible from the raw value,
|
||||||
- explicitly convertible to a raw value,
|
- explicitly convertible to a raw value,
|
||||||
@ -185,8 +186,8 @@ This property also expands to usual arithmetic operators.
|
|||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
Those rules do not apply to all the dimensionless quantities. It would be unsafe and misleading
|
Those rules do not apply to all the dimensionless quantities. It would be unsafe and misleading
|
||||||
to allow such operations on units with a magnitude different than `1` (e.g., `percent` or
|
to allow such operations on units with a magnitude different than `1` (e.g., `percent`) or
|
||||||
`radian`).
|
for quantities that are not implicitly convertible to `dimensionless` (e.g., `angular_measure`).
|
||||||
|
|
||||||
|
|
||||||
## Angular quantities
|
## Angular quantities
|
||||||
|
@ -128,6 +128,11 @@ using quantity_like_type = quantity<quantity_like_traits<T>::reference, typename
|
|||||||
template<typename T, typename U, typename TT = std::remove_reference_t<T>>
|
template<typename T, typename U, typename TT = std::remove_reference_t<T>>
|
||||||
concept Mutable = (!std::is_const_v<TT>) && std::derived_from<TT, U>;
|
concept Mutable = (!std::is_const_v<TT>) && std::derived_from<TT, U>;
|
||||||
|
|
||||||
|
template<auto R>
|
||||||
|
concept ConvertibleWithNumber =
|
||||||
|
Reference<MP_UNITS_REMOVE_CONST(decltype(R))> && (implicitly_convertible(get_quantity_spec(R), dimensionless)) &&
|
||||||
|
(equivalent(get_unit(R), one));
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
MP_UNITS_EXPORT_BEGIN
|
MP_UNITS_EXPORT_BEGIN
|
||||||
@ -192,7 +197,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<detail::ValuePreservingTo<Rep> FwdValue>
|
template<detail::ValuePreservingTo<Rep> FwdValue>
|
||||||
requires(unit == ::mp_units::one)
|
requires detail::ConvertibleWithNumber<reference>
|
||||||
constexpr explicit(false) quantity(FwdValue&& val) :
|
constexpr explicit(false) quantity(FwdValue&& val) :
|
||||||
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(val))
|
numerical_value_is_an_implementation_detail_(std::forward<FwdValue>(val))
|
||||||
{
|
{
|
||||||
@ -218,7 +223,7 @@ public:
|
|||||||
quantity& operator=(quantity&&) = default;
|
quantity& operator=(quantity&&) = default;
|
||||||
|
|
||||||
template<detail::ValuePreservingTo<Rep> FwdValue>
|
template<detail::ValuePreservingTo<Rep> FwdValue>
|
||||||
requires(unit == ::mp_units::one)
|
requires detail::ConvertibleWithNumber<reference>
|
||||||
constexpr quantity& operator=(FwdValue&& val)
|
constexpr quantity& operator=(FwdValue&& val)
|
||||||
{
|
{
|
||||||
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(val);
|
numerical_value_is_an_implementation_detail_ = std::forward<FwdValue>(val);
|
||||||
@ -308,7 +313,7 @@ public:
|
|||||||
|
|
||||||
// conversion operators
|
// conversion operators
|
||||||
template<typename V_, std::constructible_from<Rep> Value = std::remove_cvref_t<V_>>
|
template<typename V_, std::constructible_from<Rep> Value = std::remove_cvref_t<V_>>
|
||||||
requires(unit == ::mp_units::one)
|
requires detail::ConvertibleWithNumber<reference>
|
||||||
[[nodiscard]] explicit operator V_() const& noexcept
|
[[nodiscard]] explicit operator V_() const& noexcept
|
||||||
{
|
{
|
||||||
return numerical_value_is_an_implementation_detail_;
|
return numerical_value_is_an_implementation_detail_;
|
||||||
@ -436,10 +441,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<detail::Mutable<quantity> Q1, QuantityOf<dimensionless> Q2>
|
template<detail::Mutable<quantity> Q1, QuantityOf<dimensionless> Q2>
|
||||||
requires(Q2::unit == ::mp_units::one) && detail::ValuePreservingTo<typename Q2::rep, Rep> &&
|
requires detail::ConvertibleWithNumber<Q2::reference> && detail::ValuePreservingTo<typename Q2::rep, Rep> &&
|
||||||
requires(rep& a, const Q2::rep b) {
|
requires(rep& a, const Q2::rep b) {
|
||||||
{ a *= b } -> std::same_as<rep&>;
|
{ a *= b } -> std::same_as<rep&>;
|
||||||
}
|
}
|
||||||
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
|
friend constexpr decltype(auto) operator*=(Q1&& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
return std::forward<Q1>(lhs) *= rhs.numerical_value_is_an_implementation_detail_;
|
return std::forward<Q1>(lhs) *= rhs.numerical_value_is_an_implementation_detail_;
|
||||||
@ -459,10 +464,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<detail::Mutable<quantity> Q1, QuantityOf<dimensionless> Q2>
|
template<detail::Mutable<quantity> Q1, QuantityOf<dimensionless> Q2>
|
||||||
requires(Q2::unit == ::mp_units::one) && detail::ValuePreservingTo<typename Q2::rep, Rep> &&
|
requires detail::ConvertibleWithNumber<Q2::reference> && detail::ValuePreservingTo<typename Q2::rep, Rep> &&
|
||||||
requires(rep& a, const Q2::rep b) {
|
requires(rep& a, const Q2::rep b) {
|
||||||
{ a /= b } -> std::same_as<rep&>;
|
{ a /= b } -> std::same_as<rep&>;
|
||||||
}
|
}
|
||||||
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
|
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
return std::forward<Q1>(lhs) /= rhs.numerical_value_is_an_implementation_detail_;
|
return std::forward<Q1>(lhs) /= rhs.numerical_value_is_an_implementation_detail_;
|
||||||
@ -481,14 +486,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
|
requires detail::ConvertibleWithNumber<Q::reference> &&
|
||||||
|
detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs)
|
||||||
{
|
{
|
||||||
return lhs + ::mp_units::quantity{rhs};
|
return lhs + ::mp_units::quantity{rhs};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
|
requires detail::ConvertibleWithNumber<Q::reference> &&
|
||||||
|
detail::InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs)
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity{lhs} + rhs;
|
return ::mp_units::quantity{lhs} + rhs;
|
||||||
@ -506,14 +513,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
|
requires detail::ConvertibleWithNumber<Q::reference> &&
|
||||||
|
detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs)
|
||||||
{
|
{
|
||||||
return lhs - ::mp_units::quantity{rhs};
|
return lhs - ::mp_units::quantity{rhs};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
|
requires detail::ConvertibleWithNumber<Q::reference> &&
|
||||||
|
detail::InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs)
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity{lhs} - rhs;
|
return ::mp_units::quantity{lhs} - rhs;
|
||||||
@ -533,14 +542,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
|
requires detail::ConvertibleWithNumber<Q::reference> &&
|
||||||
|
detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs)
|
||||||
{
|
{
|
||||||
return lhs % ::mp_units::quantity{rhs};
|
return lhs % ::mp_units::quantity{rhs};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
|
requires detail::ConvertibleWithNumber<Q::reference> &&
|
||||||
|
detail::InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs)
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity{lhs} % rhs;
|
return ::mp_units::quantity{lhs} % rhs;
|
||||||
@ -592,7 +603,7 @@ public:
|
|||||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& val, const Q& q)
|
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& val, const Q& q)
|
||||||
{
|
{
|
||||||
MP_UNITS_EXPECTS_DEBUG(is_neq_zero(q));
|
MP_UNITS_EXPECTS_DEBUG(is_neq_zero(q));
|
||||||
return ::mp_units::quantity{val / q.numerical_value_ref_in(unit), ::mp_units::one / R};
|
return ::mp_units::quantity{val / q.numerical_value_ref_in(unit), one / R};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, auto R2, typename Rep2>
|
template<std::derived_from<quantity> Q, auto R2, typename Rep2>
|
||||||
@ -607,7 +618,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && std::equality_comparable_with<Rep, Value>
|
requires detail::ConvertibleWithNumber<Q::reference> && std::equality_comparable_with<Rep, Value>
|
||||||
[[nodiscard]] friend constexpr bool operator==(const Q& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr bool operator==(const Q& lhs, const Value& rhs)
|
||||||
{
|
{
|
||||||
return lhs.numerical_value_ref_in(unit) == rhs;
|
return lhs.numerical_value_ref_in(unit) == rhs;
|
||||||
@ -625,7 +636,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<std::derived_from<quantity> Q, Representation Value>
|
template<std::derived_from<quantity> Q, Representation Value>
|
||||||
requires(Q::unit == ::mp_units::one) && std::three_way_comparable_with<Rep, Value>
|
requires detail::ConvertibleWithNumber<Q::reference> && std::three_way_comparable_with<Rep, Value>
|
||||||
[[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr auto operator<=>(const Q& lhs, const Value& rhs)
|
||||||
{
|
{
|
||||||
return lhs.numerical_value_ref_in(unit) <=> rhs;
|
return lhs.numerical_value_ref_in(unit) <=> rhs;
|
||||||
|
@ -279,16 +279,16 @@ static_assert(quantity<isq::length[km]>(1500 * m).numerical_value_in(km) == 1.5)
|
|||||||
|
|
||||||
static_assert(!std::convertible_to<quantity<one>, double>);
|
static_assert(!std::convertible_to<quantity<one>, double>);
|
||||||
static_assert(std::constructible_from<double, quantity<one>>);
|
static_assert(std::constructible_from<double, quantity<one>>);
|
||||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[one]>, double>);
|
|
||||||
static_assert(std::constructible_from<double, quantity<isq::angular_measure[one]>>);
|
|
||||||
static_assert(!std::convertible_to<quantity<one>, int>);
|
static_assert(!std::convertible_to<quantity<one>, int>);
|
||||||
static_assert(std::constructible_from<int, quantity<one>>);
|
static_assert(std::constructible_from<int, quantity<one>>);
|
||||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[one]>, int>);
|
|
||||||
static_assert(std::constructible_from<int, quantity<isq::angular_measure[one]>>);
|
|
||||||
static_assert(!std::convertible_to<quantity<one, int>, double>);
|
static_assert(!std::convertible_to<quantity<one, int>, double>);
|
||||||
static_assert(std::constructible_from<double, quantity<one, int>>);
|
static_assert(std::constructible_from<double, quantity<one, int>>);
|
||||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[one], int>, double>);
|
static_assert(!std::convertible_to<quantity<isq::rotation[one]>, double>);
|
||||||
static_assert(std::constructible_from<double, quantity<isq::angular_measure[one], int>>);
|
static_assert(std::constructible_from<double, quantity<isq::rotation[one]>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<isq::rotation[one]>, int>);
|
||||||
|
static_assert(std::constructible_from<int, quantity<isq::rotation[one]>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<isq::rotation[one], int>, double>);
|
||||||
|
static_assert(std::constructible_from<double, quantity<isq::rotation[one], int>>);
|
||||||
#if MP_UNITS_HOSTED
|
#if MP_UNITS_HOSTED
|
||||||
static_assert(!std::convertible_to<quantity<one, std::complex<double>>, std::complex<double>>);
|
static_assert(!std::convertible_to<quantity<one, std::complex<double>>, std::complex<double>>);
|
||||||
static_assert(std::constructible_from<std::complex<double>, quantity<one, std::complex<double>>>);
|
static_assert(std::constructible_from<std::complex<double>, quantity<one, std::complex<double>>>);
|
||||||
@ -300,6 +300,18 @@ static_assert(!std::convertible_to<quantity<one, double>, cartesian_vector<doubl
|
|||||||
static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>);
|
static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static_assert(!std::convertible_to<quantity<rad>, double>);
|
||||||
|
static_assert(!std::constructible_from<double, quantity<rad>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<rad>, int>);
|
||||||
|
static_assert(!std::constructible_from<int, quantity<rad>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<rad, int>, double>);
|
||||||
|
static_assert(!std::constructible_from<double, quantity<rad, int>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<isq::angular_measure[one]>, double>);
|
||||||
|
static_assert(!std::constructible_from<double, quantity<isq::angular_measure[one]>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<isq::angular_measure[one]>, int>);
|
||||||
|
static_assert(!std::constructible_from<int, quantity<isq::angular_measure[one]>>);
|
||||||
|
static_assert(!std::convertible_to<quantity<isq::angular_measure[one], int>, double>);
|
||||||
|
static_assert(!std::constructible_from<double, quantity<isq::angular_measure[one], int>>);
|
||||||
|
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
// converting to a different unit
|
// converting to a different unit
|
||||||
|
Reference in New Issue
Block a user