refactor: unit-related constexpr functions compile-time evaluation limited to only one that determines the return type

This commit is contained in:
Mateusz Pusz
2024-06-05 08:24:33 +02:00
parent fb77585593
commit 760d48502d
5 changed files with 79 additions and 123 deletions

View File

@@ -64,10 +64,11 @@ template<Quantity To, typename From>
// warnings on conversions // warnings on conversions
} else { } else {
// scale the number // scale the number
constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag; constexpr Magnitude auto c_mag =
constexpr Magnitude auto num = numerator(c_mag); decltype(decltype(get_canonical_unit(q_unit))::mag / decltype(get_canonical_unit(To::unit))::mag){};
constexpr Magnitude auto den = denominator(c_mag); constexpr Magnitude auto num = decltype(numerator(c_mag)){};
constexpr Magnitude auto irr = c_mag * (den / num); constexpr Magnitude auto den = decltype(denominator(c_mag)){};
constexpr Magnitude auto irr = decltype(c_mag * decltype(den / num){}){};
using c_rep_type = maybe_common_type<typename std::remove_reference_t<From>::rep, typename To::rep>; using c_rep_type = maybe_common_type<typename std::remove_reference_t<From>::rep, typename To::rep>;
using c_mag_type = common_magnitude_type<c_mag>; using c_mag_type = common_magnitude_type<c_mag>;
using multiplier_type = conditional< using multiplier_type = conditional<

View File

@@ -46,8 +46,9 @@ namespace mp_units {
namespace detail { namespace detail {
template<auto UFrom, auto UTo> template<auto UFrom, auto UTo>
concept IntegralConversionFactor = Unit<decltype(UFrom)> && Unit<decltype(UTo)> && concept IntegralConversionFactor =
is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag); Unit<decltype(UFrom)> && Unit<decltype(UTo)> &&
is_integral(decltype(decltype(get_canonical_unit(UFrom))::mag / decltype(get_canonical_unit(UTo))::mag){});
template<typename QFrom, typename QTo> template<typename QFrom, typename QTo>
concept QuantityConvertibleTo = concept QuantityConvertibleTo =

View File

@@ -321,22 +321,12 @@ struct is_one<struct one> : std::true_type {};
* @tparam U a unit to use as a `reference_unit` * @tparam U a unit to use as a `reference_unit`
* @tparam M a Magnitude representing an absolute scaling factor of this unit * @tparam M a Magnitude representing an absolute scaling factor of this unit
*/ */
template<Magnitude M, Unit U> template<Magnitude auto M, Unit auto U>
struct canonical_unit { struct canonical_unit {
M mag; static constexpr auto mag = M;
U reference_unit; static constexpr auto reference_unit = U;
}; };
#if MP_UNITS_COMP_CLANG
template<Magnitude M, Unit U>
canonical_unit(M, U) -> canonical_unit<M, U>;
#endif
template<Unit T, symbol_text Symbol, detail::QuantityKindSpec auto Q, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q, Args...>&);
template<Unit T, symbol_text Symbol, auto... Args> template<Unit T, symbol_text Symbol, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&); [[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&);
@@ -352,64 +342,61 @@ template<Unit T, typename... Expr>
template<Unit T, auto M, typename U> template<Unit T, auto M, typename U>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit<M, U>&) [[nodiscard]] consteval auto get_canonical_unit_impl(T, const scaled_unit<M, U>&)
{ {
auto base = get_canonical_unit_impl(U{}, U{}); using base = decltype(get_canonical_unit_impl(U{}, U{}));
return canonical_unit{M * base.mag, base.reference_unit}; return canonical_unit<decltype(M * base::mag){}, base::reference_unit>{};
}
template<Unit T, symbol_text Symbol, detail::QuantityKindSpec auto Q, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q, Args...>&)
{
return canonical_unit{mag<1>, t};
} }
template<Unit T, symbol_text Symbol, auto... Args> template<Unit T, symbol_text Symbol, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Args...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, Args...>&)
{ {
return canonical_unit{mag<1>, t}; return canonical_unit<mag<1>, T{}>{};
} }
template<Unit T, symbol_text Symbol, Unit auto U, auto... Args> template<Unit T, symbol_text Symbol, Unit auto U, auto... Args>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U, Args...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(T, const named_unit<Symbol, U, Args...>&)
{ {
return get_canonical_unit_impl(U, U); return decltype(get_canonical_unit_impl(U, U)){};
} }
template<typename F, int Num, int... Den, typename... Us> template<typename F, int Num, int... Den, typename... Us>
[[nodiscard]] consteval auto get_canonical_unit_impl(const power<F, Num, Den...>&, const type_list<Us...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(const power<F, Num, Den...>&, const type_list<Us...>&)
{ {
auto mag = (mp_units::mag<1> * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).mag)); using mag = decltype((mp_units::mag<1> * ... * pow<Num, Den...>(decltype(get_canonical_unit_impl(Us{}, Us{}))::mag)));
auto u = (one * ... * pow<Num, Den...>(get_canonical_unit_impl(Us{}, Us{}).reference_unit)); using u = decltype((one * ... * pow<Num, Den...>(decltype(get_canonical_unit_impl(Us{}, Us{}))::reference_unit)));
return canonical_unit{mag, u}; return canonical_unit<mag{}, u{}>{};
} }
template<typename T, typename F, int Num, int... Den> template<typename T, typename F, int Num, int... Den>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(T, const power<F, Num, Den...>&)
{ {
auto base = get_canonical_unit_impl(F{}, F{}); using base = decltype(get_canonical_unit_impl(F{}, F{}));
if constexpr (requires { typename decltype(base.reference_unit)::_num_; }) { if constexpr (requires { typename decltype(base::reference_unit)::_num_; }) {
auto num = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_num_{}); using num =
auto den = get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base.reference_unit)::_den_{}); decltype(get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base::reference_unit)::_num_{}));
return canonical_unit{pow<Num, Den...>(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit}; using den =
decltype(get_canonical_unit_impl(power<F, Num, Den...>{}, typename decltype(base::reference_unit)::_den_{}));
return canonical_unit<decltype(decltype(pow<Num, Den...>(base::mag) * num::mag){} / den::mag){},
decltype(num::reference_unit / den::reference_unit){}>{};
} else { } else {
return canonical_unit{pow<Num, Den...>(base.mag), return canonical_unit<decltype(pow<Num, Den...>(base::mag)){},
derived_unit<power<decltype(base.reference_unit), Num, Den...>>{}}; derived_unit<power<std::remove_const_t<decltype(base::reference_unit)>, Num, Den...>>{}>{};
} }
} }
template<typename... Us> template<typename... Us>
[[nodiscard]] consteval auto get_canonical_unit_impl(const type_list<Us...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(const type_list<Us...>&)
{ {
auto m = (mp_units::mag<1> * ... * get_canonical_unit_impl(Us{}, Us{}).mag); using m = decltype((mp_units::mag<1> * ... * decltype(get_canonical_unit_impl(Us{}, Us{}))::mag));
auto u = (one * ... * get_canonical_unit_impl(Us{}, Us{}).reference_unit); using u = decltype((one * ... * decltype(get_canonical_unit_impl(Us{}, Us{}))::reference_unit));
return canonical_unit{m, u}; return canonical_unit<m{}, u{}>{};
} }
template<Unit T, typename... Expr> template<Unit T, typename... Expr>
[[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Expr...>&) [[nodiscard]] consteval auto get_canonical_unit_impl(T, const derived_unit<Expr...>&)
{ {
auto num = get_canonical_unit_impl(typename derived_unit<Expr...>::_num_{}); using num = decltype(get_canonical_unit_impl(typename derived_unit<Expr...>::_num_{}));
auto den = get_canonical_unit_impl(typename derived_unit<Expr...>::_den_{}); using den = decltype(get_canonical_unit_impl(typename derived_unit<Expr...>::_den_{}));
return canonical_unit{num.mag / den.mag, num.reference_unit / den.reference_unit}; return canonical_unit<decltype(num::mag / den::mag){}, decltype(num::reference_unit / den::reference_unit){}>{};
} }
template<Unit Lhs, Unit Rhs> template<Unit Lhs, Unit Rhs>
@@ -422,7 +409,10 @@ using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
// TODO this should really be in the `details` namespace but is used in `chrono.h` (a part of mp_units.systems) // TODO this should really be in the `details` namespace but is used in `chrono.h` (a part of mp_units.systems)
// Even though it is not exported, it is visible to the other module via ADL // Even though it is not exported, it is visible to the other module via ADL
[[nodiscard]] consteval auto get_canonical_unit(Unit auto u) { return detail::get_canonical_unit_impl(u, u); } [[nodiscard]] consteval auto get_canonical_unit(Unit auto u)
{
return decltype(detail::get_canonical_unit_impl(u, u)){};
}
MP_UNITS_EXPORT_BEGIN MP_UNITS_EXPORT_BEGIN
@@ -448,7 +438,7 @@ template<Magnitude M, Unit U>
template<Magnitude M, Unit U> template<Magnitude M, Unit U>
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, U u) [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, U u)
{ {
return mag * inverse(u); return decltype(mag * inverse(u)){};
} }
/** /**
@@ -460,13 +450,13 @@ template<Unit Lhs, Unit Rhs>
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs) [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs)
{ {
if constexpr (detail::is_specialization_of_scaled_unit<Lhs> && detail::is_specialization_of_scaled_unit<Rhs>) if constexpr (detail::is_specialization_of_scaled_unit<Lhs> && detail::is_specialization_of_scaled_unit<Rhs>)
return (Lhs::mag * Rhs::mag) * (Lhs::reference_unit * Rhs::reference_unit); return decltype(Lhs::mag * Rhs::mag){} * decltype(Lhs::reference_unit * Rhs::reference_unit){};
else if constexpr (detail::is_specialization_of_scaled_unit<Lhs>) else if constexpr (detail::is_specialization_of_scaled_unit<Lhs>)
return Lhs::mag * (Lhs::reference_unit * rhs); return decltype(Lhs::mag * decltype(Lhs::reference_unit * rhs){}){};
else if constexpr (detail::is_specialization_of_scaled_unit<Rhs>) else if constexpr (detail::is_specialization_of_scaled_unit<Rhs>)
return Rhs::mag * (lhs * Rhs::reference_unit); return decltype(Rhs::mag * decltype(lhs * Rhs::reference_unit){}){};
else else
return detail::expr_multiply<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs); return decltype(detail::expr_multiply<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs)){};
} }
/** /**
@@ -478,69 +468,36 @@ template<Unit Lhs, Unit Rhs>
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs) [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs)
{ {
if constexpr (detail::is_specialization_of_scaled_unit<Lhs> && detail::is_specialization_of_scaled_unit<Rhs>) if constexpr (detail::is_specialization_of_scaled_unit<Lhs> && detail::is_specialization_of_scaled_unit<Rhs>)
return (Lhs::mag / Rhs::mag) * (Lhs::reference_unit / Rhs::reference_unit); return decltype(Lhs::mag / Rhs::mag){} * decltype(Lhs::reference_unit / Rhs::reference_unit){};
else if constexpr (detail::is_specialization_of_scaled_unit<Lhs>) else if constexpr (detail::is_specialization_of_scaled_unit<Lhs>)
return Lhs::mag * (Lhs::reference_unit / rhs); return Lhs::mag * decltype(Lhs::reference_unit / rhs){};
else if constexpr (detail::is_specialization_of_scaled_unit<Rhs>) else if constexpr (detail::is_specialization_of_scaled_unit<Rhs>)
return mag<1> / Rhs::mag * (lhs / Rhs::reference_unit); return decltype(mag<1> / Rhs::mag){} * decltype(lhs / Rhs::reference_unit){};
else else
return detail::expr_divide<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs); return detail::expr_divide<derived_unit, struct one, detail::type_list_of_unit_less>(lhs, rhs);
} }
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return one / u; } [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return decltype(one / u){}; }
MP_UNITS_EXPORT_END MP_UNITS_EXPORT_END
namespace detail { namespace detail {
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(...) { return false; } [[nodiscard]] consteval auto have_same_canonical_reference_unit(Unit auto u1, Unit auto u2)
template<symbol_text Symbol, auto... D>
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const named_unit<Symbol, D...>&,
const named_unit<Symbol, D...>&)
{ {
return true; using canonical_lhs = decltype(get_canonical_unit(u1));
} using canonical_rhs = decltype(get_canonical_unit(u2));
return std::is_same<decltype(canonical_lhs::reference_unit), decltype(canonical_rhs::reference_unit)>{};
template<typename F1, typename F2, auto... Vs>
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const power<F1, Vs...>&, const power<F2, Vs...>&)
{
return have_same_canonical_reference_unit_impl(F1{}, F2{});
}
template<typename... Us1, typename... Us2>
requires(sizeof...(Us1) == sizeof...(Us2))
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const type_list<Us1...>&, const type_list<Us2...>&)
{
return (... && have_same_canonical_reference_unit_impl(Us1{}, Us2{}));
}
template<typename... Expr1, typename... Expr2>
[[nodiscard]] consteval bool have_same_canonical_reference_unit_impl(const derived_unit<Expr1...>&,
const derived_unit<Expr2...>&)
{
return have_same_canonical_reference_unit_impl(typename derived_unit<Expr1...>::_num_{},
typename derived_unit<Expr2...>::_num_{}) &&
have_same_canonical_reference_unit_impl(typename derived_unit<Expr1...>::_den_{},
typename derived_unit<Expr2...>::_den_{});
}
[[nodiscard]] consteval bool have_same_canonical_reference_unit(Unit auto u1, Unit auto u2)
{
auto canonical_lhs = get_canonical_unit(u1);
auto canonical_rhs = get_canonical_unit(u2);
return have_same_canonical_reference_unit_impl(canonical_lhs.reference_unit, canonical_rhs.reference_unit);
} }
} // namespace detail } // namespace detail
MP_UNITS_EXPORT [[nodiscard]] consteval bool operator==(Unit auto lhs, Unit auto rhs) MP_UNITS_EXPORT template<Unit U1, Unit U2>
[[nodiscard]] consteval bool operator==(U1 lhs, U2 rhs)
{ {
auto canonical_lhs = get_canonical_unit(lhs); return decltype(detail::have_same_canonical_reference_unit(lhs, rhs))::value &&
auto canonical_rhs = get_canonical_unit(rhs); decltype(get_canonical_unit(lhs))::mag == decltype(get_canonical_unit(rhs))::mag;
return detail::have_same_canonical_reference_unit(canonical_lhs.reference_unit, canonical_rhs.reference_unit) &&
canonical_lhs.mag == canonical_rhs.mag;
} }
namespace detail { namespace detail {
@@ -575,7 +532,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
else if constexpr (detail::is_specialization_of_scaled_unit<U>) else if constexpr (detail::is_specialization_of_scaled_unit<U>)
return scaled_unit<pow<Num, Den>(U::mag), decltype(pow<Num, Den>(U::reference_unit))>{}; return scaled_unit<pow<Num, Den>(U::mag), decltype(pow<Num, Den>(U::reference_unit))>{};
else if constexpr (detail::is_specialization_of_derived_unit<U>) else if constexpr (detail::is_specialization_of_derived_unit<U>)
return detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u); return decltype(detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u)){};
else if constexpr (Den == 1) else if constexpr (Den == 1)
return derived_unit<power<U, Num>>{}; return derived_unit<power<U, Num>>{};
else else
@@ -589,7 +546,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
* *
* @return Unit The result of computation * @return Unit The result of computation
*/ */
[[nodiscard]] consteval Unit auto sqrt(Unit auto u) { return pow<1, 2>(u); } [[nodiscard]] consteval Unit auto sqrt(Unit auto u) { return decltype(pow<1, 2>(u)){}; }
/** /**
* @brief Computes the cubic root of a unit * @brief Computes the cubic root of a unit
@@ -598,7 +555,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
* *
* @return Unit The result of computation * @return Unit The result of computation
*/ */
[[nodiscard]] consteval Unit auto cbrt(Unit auto u) { return pow<1, 3>(u); } [[nodiscard]] consteval Unit auto cbrt(Unit auto u) { return decltype(pow<1, 3>(u)){}; }
/** /**
* @brief Computes the square power of a unit * @brief Computes the square power of a unit
@@ -607,7 +564,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
* *
* @return Unit The result of computation * @return Unit The result of computation
*/ */
[[nodiscard]] consteval Unit auto square(Unit auto u) { return pow<2>(u); } [[nodiscard]] consteval Unit auto square(Unit auto u) { return decltype(pow<2>(u)){}; }
/** /**
* @brief Computes the cubic power of a unit * @brief Computes the cubic power of a unit
@@ -616,7 +573,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
* *
* @return Unit The result of computation * @return Unit The result of computation
*/ */
[[nodiscard]] consteval Unit auto cubic(Unit auto u) { return pow<3>(u); } [[nodiscard]] consteval Unit auto cubic(Unit auto u) { return decltype(pow<3>(u)){}; }
// common dimensionless units // common dimensionless units
@@ -631,7 +588,7 @@ inline constexpr auto ppm = parts_per_million;
// convertible_to // convertible_to
[[nodiscard]] consteval bool convertible(Unit auto from, Unit auto to) [[nodiscard]] consteval bool convertible(Unit auto from, Unit auto to)
{ {
return detail::have_same_canonical_reference_unit(from, to); return decltype(detail::have_same_canonical_reference_unit(from, to))::value;
} }
// Common unit // Common unit
@@ -639,7 +596,7 @@ inline constexpr auto ppm = parts_per_million;
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(decltype(detail::have_same_canonical_reference_unit(u1, u2))::value)
{ {
if constexpr (U1{} == U2{}) { if constexpr (U1{} == U2{}) {
if constexpr (std::derived_from<U1, U2>) if constexpr (std::derived_from<U1, U2>)
@@ -648,18 +605,18 @@ template<Unit U1, Unit U2>
return u2; return u2;
else else
// TODO Check if there is a better choice here // TODO Check if there is a better choice here
return detail::better_type_name(u1, u2); return decltype(detail::better_type_name(u1, u2)){};
} else { } else {
constexpr auto canonical_lhs = get_canonical_unit(U1{}); using canonical_lhs = decltype(get_canonical_unit(U1{}));
constexpr auto canonical_rhs = get_canonical_unit(U2{}); using canonical_rhs = decltype(get_canonical_unit(U2{}));
if constexpr (is_integral(canonical_lhs.mag / canonical_rhs.mag)) if constexpr (is_integral(decltype(canonical_lhs::mag / canonical_rhs::mag){}))
return u2; return u2;
else if constexpr (is_integral(canonical_rhs.mag / canonical_lhs.mag)) else if constexpr (is_integral(decltype(canonical_rhs::mag / canonical_lhs::mag){}))
return u1; return u1;
else { else {
constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag); constexpr auto cm = decltype(detail::common_magnitude(canonical_lhs::mag, canonical_rhs::mag)){};
return scaled_unit<cm, decltype(canonical_lhs.reference_unit)>{}; return scaled_unit<cm, std::remove_const_t<decltype(canonical_lhs::reference_unit)>>{};
} }
} }
} }
@@ -667,7 +624,7 @@ template<Unit U1, Unit U2>
[[nodiscard]] consteval Unit auto common_unit(Unit auto u1, Unit auto u2, Unit auto u3, Unit auto... rest) [[nodiscard]] consteval Unit auto common_unit(Unit auto u1, Unit auto u2, Unit auto u3, Unit auto... rest)
requires requires { common_unit(common_unit(u1, u2), u3, rest...); } requires requires { common_unit(common_unit(u1, u2), u3, rest...); }
{ {
return common_unit(common_unit(u1, u2), u3, rest...); return decltype(common_unit(common_unit(u1, u2), u3, rest...)){};
} }

