forked from mpusz/mp-units
refactor: error messages-related improvements
This commit is contained in:
@@ -97,12 +97,20 @@ concept DerivedDimension =
|
|||||||
MP_UNITS_EXPORT template<typename T>
|
MP_UNITS_EXPORT template<typename T>
|
||||||
concept Dimension = detail::BaseDimension<T> || detail::DerivedDimension<T>;
|
concept Dimension = detail::BaseDimension<T> || detail::DerivedDimension<T>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<auto D1, auto D2>
|
||||||
|
concept SameDimension =
|
||||||
|
Dimension<MP_UNITS_REMOVE_CONST(decltype(D1))> && Dimension<MP_UNITS_REMOVE_CONST(decltype(D2))> && (D1 == D2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept checking if the argument is of the same dimension.
|
* @brief A concept checking if the argument is of the same dimension.
|
||||||
*
|
*
|
||||||
* Satisfied when both argument satisfy a `Dimension` concept and when they compare equal.
|
* Satisfied when both argument satisfy a `Dimension` concept and when they compare equal.
|
||||||
*/
|
*/
|
||||||
MP_UNITS_EXPORT template<typename T, auto D>
|
MP_UNITS_EXPORT template<typename T, auto D>
|
||||||
concept DimensionOf = Dimension<T> && Dimension<MP_UNITS_REMOVE_CONST(decltype(D))> && (T{} == D);
|
concept DimensionOf = Dimension<T> && Dimension<MP_UNITS_REMOVE_CONST(decltype(D))> && detail::SameDimension<T{}, D>;
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@@ -56,12 +56,15 @@ template<Unit UFrom, Unit UTo>
|
|||||||
return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag);
|
return is_integral(get_canonical_unit(from).mag / get_canonical_unit(to).mag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept IsFloatingPoint = treat_as_floating_point<T>;
|
||||||
|
|
||||||
template<typename QFrom, typename QTo>
|
template<typename QFrom, typename QTo>
|
||||||
concept QuantityConvertibleTo =
|
concept QuantityConvertibleTo =
|
||||||
Quantity<QFrom> && Quantity<QTo> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
|
Quantity<QFrom> && Quantity<QTo> && detail::QuantitySpecConvertibleTo<QFrom::quantity_spec, QTo::quantity_spec> &&
|
||||||
convertible(QFrom::unit, QTo::unit) &&
|
detail::UnitConvertibleTo<QFrom::unit, QTo::unit> &&
|
||||||
(treat_as_floating_point<typename QTo::rep> ||
|
(IsFloatingPoint<typename QTo::rep> ||
|
||||||
(!treat_as_floating_point<typename QFrom::rep> && (integral_conversion_factor(QFrom::unit, QTo::unit)))) &&
|
(!IsFloatingPoint<typename QFrom::rep> && (integral_conversion_factor(QFrom::unit, QTo::unit)))) &&
|
||||||
// TODO consider providing constraints of sudo_cast here rather than testing if it can be called (its return type is
|
// TODO consider providing constraints of sudo_cast here rather than testing if it can be called (its return type is
|
||||||
// deduced thus the function is evaluated here and may emit truncating conversion or other warnings)
|
// deduced thus the function is evaluated here and may emit truncating conversion or other warnings)
|
||||||
requires(QFrom q) { detail::sudo_cast<QTo>(q); };
|
requires(QFrom q) { detail::sudo_cast<QTo>(q); };
|
||||||
@@ -75,23 +78,28 @@ template<typename Func, typename Q1, typename Q2,
|
|||||||
concept InvocableQuantities =
|
concept InvocableQuantities =
|
||||||
Quantity<Q1> && Quantity<Q2> && InvokeResultOf<Ch, Func, typename Q1::rep, typename Q2::rep>;
|
Quantity<Q1> && Quantity<Q2> && InvokeResultOf<Ch, Func, typename Q1::rep, typename Q2::rep>;
|
||||||
|
|
||||||
|
// TODO remove the following when clang diagnostics improve
|
||||||
|
// https://github.com/llvm/llvm-project/issues/96660
|
||||||
|
template<auto R1, auto R2>
|
||||||
|
concept HaveCommonReferenceImpl = requires { common_reference(R1, R2); };
|
||||||
|
|
||||||
|
template<auto R1, auto R2>
|
||||||
|
concept HaveCommonReference = HaveCommonReferenceImpl<R1, R2>;
|
||||||
|
|
||||||
template<typename Func, typename Q1, typename Q2>
|
template<typename Func, typename Q1, typename Q2>
|
||||||
concept CommonlyInvocableQuantities =
|
concept CommonlyInvocableQuantities =
|
||||||
Quantity<Q1> && Quantity<Q2> &&
|
Quantity<Q1> && Quantity<Q2> && HaveCommonReference<Q1::reference, Q2::reference> &&
|
||||||
// (Q1::quantity_spec.character == Q2::quantity_spec.character) && // TODO enable when vector quantities are handled
|
|
||||||
// correctly
|
|
||||||
requires { common_reference(Q1::reference, Q2::reference); } &&
|
|
||||||
InvocableQuantities<Func, Q1, Q2, common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character>;
|
InvocableQuantities<Func, Q1, Q2, common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character>;
|
||||||
|
|
||||||
|
|
||||||
template<typename Func, Quantity Q1, Quantity Q2>
|
template<typename Func, Quantity Q1, Quantity Q2>
|
||||||
requires detail::CommonlyInvocableQuantities<Func, Q1, Q2>
|
requires detail::CommonlyInvocableQuantities<Func, Q1, Q2>
|
||||||
using common_quantity_for = quantity<common_reference(Q1::reference, Q2::reference),
|
using common_quantity_for = quantity<common_reference(Q1::reference, Q2::reference),
|
||||||
std::invoke_result_t<Func, typename Q1::rep, typename Q2::rep>>;
|
std::invoke_result_t<Func, typename Q1::rep, typename Q2::rep>>;
|
||||||
|
|
||||||
template<auto T, auto R>
|
template<auto T, auto R>
|
||||||
concept SameOriginalReferenceAs = DeltaReference<MP_UNITS_REMOVE_CONST(decltype(T))> &&
|
concept SameOriginalReferenceAs =
|
||||||
Reference<MP_UNITS_REMOVE_CONST(decltype(R))> && (get_original_reference(T) == R);
|
DeltaReference<MP_UNITS_REMOVE_CONST(decltype(T))> && Reference<MP_UNITS_REMOVE_CONST(decltype(R))> &&
|
||||||
|
detail::SameReference<remove_reference_specifier(T), R>;
|
||||||
|
|
||||||
template<auto R1, auto R2, typename Rep1, typename Rep2>
|
template<auto R1, auto R2, typename Rep1, typename Rep2>
|
||||||
concept SameValueAs = detail::SameOriginalReferenceAs<R1, R2> && std::same_as<Rep1, Rep2>;
|
concept SameValueAs = detail::SameOriginalReferenceAs<R1, R2> && std::same_as<Rep1, Rep2>;
|
||||||
@@ -238,14 +246,14 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<UnitCompatibleWith<unit, quantity_spec> U>
|
template<UnitCompatibleWith<unit, quantity_spec> U>
|
||||||
requires requires(quantity q) { q.in(U{}); }
|
requires detail::QuantityConvertibleTo<quantity, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
|
||||||
[[nodiscard]] constexpr rep numerical_value_in(U) const noexcept
|
[[nodiscard]] constexpr rep numerical_value_in(U) const noexcept
|
||||||
{
|
{
|
||||||
return (*this).in(U{}).numerical_value_is_an_implementation_detail_;
|
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) { value_cast<U{}>(q); }
|
||||||
[[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_is_an_implementation_detail_;
|
return (*this).force_in(U{}).numerical_value_is_an_implementation_detail_;
|
||||||
|
@@ -53,7 +53,8 @@ namespace mp_units {
|
|||||||
* @tparam ToQS a quantity specification to use for a target quantity
|
* @tparam ToQS a quantity specification to use for a target quantity
|
||||||
*/
|
*/
|
||||||
template<QuantitySpec auto ToQS, typename Q>
|
template<QuantitySpec auto ToQS, typename Q>
|
||||||
requires Quantity<std::remove_cvref_t<Q>> && (castable(std::remove_reference_t<Q>::quantity_spec, ToQS))
|
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||||
|
detail::QuantitySpecCastableTo<std::remove_reference_t<Q>::quantity_spec, ToQS>
|
||||||
[[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_,
|
||||||
@@ -78,7 +79,8 @@ template<QuantitySpec auto ToQS, typename Q>
|
|||||||
* @tparam ToQS a quantity specification to use for a target quantity point
|
* @tparam ToQS a quantity specification to use for a target quantity point
|
||||||
*/
|
*/
|
||||||
template<QuantitySpec auto ToQS, typename QP>
|
template<QuantitySpec auto ToQS, typename QP>
|
||||||
requires QuantityPoint<std::remove_cvref_t<QP>> && (castable(std::remove_reference_t<QP>::quantity_spec, ToQS))
|
requires QuantityPoint<std::remove_cvref_t<QP>> &&
|
||||||
|
detail::QuantitySpecCastableTo<std::remove_reference_t<QP>::quantity_spec, ToQS>
|
||||||
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(QP&& qp)
|
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(QP&& qp)
|
||||||
{
|
{
|
||||||
return QP{quantity_cast<ToQS>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
return QP{quantity_cast<ToQS>(std::forward<QP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||||
|
@@ -271,18 +271,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unit conversions
|
// unit conversions
|
||||||
template<UnitCompatibleWith<unit, quantity_spec> U>
|
template<UnitCompatibleWith<unit, quantity_spec> ToU>
|
||||||
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, U{}), Rep>>
|
requires detail::QuantityConvertibleTo<quantity_type, quantity<detail::make_reference(quantity_spec, ToU{}), Rep>>
|
||||||
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(U) const
|
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto in(ToU) const
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity_point{quantity_ref_from(PO).in(U{}), PO};
|
return ::mp_units::quantity_point{quantity_ref_from(PO).in(ToU{}), PO};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<UnitCompatibleWith<unit, quantity_spec> U>
|
template<UnitCompatibleWith<unit, quantity_spec> ToU>
|
||||||
requires requires(quantity_type q) { value_cast<U{}>(q); }
|
requires requires(quantity_type q) { value_cast<ToU{}>(q); }
|
||||||
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(U) const
|
[[nodiscard]] constexpr QuantityPointOf<quantity_spec> auto force_in(ToU) const
|
||||||
{
|
{
|
||||||
return ::mp_units::quantity_point{quantity_ref_from(PO).force_in(U{}), PO};
|
return ::mp_units::quantity_point{quantity_ref_from(PO).force_in(ToU{}), PO};
|
||||||
}
|
}
|
||||||
|
|
||||||
// conversion operators
|
// conversion operators
|
||||||
|
@@ -126,7 +126,7 @@ struct quantity_spec_interface {
|
|||||||
template<typename Self, typename Q>
|
template<typename Self, typename Q>
|
||||||
[[nodiscard]] constexpr Quantity auto operator()(this Self self, Q&& q)
|
[[nodiscard]] constexpr Quantity auto operator()(this Self self, Q&& q)
|
||||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||||
(explicitly_convertible(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)>};
|
delta<detail::make_reference(self, std::remove_cvref_t<Q>::unit)>};
|
||||||
@@ -140,7 +140,7 @@ struct quantity_spec_interface {
|
|||||||
|
|
||||||
template<typename Q, typename Self_ = Self>
|
template<typename Q, typename Self_ = Self>
|
||||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||||
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
|
detail::QuantitySpecExplicitlyConvertibleTo<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 quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||||
@@ -337,7 +337,7 @@ struct quantity_spec<Self, QS, Args...> : detail::propagate_equation<QS>, detail
|
|||||||
|
|
||||||
template<typename Q, typename Self_ = Self>
|
template<typename Q, typename Self_ = Self>
|
||||||
requires Quantity<std::remove_cvref_t<Q>> &&
|
requires Quantity<std::remove_cvref_t<Q>> &&
|
||||||
(explicitly_convertible(std::remove_reference_t<Q>::quantity_spec, Self_{}))
|
detail::QuantitySpecExplicitlyConvertibleTo<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 quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
return quantity{std::forward<Q>(q).numerical_value_is_an_implementation_detail_,
|
||||||
@@ -379,16 +379,16 @@ struct quantity_spec<Self, QS, Args...> : detail::propagate_equation<QS>, detail
|
|||||||
#ifdef MP_UNITS_API_NO_CRTP
|
#ifdef MP_UNITS_API_NO_CRTP
|
||||||
template<detail::NamedQuantitySpec auto QS, detail::DerivedQuantitySpec auto Eq,
|
template<detail::NamedQuantitySpec auto QS, detail::DerivedQuantitySpec auto Eq,
|
||||||
one_of<quantity_character, struct is_kind> auto... Args>
|
one_of<quantity_character, struct is_kind> auto... Args>
|
||||||
requires(!requires { QS._equation_; } || (requires {
|
requires(!requires { QS._equation_; } ||
|
||||||
QS._equation_;
|
((requires { QS._equation_; }) && detail::QuantitySpecExplicitlyConvertibleTo<Eq, QS._equation_>)) &&
|
||||||
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
|
(... && !QuantitySpec<decltype(Args)>)
|
||||||
struct quantity_spec<QS, Eq, Args...> : detail::quantity_spec_interface {
|
struct quantity_spec<QS, Eq, Args...> : detail::quantity_spec_interface {
|
||||||
#else
|
#else
|
||||||
template<typename Self, detail::NamedQuantitySpec auto QS, detail::DerivedQuantitySpec auto Eq,
|
template<typename Self, detail::NamedQuantitySpec auto QS, detail::DerivedQuantitySpec auto Eq,
|
||||||
one_of<quantity_character, struct is_kind> auto... Args>
|
one_of<quantity_character, struct is_kind> auto... Args>
|
||||||
requires(!requires { QS._equation_; } || (requires {
|
requires(!requires { QS._equation_; } ||
|
||||||
QS._equation_;
|
((requires { QS._equation_; }) && detail::QuantitySpecExplicitlyConvertibleTo<Eq, QS._equation_>)) &&
|
||||||
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
|
(... && !QuantitySpec<decltype(Args)>)
|
||||||
struct quantity_spec<Self, QS, Eq, Args...> : detail::quantity_spec_interface<Self> {
|
struct quantity_spec<Self, QS, Eq, Args...> : detail::quantity_spec_interface<Self> {
|
||||||
#endif
|
#endif
|
||||||
using _base_type_ = quantity_spec;
|
using _base_type_ = quantity_spec;
|
||||||
@@ -498,7 +498,7 @@ template<QuantitySpec Q>
|
|||||||
|
|
||||||
#ifdef MP_UNITS_API_NO_CRTP
|
#ifdef MP_UNITS_API_NO_CRTP
|
||||||
template<typename Q>
|
template<typename Q>
|
||||||
requires detail::QuantitySpecWithNoSpecifiers<Q> && (detail::get_kind_tree_root(Q{}) == Q{})
|
requires detail::QuantitySpecWithNoSpecifiers<Q> && detail::SameQuantitySpec<detail::get_kind_tree_root(Q{}), Q{}>
|
||||||
struct kind_of_<Q> final : Q::_base_type_ {
|
struct kind_of_<Q> final : Q::_base_type_ {
|
||||||
using _base_type_ = kind_of_;
|
using _base_type_ = kind_of_;
|
||||||
static constexpr auto _quantity_spec_ = Q{};
|
static constexpr auto _quantity_spec_ = Q{};
|
||||||
@@ -507,10 +507,10 @@ struct kind_of_<Q> final : Q::_base_type_ {
|
|||||||
|
|
||||||
#if MP_UNITS_COMP_CLANG
|
#if MP_UNITS_COMP_CLANG
|
||||||
template<typename Q>
|
template<typename Q>
|
||||||
requires detail::QuantitySpecWithNoSpecifiers<Q> && (detail::get_kind_tree_root(Q{}) == Q{})
|
requires detail::QuantitySpecWithNoSpecifiers<Q> && detail::SameQuantitySpec<detail::get_kind_tree_root(Q{}), Q{}>
|
||||||
#else
|
#else
|
||||||
template<detail::QuantitySpecWithNoSpecifiers Q>
|
template<detail::QuantitySpecWithNoSpecifiers Q>
|
||||||
requires(detail::get_kind_tree_root(Q{}) == Q{})
|
requires detail::SameQuantitySpec<detail::get_kind_tree_root(Q{}), Q{}>
|
||||||
#endif
|
#endif
|
||||||
struct kind_of_<Q> final : quantity_spec<kind_of_<Q>, Q{}>::_base_type_ {
|
struct kind_of_<Q> final : quantity_spec<kind_of_<Q>, Q{}>::_base_type_ {
|
||||||
using _base_type_ = kind_of_;
|
using _base_type_ = kind_of_;
|
||||||
@@ -519,7 +519,7 @@ struct kind_of_<Q> final : quantity_spec<kind_of_<Q>, Q{}>::_base_type_ {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
MP_UNITS_EXPORT template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
MP_UNITS_EXPORT template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
||||||
requires(detail::get_kind_tree_root(Q) == Q)
|
requires detail::SameQuantitySpec<detail::get_kind_tree_root(Q), Q>
|
||||||
inline constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
|
inline constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -1531,8 +1531,8 @@ template<QuantitySpec Q>
|
|||||||
|
|
||||||
template<QuantitySpec Q1, QuantitySpec Q2>
|
template<QuantitySpec Q1, QuantitySpec Q2>
|
||||||
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2)
|
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2)
|
||||||
requires(implicitly_convertible(get_kind_tree_root(q1), get_kind_tree_root(q2)) ||
|
requires detail::QuantitySpecConvertibleTo<get_kind_tree_root(q1), get_kind_tree_root(q2)> ||
|
||||||
implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1)))
|
detail::QuantitySpecConvertibleTo<get_kind_tree_root(q2), get_kind_tree_root(q1)>
|
||||||
{
|
{
|
||||||
using QQ1 = decltype(detail::remove_kind(q1));
|
using QQ1 = decltype(detail::remove_kind(q1));
|
||||||
using QQ2 = decltype(detail::remove_kind(q2));
|
using QQ2 = decltype(detail::remove_kind(q2));
|
||||||
|
@@ -125,18 +125,41 @@ MP_UNITS_EXPORT template<QuantitySpec Q>
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
template<auto QS1, auto QS2>
|
||||||
|
concept SameQuantitySpec = QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS1))> &&
|
||||||
|
QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS2))> && (QS1 == QS2);
|
||||||
|
|
||||||
template<QuantitySpec Child, QuantitySpec Parent>
|
template<QuantitySpec Child, QuantitySpec Parent>
|
||||||
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p);
|
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p);
|
||||||
|
|
||||||
|
template<auto Child, auto Parent>
|
||||||
|
concept ChildQuantitySpecOf = (is_child_of(Child, Parent));
|
||||||
|
|
||||||
template<auto To, auto From>
|
template<auto To, auto From>
|
||||||
concept NestedQuantityKindSpecOf = QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> &&
|
concept NestedQuantityKindSpecOf =
|
||||||
get_kind(From) != get_kind(To) && is_child_of(To, get_kind(From)._quantity_spec_);
|
QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> &&
|
||||||
|
(!SameQuantitySpec<get_kind(From), get_kind(To)>)&&ChildQuantitySpecOf<To, get_kind(From)._quantity_spec_>;
|
||||||
|
|
||||||
|
template<auto From, auto To>
|
||||||
|
concept QuantitySpecConvertibleTo =
|
||||||
|
QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(From))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(To))> &&
|
||||||
|
implicitly_convertible(From, To);
|
||||||
|
|
||||||
|
template<auto From, auto To>
|
||||||
|
concept QuantitySpecExplicitlyConvertibleTo =
|
||||||
|
QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(From))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(To))> &&
|
||||||
|
explicitly_convertible(From, To);
|
||||||
|
|
||||||
|
template<auto From, auto To>
|
||||||
|
concept QuantitySpecCastableTo =
|
||||||
|
QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(From))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(To))> &&
|
||||||
|
castable(From, To);
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
MP_UNITS_EXPORT template<typename T, auto QS>
|
MP_UNITS_EXPORT template<typename T, auto QS>
|
||||||
concept QuantitySpecOf =
|
concept QuantitySpecOf =
|
||||||
QuantitySpec<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && implicitly_convertible(T{}, QS) &&
|
QuantitySpec<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && detail::QuantitySpecConvertibleTo<T{}, QS> &&
|
||||||
// the below is to make the following work
|
// the below is to make the following work
|
||||||
// static_assert(ReferenceOf<si::radian, isq::angular_measure>);
|
// static_assert(ReferenceOf<si::radian, isq::angular_measure>);
|
||||||
// static_assert(!ReferenceOf<si::radian, dimensionless>);
|
// static_assert(!ReferenceOf<si::radian, dimensionless>);
|
||||||
|
@@ -108,4 +108,12 @@ concept AbsoluteReference = is_specialization_of<T, absolute_>;
|
|||||||
|
|
||||||
MP_UNITS_EXPORT_END
|
MP_UNITS_EXPORT_END
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<auto R1, auto R2>
|
||||||
|
concept SameReference =
|
||||||
|
Reference<MP_UNITS_REMOVE_CONST(decltype(R1))> && Reference<MP_UNITS_REMOVE_CONST(decltype(R2))> && (R1 == R2);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@@ -66,7 +66,7 @@ struct system_reference {
|
|||||||
static constexpr auto coherent_unit = CoU;
|
static constexpr auto coherent_unit = CoU;
|
||||||
|
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
requires(convertible(coherent_unit, U{}))
|
requires detail::UnitConvertibleTo<coherent_unit, U{}>
|
||||||
#if MP_UNITS_COMP_MSVC
|
#if MP_UNITS_COMP_MSVC
|
||||||
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
|
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
|
||||||
#else
|
#else
|
||||||
|
@@ -518,12 +518,11 @@ template<Unit U1, Unit U2>
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
MP_UNITS_EXPORT [[nodiscard]] consteval bool operator==(Unit auto lhs, Unit auto rhs)
|
MP_UNITS_EXPORT [[nodiscard]] consteval bool operator==(Unit auto lhs, Unit auto rhs)
|
||||||
{
|
{
|
||||||
auto canonical_lhs = get_canonical_unit(lhs);
|
auto canonical_lhs = get_canonical_unit(lhs);
|
||||||
auto canonical_rhs = get_canonical_unit(rhs);
|
auto canonical_rhs = get_canonical_unit(rhs);
|
||||||
return detail::have_same_canonical_reference_unit(canonical_lhs.reference_unit, canonical_rhs.reference_unit) &&
|
return convertible(canonical_lhs.reference_unit, canonical_rhs.reference_unit) &&
|
||||||
canonical_lhs.mag == canonical_rhs.mag;
|
canonical_lhs.mag == canonical_rhs.mag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,11 +611,11 @@ inline constexpr auto ppm = parts_per_million;
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
// convertible_to
|
// convertible
|
||||||
template<Unit U1, Unit U2>
|
template<Unit From, Unit To>
|
||||||
[[nodiscard]] consteval bool convertible(U1 from, U2 to)
|
[[nodiscard]] consteval bool convertible(From from, To to)
|
||||||
{
|
{
|
||||||
if constexpr (is_same_v<U1, U2>)
|
if constexpr (is_same_v<From, To>)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return detail::have_same_canonical_reference_unit(from, to);
|
return detail::have_same_canonical_reference_unit(from, to);
|
||||||
@@ -627,7 +626,7 @@ template<Unit U1, Unit U2>
|
|||||||
|
|
||||||
template<Unit U1, Unit U2>
|
template<Unit U1, Unit U2>
|
||||||
[[nodiscard]] consteval Unit auto common_unit(U1 u1, U2 u2)
|
[[nodiscard]] consteval Unit auto common_unit(U1 u1, U2 u2)
|
||||||
requires(detail::have_same_canonical_reference_unit(u1, u2))
|
requires(convertible(u1, u2))
|
||||||
{
|
{
|
||||||
if constexpr (is_same_v<U1, U2>)
|
if constexpr (is_same_v<U1, U2>)
|
||||||
return u1;
|
return u1;
|
||||||
|
@@ -182,18 +182,22 @@ concept AssociatedUnit = Unit<U> && detail::has_associated_quantity(U{});
|
|||||||
* the provided quantity_spec type.
|
* the provided quantity_spec type.
|
||||||
*/
|
*/
|
||||||
MP_UNITS_EXPORT template<typename U, auto QS>
|
MP_UNITS_EXPORT template<typename U, auto QS>
|
||||||
concept UnitOf =
|
concept UnitOf = AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||||
AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
detail::QuantitySpecConvertibleTo<get_quantity_spec(U{}), QS> &&
|
||||||
implicitly_convertible(get_quantity_spec(U{}), QS) &&
|
// the below is to make `dimensionless[radian]` invalid
|
||||||
// the below is to make `dimensionless[radian]` invalid
|
(detail::SameQuantitySpec<get_kind(QS), get_kind(get_quantity_spec(U{}))> ||
|
||||||
(get_kind(QS) == get_kind(get_quantity_spec(U{})) || !detail::NestedQuantityKindSpecOf<get_quantity_spec(U{}), QS>);
|
!detail::NestedQuantityKindSpecOf<get_quantity_spec(U{}), QS>);
|
||||||
|
|
||||||
|
MP_UNITS_EXPORT template<Unit From, Unit To>
|
||||||
|
[[nodiscard]] consteval bool convertible(From from, To to);
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<Unit U1, Unit U2>
|
template<auto From, auto To>
|
||||||
[[nodiscard]] consteval bool have_same_canonical_reference_unit(U1 u1, U2 u2);
|
concept UnitConvertibleTo =
|
||||||
|
Unit<MP_UNITS_REMOVE_CONST(decltype(From))> && Unit<MP_UNITS_REMOVE_CONST(decltype(To))> && (convertible(From, To));
|
||||||
|
|
||||||
}
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all units compatible with the provided unit and quantity spec
|
* @brief A concept matching all units compatible with the provided unit and quantity spec
|
||||||
@@ -201,10 +205,9 @@ template<Unit U1, Unit U2>
|
|||||||
* Satisfied by all units that have the same canonical reference as `U2` and in case they
|
* Satisfied by all units that have the same canonical reference as `U2` and in case they
|
||||||
* have associated quantity specification it should satisfy `UnitOf<QS>`.
|
* have associated quantity specification it should satisfy `UnitOf<QS>`.
|
||||||
*/
|
*/
|
||||||
MP_UNITS_EXPORT template<typename U, auto U2, auto QS>
|
MP_UNITS_EXPORT template<typename U, auto FromU, auto QS>
|
||||||
concept UnitCompatibleWith =
|
concept UnitCompatibleWith =
|
||||||
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(FromU))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||||
(!AssociatedUnit<U> || UnitOf<U, QS>)&&(detail::have_same_canonical_reference_unit(U{}, U2));
|
(!AssociatedUnit<U> || UnitOf<U, QS>)&&detail::UnitConvertibleTo<FromU, U{}>;
|
||||||
|
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
Reference in New Issue
Block a user