mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 20:34:26 +02:00
refactor: library concepts cleanup
This commit is contained in:
@@ -42,18 +42,13 @@ inline constexpr bool is_specialization_of_base_dimension = false;
|
||||
template<basic_symbol_text Symbol>
|
||||
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all named base dimensions in the library.
|
||||
*
|
||||
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept BaseDimension =
|
||||
requires(T* t) { detail::to_base_base_dimension(t); } && (!detail::is_specialization_of_base_dimension<T>);
|
||||
|
||||
namespace detail {
|
||||
concept BaseDimension = requires(T* t) { to_base_base_dimension(t); } && (!is_specialization_of_base_dimension<T>);
|
||||
|
||||
template<typename T>
|
||||
struct is_dimension_one : std::false_type {};
|
||||
@@ -71,13 +66,13 @@ template<typename... Ts>
|
||||
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
||||
(... && (BaseDimension<Ts> || is_dimension_one<Ts>::value || is_power_of_dim<Ts>));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept DerivedDimensionExpr =
|
||||
BaseDimension<T> || detail::is_dimension_one<T>::value || detail::is_power_of_dim<T> || detail::is_per_of_dims<T>;
|
||||
BaseDimension<T> || is_dimension_one<T>::value || is_power_of_dim<T> || is_per_of_dims<T>;
|
||||
|
||||
template<DerivedDimensionExpr... Expr>
|
||||
} // namespace detail
|
||||
|
||||
template<detail::DerivedDimensionExpr... Expr>
|
||||
struct derived_dimension;
|
||||
|
||||
namespace detail {
|
||||
@@ -99,6 +94,6 @@ concept DerivedDimension = is_derived_from_specialization_of<T, derived_dimensio
|
||||
* Satisfied by all dimension types for which either `BaseDimension<T>` or `DerivedDimension<T>` is `true`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Dimension = BaseDimension<T> || detail::DerivedDimension<T>;
|
||||
concept Dimension = detail::BaseDimension<T> || detail::DerivedDimension<T>;
|
||||
|
||||
} // namespace mp_units
|
||||
|
@@ -34,8 +34,20 @@ template<typename, auto...>
|
||||
#endif
|
||||
struct quantity_spec;
|
||||
|
||||
template<auto Q>
|
||||
struct kind_of_;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_kind_of = false;
|
||||
|
||||
template<auto Q>
|
||||
inline constexpr bool is_specialization_of_kind_of<kind_of_<Q>> = true;
|
||||
|
||||
template<typename T>
|
||||
concept QuantityKindSpec = is_specialization_of_kind_of<T>;
|
||||
|
||||
#ifdef __cpp_explicit_this_parameter
|
||||
template<auto... Args>
|
||||
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<Args...>*);
|
||||
@@ -70,10 +82,8 @@ inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<T, Args..
|
||||
* Satisfied by all types that derive from `quantity_spec`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_quantity_spec(t); } &&
|
||||
(!detail::is_specialization_of_quantity_spec<T>);
|
||||
|
||||
} // namespace detail
|
||||
concept NamedQuantitySpec = requires(T* t) { to_base_specialization_of_quantity_spec(t); } &&
|
||||
(!is_specialization_of_quantity_spec<T>)&&(!QuantityKindSpec<T>);
|
||||
|
||||
/**
|
||||
* @brief Concept matching all named base quantity specification types
|
||||
@@ -82,10 +92,7 @@ concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_q
|
||||
* as a template parameter.
|
||||
*/
|
||||
template<typename T>
|
||||
concept BaseQuantitySpec =
|
||||
detail::NamedQuantitySpec<T> && requires(T* t) { detail::to_base_specialization_of_base_quantity_spec(t); };
|
||||
|
||||
namespace detail {
|
||||
concept BaseQuantitySpec = NamedQuantitySpec<T> && requires(T* t) { to_base_specialization_of_base_quantity_spec(t); };
|
||||
|
||||
template<typename T>
|
||||
struct is_dimensionless : std::false_type {};
|
||||
@@ -103,15 +110,14 @@ template<typename... Ts>
|
||||
inline constexpr bool is_per_of_quantity_specs<per<Ts...>> =
|
||||
(... && (NamedQuantitySpec<Ts> || is_dimensionless<Ts>::value || is_power_of_quantity_spec<Ts>));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept IntermediateDerivedQuantitySpecExpr =
|
||||
detail::NamedQuantitySpec<T> || detail::is_dimensionless<T>::value || detail::is_power_of_quantity_spec<T> ||
|
||||
detail::is_per_of_quantity_specs<T>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<IntermediateDerivedQuantitySpecExpr... Expr>
|
||||
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
|
||||
struct derived_quantity_spec;
|
||||
|
||||
namespace detail {
|
||||
@@ -129,45 +135,9 @@ concept IntermediateDerivedQuantitySpec = is_specialization_of<T, derived_quanti
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept QuantitySpec = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_quantity_spec_with_no_specifiers = false;
|
||||
concept QuantitySpec =
|
||||
detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T> || detail::QuantityKindSpec<T>;
|
||||
|
||||
template<typename T>
|
||||
concept QuantitySpecWithNoSpecifiers = is_quantity_spec_with_no_specifiers<T>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<QuantitySpec Q>
|
||||
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q);
|
||||
|
||||
template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
||||
requires(get_kind(Q) == Q)
|
||||
struct kind_of_;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<auto Q>
|
||||
void to_base_specialization_of_kind_of(const volatile kind_of_<Q>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_kind_of =
|
||||
requires(T* t) { to_base_specialization_of_kind_of(t); };
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept QuantityKindSpec = QuantitySpec<T> && detail::is_derived_from_specialization_of_kind_of<T>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
requires QuantitySpec<T> && (!QuantityKindSpec<T>)
|
||||
inline constexpr bool is_quantity_spec_with_no_specifiers<T> = true;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mp_units
|
||||
|
@@ -50,27 +50,30 @@ namespace mp_units {
|
||||
*/
|
||||
enum class quantity_character { scalar, vector, tensor };
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename U>
|
||||
concept common_type_with_ = // exposition only
|
||||
concept CommonTypeWith =
|
||||
std::same_as<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
|
||||
std::constructible_from<std::common_type_t<T, U>, T> && std::constructible_from<std::common_type_t<T, U>, U>;
|
||||
|
||||
template<typename T, typename U = T>
|
||||
concept scalable_number_ = // exposition only
|
||||
concept ScalableNumber =
|
||||
std::regular_invocable<std::multiplies<>, T, U> && std::regular_invocable<std::divides<>, T, U>;
|
||||
|
||||
template<typename T>
|
||||
concept castable_number_ = // exposition only
|
||||
common_type_with_<T, std::intmax_t> && scalable_number_<std::common_type_t<T, std::intmax_t>>;
|
||||
concept CastableNumber = CommonTypeWith<T, std::intmax_t> && ScalableNumber<std::common_type_t<T, std::intmax_t>>;
|
||||
|
||||
// TODO Fix it according to sudo_cast implementation
|
||||
template<typename T>
|
||||
concept scalable_ = // exposition only
|
||||
castable_number_<T> || (requires { typename T::value_type; } && castable_number_<typename T::value_type> &&
|
||||
scalable_number_<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
||||
concept Scalable =
|
||||
CastableNumber<T> || (requires { typename T::value_type; } && CastableNumber<typename T::value_type> &&
|
||||
ScalableNumber<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept Representation = (is_scalar<T> || is_vector<T> || is_tensor<T>)&&std::regular<T> && scalable_<T>;
|
||||
concept Representation = (is_scalar<T> || is_vector<T> || is_tensor<T>)&&std::regular<T> && detail::Scalable<T>;
|
||||
|
||||
template<typename T, quantity_character Ch>
|
||||
concept RepresentationOf = Representation<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
||||
|
@@ -50,27 +50,42 @@ struct scaled_unit;
|
||||
template<basic_symbol_text Symbol, auto...>
|
||||
struct named_unit;
|
||||
|
||||
template<basic_symbol_text Symbol, Unit auto U>
|
||||
requires(!Symbol.empty())
|
||||
struct constant_unit;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<basic_symbol_text Symbol, auto... Args>
|
||||
void to_base_specialization_of_named_unit(const volatile named_unit<Symbol, Args...>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_named_unit =
|
||||
requires(T* t) { to_base_specialization_of_named_unit(t); };
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_named_unit = false;
|
||||
|
||||
template<basic_symbol_text Symbol, auto... Args>
|
||||
inline constexpr bool is_specialization_of_named_unit<named_unit<Symbol, Args...>> = true;
|
||||
|
||||
} // namespace detail
|
||||
template<basic_symbol_text Symbol, auto U>
|
||||
void to_base_specialization_of_constant_unit(const volatile constant_unit<Symbol, U>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_constant_unit =
|
||||
requires(T* t) { to_base_specialization_of_constant_unit(t); };
|
||||
|
||||
/**
|
||||
* @brief A concept matching all units with special names
|
||||
*
|
||||
* Satisfied by all unit types derived from the specialization of `named_unit`.
|
||||
* Satisfied by all unit types derived from the specialization of `named_unit` (but not constant units).
|
||||
*/
|
||||
template<typename T>
|
||||
concept NamedUnit = Unit<T> && requires(T* t) { detail::to_base_specialization_of_named_unit(t); } &&
|
||||
(!detail::is_specialization_of_named_unit<T>);
|
||||
concept NamedUnit = Unit<T> && detail::is_derived_from_specialization_of_named_unit<T> &&
|
||||
(!detail::is_derived_from_specialization_of_constant_unit<T>);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief Prevents assignment of a prefix to specific units
|
||||
@@ -79,14 +94,14 @@ concept NamedUnit = Unit<T> && requires(T* t) { detail::to_base_specialization_o
|
||||
* `hour` or `degree_Celsius`. For those a partial specialization with the value `false` should be
|
||||
* provided.
|
||||
*/
|
||||
template<NamedUnit auto V>
|
||||
inline constexpr bool unit_can_be_prefixed = true;
|
||||
template<Unit auto V>
|
||||
inline constexpr bool unit_can_be_prefixed = detail::NamedUnit<std::remove_const_t<decltype(V)>>;
|
||||
|
||||
/**
|
||||
* @brief A concept to be used to define prefixes for a unit
|
||||
*/
|
||||
template<typename T>
|
||||
concept PrefixableUnit = NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
||||
concept PrefixableUnit = detail::NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -100,14 +115,18 @@ inline constexpr bool is_per_of_units = false;
|
||||
template<typename... Ts>
|
||||
inline constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept DerivedUnitExpr = Unit<T> || detail::is_power_of_unit<T> || detail::is_per_of_units<T>;
|
||||
|
||||
template<DerivedUnitExpr... Expr>
|
||||
} // namespace detail
|
||||
|
||||
template<detail::DerivedUnitExpr... Expr>
|
||||
struct derived_unit;
|
||||
|
||||
template<basic_symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
|
||||
requires(!Symbol.empty())
|
||||
struct prefixed_unit;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<auto M, typename U>
|
||||
@@ -119,9 +138,28 @@ void is_unit_impl(const named_unit<Symbol, Args...>*);
|
||||
template<typename... Expr>
|
||||
void is_unit_impl(const derived_unit<Expr...>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_unit = false;
|
||||
|
||||
template<basic_symbol_text Symbol, auto... Args>
|
||||
inline constexpr bool is_specialization_of_unit<named_unit<Symbol, Args...>> = true;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_constant_unit = false;
|
||||
|
||||
template<basic_symbol_text Symbol, auto U>
|
||||
inline constexpr bool is_specialization_of_constant_unit<constant_unit<Symbol, U>> = true;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_specialization_of_prefixed_unit = false;
|
||||
|
||||
template<basic_symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
|
||||
inline constexpr bool is_specialization_of_prefixed_unit<prefixed_unit<Symbol, M, U>> = true;
|
||||
|
||||
template<typename T>
|
||||
requires requires(T* t) { is_unit_impl(t); }
|
||||
inline constexpr bool is_unit<T> = true;
|
||||
inline constexpr bool is_unit<T> = !is_specialization_of_named_unit<T> && !is_specialization_of_constant_unit<T> &&
|
||||
!is_specialization_of_prefixed_unit<T>;
|
||||
|
||||
template<Unit U>
|
||||
[[nodiscard]] consteval bool has_associated_quantity(U);
|
||||
|
@@ -114,7 +114,7 @@ using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
|
||||
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
||||
* instantiate this type automatically based on the dimensional arithmetic equation provided by the user.
|
||||
*/
|
||||
template<DerivedDimensionExpr... Expr>
|
||||
template<detail::DerivedDimensionExpr... Expr>
|
||||
struct derived_dimension : detail::expr_fractions<detail::is_dimension_one, Expr...> {};
|
||||
|
||||
/**
|
||||
@@ -179,7 +179,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
|
||||
requires detail::non_zero<Den>
|
||||
[[nodiscard]] consteval Dimension auto pow(D d)
|
||||
{
|
||||
if constexpr (BaseDimension<D>) {
|
||||
if constexpr (detail::BaseDimension<D>) {
|
||||
if constexpr (Den == 1)
|
||||
return derived_dimension<power<D, Num>>{};
|
||||
else
|
||||
|
@@ -47,16 +47,15 @@ template<QuantityLike Q>
|
||||
using quantity_like_type = quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
template<typename T, typename Arg>
|
||||
concept RepSafeConstructibleFrom = // exposition only
|
||||
concept RepSafeConstructibleFrom =
|
||||
std::constructible_from<T, Arg> && (treat_as_floating_point<T> || !treat_as_floating_point<Arg>);
|
||||
|
||||
template<auto UFrom, auto UTo>
|
||||
concept IntegralConversionFactor = // exposition only
|
||||
Unit<decltype(UFrom)> && Unit<decltype(UTo)> &&
|
||||
concept IntegralConversionFactor = Unit<decltype(UFrom)> && Unit<decltype(UTo)> &&
|
||||
is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag);
|
||||
|
||||
template<typename QFrom, typename QTo>
|
||||
concept QuantityConvertibleTo = // exposition only
|
||||
concept QuantityConvertibleTo =
|
||||
Quantity<QFrom> && Quantity<QTo> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
|
||||
convertible(QFrom::unit, QTo::unit) && requires(QFrom q) { detail::sudo_cast<QTo>(q); } &&
|
||||
(treat_as_floating_point<typename QTo::rep> ||
|
||||
|
@@ -189,15 +189,15 @@ inline constexpr struct is_kind {
|
||||
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
|
||||
*/
|
||||
#ifdef __cpp_explicit_this_parameter
|
||||
template<BaseDimension auto Dim, one_of<quantity_character> auto... Args>
|
||||
template<detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
struct quantity_spec<Dim, Args...> : detail::quantity_spec_interface {
|
||||
#else
|
||||
template<typename Self, BaseDimension auto Dim, one_of<quantity_character> auto... Args>
|
||||
template<typename Self, detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
|
||||
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||
struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self> {
|
||||
#endif
|
||||
static constexpr BaseDimension auto dimension = Dim;
|
||||
static constexpr detail::BaseDimension auto dimension = Dim;
|
||||
static constexpr quantity_character character = detail::quantity_character_init<Args...>(quantity_character::scalar);
|
||||
};
|
||||
|
||||
@@ -405,7 +405,7 @@ struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
|
||||
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
||||
* instantiate this type automatically based on the dimensional arithmetic equation provided by the user.
|
||||
*/
|
||||
template<IntermediateDerivedQuantitySpecExpr... Expr>
|
||||
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
|
||||
struct derived_quantity_spec :
|
||||
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
|
||||
detail::expr_fractions<detail::is_dimensionless, Expr...> {
|
||||
@@ -426,18 +426,31 @@ struct derived_quantity_spec :
|
||||
*/
|
||||
QUANTITY_SPEC(dimensionless, derived_quantity_spec<>{});
|
||||
|
||||
template<QuantitySpec Q>
|
||||
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q);
|
||||
|
||||
/**
|
||||
* @brief Quantity kind specifier
|
||||
*
|
||||
* Specifies that the provided `Q` should be treated as a quantity kind.
|
||||
*/
|
||||
template<auto Q>
|
||||
struct kind_of_;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
||||
requires(get_kind(Q) == Q)
|
||||
#ifdef __cpp_explicit_this_parameter
|
||||
struct kind_of_ : Q {
|
||||
struct kind_of_<Q> : Q {
|
||||
};
|
||||
#else
|
||||
struct kind_of_ : quantity_spec<kind_of_<Q>, Q> {
|
||||
struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> {
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -492,13 +505,13 @@ template<QuantitySpec Lhs, QuantitySpec Rhs>
|
||||
return is_same_v<Lhs, Rhs>;
|
||||
}
|
||||
|
||||
template<QuantityKindSpec Lhs, QuantityKindSpec Rhs>
|
||||
template<detail::QuantityKindSpec Lhs, detail::QuantityKindSpec Rhs>
|
||||
[[nodiscard]] consteval bool operator==(Lhs, Rhs)
|
||||
{
|
||||
return is_same_v<Lhs, Rhs>;
|
||||
}
|
||||
|
||||
template<QuantitySpec Lhs, QuantityKindSpec Rhs>
|
||||
template<QuantitySpec Lhs, detail::QuantityKindSpec Rhs>
|
||||
[[nodiscard]] consteval bool operator==(Lhs, Rhs rhs)
|
||||
{
|
||||
return is_same_v<Lhs, std::remove_const_t<decltype(remove_kind(rhs))>>;
|
||||
@@ -1374,7 +1387,7 @@ template<typename Self, NamedQuantitySpec auto QS, auto... Args>
|
||||
template<QuantitySpec Q>
|
||||
[[nodiscard]] consteval auto remove_kind(Q q)
|
||||
{
|
||||
if constexpr (QuantityKindSpec<Q>) {
|
||||
if constexpr (detail::QuantityKindSpec<Q>) {
|
||||
if constexpr (requires { Q::_parent_; })
|
||||
return Q::_parent_;
|
||||
else
|
||||
@@ -1393,7 +1406,7 @@ template<QuantitySpec Q>
|
||||
return false;
|
||||
};
|
||||
|
||||
if constexpr (QuantityKindSpec<Q>) {
|
||||
if constexpr (detail::QuantityKindSpec<Q>) {
|
||||
return remove_kind(q);
|
||||
} else if constexpr (defined_as_kind(q)) {
|
||||
return q;
|
||||
@@ -1424,11 +1437,11 @@ template<QuantitySpec Q1, QuantitySpec Q2>
|
||||
else if constexpr (get_kind(q1) != get_kind(q2) && std::derived_from<std::remove_const_t<decltype(get_kind(q2))>,
|
||||
std::remove_const_t<decltype(get_kind(q1))>>)
|
||||
return remove_kind(q2);
|
||||
else if constexpr ((QuantityKindSpec<Q1> && !QuantityKindSpec<Q2>) ||
|
||||
else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) ||
|
||||
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
|
||||
implicitly_convertible(q1, q2)))
|
||||
return q2;
|
||||
else if constexpr ((!QuantityKindSpec<Q1> && QuantityKindSpec<Q2>) ||
|
||||
else if constexpr ((!detail::QuantityKindSpec<Q1> && detail::QuantityKindSpec<Q2>) ||
|
||||
(detail::NamedQuantitySpec<QQ1> && detail::IntermediateDerivedQuantitySpec<QQ2> &&
|
||||
implicitly_convertible(q2, q1)))
|
||||
return q1;
|
||||
|
@@ -109,8 +109,8 @@ struct named_unit;
|
||||
* @tparam Symbol a short text representation of the unit
|
||||
* @tparam QuantitySpec a specification of a base quantity to be measured with this unit
|
||||
*/
|
||||
template<basic_symbol_text Symbol, QuantityKindSpec auto QS>
|
||||
requires(!Symbol.empty()) && BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
|
||||
template<basic_symbol_text Symbol, detail::QuantityKindSpec auto QS>
|
||||
requires(!Symbol.empty()) && detail::BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
|
||||
struct named_unit<Symbol, QS> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
||||
static constexpr auto quantity_spec = QS;
|
||||
@@ -155,7 +155,7 @@ struct named_unit<Symbol, U> : std::remove_const_t<decltype(U)> {
|
||||
* @tparam Unit a unit for which we provide a special name
|
||||
* @tparam QuantitySpec a specification of a quantity to be measured with this unit
|
||||
*/
|
||||
template<basic_symbol_text Symbol, AssociatedUnit auto U, QuantityKindSpec auto QS>
|
||||
template<basic_symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS>
|
||||
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||
struct named_unit<Symbol, U, QS> : std::remove_const_t<decltype(U)> {
|
||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||
@@ -197,17 +197,6 @@ template<basic_symbol_text Symbol, Unit auto U>
|
||||
requires(!Symbol.empty())
|
||||
struct constant_unit : named_unit<'[' + Symbol + ']', U> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<basic_symbol_text Symbol, auto U>
|
||||
void to_base_specialization_of_constant_unit(const volatile constant_unit<Symbol, U>*);
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_specialization_of_constant_unit =
|
||||
requires(T* t) { to_base_specialization_of_constant_unit(t); };
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A prefixed unit
|
||||
*
|
||||
@@ -288,7 +277,7 @@ struct is_one : std::false_type {};
|
||||
* @note User should not instantiate this type! It is not exported from the C++ module. The library will
|
||||
* instantiate this type automatically based on the unit arithmetic equation provided by the user.
|
||||
*/
|
||||
template<DerivedUnitExpr... Expr>
|
||||
template<detail::DerivedUnitExpr... Expr>
|
||||
struct derived_unit : detail::expr_fractions<detail::is_one, Expr...> {};
|
||||
|
||||
/**
|
||||
@@ -328,7 +317,7 @@ struct canonical_unit {
|
||||
U reference_unit;
|
||||
};
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, BaseQuantitySpec auto Q>
|
||||
template<Unit T, basic_symbol_text Symbol, detail::QuantityKindSpec auto Q>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q>&);
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol>
|
||||
@@ -350,7 +339,7 @@ template<Unit T, auto M, typename U>
|
||||
return canonical_unit{M * base.mag, base.reference_unit};
|
||||
}
|
||||
|
||||
template<Unit T, basic_symbol_text Symbol, BaseQuantitySpec auto Q>
|
||||
template<Unit T, basic_symbol_text Symbol, detail::QuantityKindSpec auto Q>
|
||||
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q>&)
|
||||
{
|
||||
return canonical_unit{mag<1>, t};
|
||||
|
Reference in New Issue
Block a user