View File

@@ -33,9 +33,8 @@ namespace mp_units {
namespace detail { namespace detail {
// do not refactor below to a variable template - GCC-11 does not like it
template<typename T> template<typename T>
struct is_unit : std::false_type {}; inline constexpr bool is_unit = false;
} // namespace detail } // namespace detail
@@ -45,7 +44,7 @@ struct is_unit : std::false_type {};
* Satisfied by all unit types provided by the library. * Satisfied by all unit types provided by the library.
*/ */
MP_UNITS_EXPORT template<typename T> MP_UNITS_EXPORT template<typename T>
concept Unit = detail::is_unit<T>::value; concept Unit = detail::is_unit<T>;
template<Magnitude auto M, Unit U> template<Magnitude auto M, Unit U>
struct scaled_unit; struct scaled_unit;
@@ -144,8 +143,8 @@ inline constexpr bool is_specialization_of_prefixed_unit<prefixed_unit<Symbol, M
template<typename T> template<typename T>
requires requires(T* t) { is_unit_impl(t); } && (!is_specialization_of_named_unit<T>) && requires requires(T* t) { is_unit_impl(t); } && (!is_specialization_of_named_unit<T>) &&
(!is_specialization_of_prefixed_unit<T>) (!is_specialization_of_prefixed_unit<T>)
struct is_unit<T> : std::true_type {}; inline constexpr bool is_unit<T> = true;
template<Unit U> template<Unit U>
[[nodiscard]] consteval bool has_associated_quantity(U); [[nodiscard]] consteval bool has_associated_quantity(U);
@@ -197,7 +196,7 @@ concept UnitOf =
namespace detail { namespace detail {
[[nodiscard]] consteval bool have_same_canonical_reference_unit(Unit auto u1, Unit auto u2); [[nodiscard]] consteval auto have_same_canonical_reference_unit(Unit auto u1, Unit auto u2);
} }
@@ -210,7 +209,7 @@ namespace detail {
MP_UNITS_EXPORT template<typename U, auto U2, auto QS> MP_UNITS_EXPORT template<typename U, auto U2, 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(U2))> && 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>)&&decltype(detail::have_same_canonical_reference_unit(U{}, U2))::value;
} // namespace mp_units } // namespace mp_units

View File

@@ -116,8 +116,7 @@ struct quantity_point_like_traits<std::chrono::time_point<C, std::chrono::durati
template<QuantityOf<isq::time> Q> template<QuantityOf<isq::time> Q>
[[nodiscard]] constexpr auto to_chrono_duration(const Q& q) [[nodiscard]] constexpr auto to_chrono_duration(const Q& q)
{ {
constexpr auto canonical = get_canonical_unit(Q::unit); constexpr detail::ratio r = detail::as_ratio(decltype(get_canonical_unit(Q::unit))::mag);
constexpr detail::ratio r = detail::as_ratio(canonical.mag);
return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q}; return std::chrono::duration<typename Q::rep, std::ratio<r.num, r.den>>{q};
} }
@@ -127,8 +126,7 @@ template<QuantityPointOf<isq::time> QP>
{ {
using clock = MP_UNITS_TYPENAME decltype(QP::absolute_point_origin)::clock; using clock = MP_UNITS_TYPENAME decltype(QP::absolute_point_origin)::clock;
using rep = MP_UNITS_TYPENAME QP::rep; using rep = MP_UNITS_TYPENAME QP::rep;
constexpr auto canonical = get_canonical_unit(QP::unit); constexpr detail::ratio r = detail::as_ratio(decltype(get_canonical_unit(QP::unit))::mag);
constexpr detail::ratio r = detail::as_ratio(canonical.mag);
using ret_type = std::chrono::time_point<clock, std::chrono::duration<rep, std::ratio<r.num, r.den>>>; using ret_type = std::chrono::time_point<clock, std::chrono::duration<rep, std::ratio<r.num, r.den>>>;
return ret_type(to_chrono_duration(qp - qp.absolute_point_origin)); return ret_type(to_chrono_duration(qp - qp.absolute_point_origin));
} }