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>
|
template<basic_symbol_text Symbol>
|
||||||
inline constexpr bool is_specialization_of_base_dimension<base_dimension<Symbol>> = true;
|
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.
|
* @brief A concept matching all named base dimensions in the library.
|
||||||
*
|
*
|
||||||
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
* Satisfied by all dimension types derived from a specialization of `base_dimension`.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept BaseDimension =
|
concept BaseDimension = requires(T* t) { to_base_base_dimension(t); } && (!is_specialization_of_base_dimension<T>);
|
||||||
requires(T* t) { detail::to_base_base_dimension(t); } && (!detail::is_specialization_of_base_dimension<T>);
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_dimension_one : std::false_type {};
|
struct is_dimension_one : std::false_type {};
|
||||||
@@ -71,13 +66,13 @@ template<typename... Ts>
|
|||||||
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
inline constexpr bool is_per_of_dims<per<Ts...>> =
|
||||||
(... && (BaseDimension<Ts> || is_dimension_one<Ts>::value || is_power_of_dim<Ts>));
|
(... && (BaseDimension<Ts> || is_dimension_one<Ts>::value || is_power_of_dim<Ts>));
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept DerivedDimensionExpr =
|
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;
|
struct derived_dimension;
|
||||||
|
|
||||||
namespace detail {
|
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`.
|
* Satisfied by all dimension types for which either `BaseDimension<T>` or `DerivedDimension<T>` is `true`.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Dimension = BaseDimension<T> || detail::DerivedDimension<T>;
|
concept Dimension = detail::BaseDimension<T> || detail::DerivedDimension<T>;
|
||||||
|
|
||||||
} // namespace mp_units
|
} // namespace mp_units
|
||||||
|
@@ -34,8 +34,20 @@ template<typename, auto...>
|
|||||||
#endif
|
#endif
|
||||||
struct quantity_spec;
|
struct quantity_spec;
|
||||||
|
|
||||||
|
template<auto Q>
|
||||||
|
struct kind_of_;
|
||||||
|
|
||||||
namespace detail {
|
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
|
#ifdef __cpp_explicit_this_parameter
|
||||||
template<auto... Args>
|
template<auto... Args>
|
||||||
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<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`.
|
* Satisfied by all types that derive from `quantity_spec`.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_quantity_spec(t); } &&
|
concept NamedQuantitySpec = requires(T* t) { to_base_specialization_of_quantity_spec(t); } &&
|
||||||
(!detail::is_specialization_of_quantity_spec<T>);
|
(!is_specialization_of_quantity_spec<T>)&&(!QuantityKindSpec<T>);
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Concept matching all named base quantity specification types
|
* @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.
|
* as a template parameter.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept BaseQuantitySpec =
|
concept BaseQuantitySpec = NamedQuantitySpec<T> && requires(T* t) { to_base_specialization_of_base_quantity_spec(t); };
|
||||||
detail::NamedQuantitySpec<T> && requires(T* t) { detail::to_base_specialization_of_base_quantity_spec(t); };
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_dimensionless : std::false_type {};
|
struct is_dimensionless : std::false_type {};
|
||||||
@@ -103,15 +110,14 @@ template<typename... Ts>
|
|||||||
inline constexpr bool is_per_of_quantity_specs<per<Ts...>> =
|
inline constexpr bool is_per_of_quantity_specs<per<Ts...>> =
|
||||||
(... && (NamedQuantitySpec<Ts> || is_dimensionless<Ts>::value || is_power_of_quantity_spec<Ts>));
|
(... && (NamedQuantitySpec<Ts> || is_dimensionless<Ts>::value || is_power_of_quantity_spec<Ts>));
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept IntermediateDerivedQuantitySpecExpr =
|
concept IntermediateDerivedQuantitySpecExpr =
|
||||||
detail::NamedQuantitySpec<T> || detail::is_dimensionless<T>::value || detail::is_power_of_quantity_spec<T> ||
|
detail::NamedQuantitySpec<T> || detail::is_dimensionless<T>::value || detail::is_power_of_quantity_spec<T> ||
|
||||||
detail::is_per_of_quantity_specs<T>;
|
detail::is_per_of_quantity_specs<T>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template<IntermediateDerivedQuantitySpecExpr... Expr>
|
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
|
||||||
struct derived_quantity_spec;
|
struct derived_quantity_spec;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -129,45 +135,9 @@ concept IntermediateDerivedQuantitySpec = is_specialization_of<T, derived_quanti
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
concept QuantitySpec = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
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
|
} // namespace mp_units
|
||||||
|
@@ -50,27 +50,30 @@ namespace mp_units {
|
|||||||
*/
|
*/
|
||||||
enum class quantity_character { scalar, vector, tensor };
|
enum class quantity_character { scalar, vector, tensor };
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
template<typename T, typename U>
|
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::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>;
|
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>
|
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>;
|
std::regular_invocable<std::multiplies<>, T, U> && std::regular_invocable<std::divides<>, T, U>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept castable_number_ = // exposition only
|
concept CastableNumber = CommonTypeWith<T, std::intmax_t> && ScalableNumber<std::common_type_t<T, std::intmax_t>>;
|
||||||
common_type_with_<T, std::intmax_t> && scalable_number_<std::common_type_t<T, std::intmax_t>>;
|
|
||||||
|
|
||||||
// TODO Fix it according to sudo_cast implementation
|
// TODO Fix it according to sudo_cast implementation
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept scalable_ = // exposition only
|
concept Scalable =
|
||||||
castable_number_<T> || (requires { typename T::value_type; } && castable_number_<typename T::value_type> &&
|
CastableNumber<T> || (requires { typename T::value_type; } && CastableNumber<typename T::value_type> &&
|
||||||
scalable_number_<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
ScalableNumber<T, std::common_type_t<typename T::value_type, std::intmax_t>>);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template<typename T>
|
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>
|
template<typename T, quantity_character Ch>
|
||||||
concept RepresentationOf = Representation<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
concept RepresentationOf = Representation<T> && ((Ch == quantity_character::scalar && is_scalar<T>) ||
|
||||||
|
@@ -50,27 +50,42 @@ struct scaled_unit;
|
|||||||
template<basic_symbol_text Symbol, auto...>
|
template<basic_symbol_text Symbol, auto...>
|
||||||
struct named_unit;
|
struct named_unit;
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, Unit auto U>
|
||||||
|
requires(!Symbol.empty())
|
||||||
|
struct constant_unit;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<basic_symbol_text Symbol, auto... Args>
|
template<basic_symbol_text Symbol, auto... Args>
|
||||||
void to_base_specialization_of_named_unit(const volatile named_unit<Symbol, 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>
|
template<typename T>
|
||||||
inline constexpr bool is_specialization_of_named_unit = false;
|
inline constexpr bool is_specialization_of_named_unit = false;
|
||||||
|
|
||||||
template<basic_symbol_text Symbol, auto... Args>
|
template<basic_symbol_text Symbol, auto... Args>
|
||||||
inline constexpr bool is_specialization_of_named_unit<named_unit<Symbol, Args...>> = true;
|
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
|
* @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>
|
template<typename T>
|
||||||
concept NamedUnit = Unit<T> && requires(T* t) { detail::to_base_specialization_of_named_unit(t); } &&
|
concept NamedUnit = Unit<T> && detail::is_derived_from_specialization_of_named_unit<T> &&
|
||||||
(!detail::is_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
|
* @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
|
* `hour` or `degree_Celsius`. For those a partial specialization with the value `false` should be
|
||||||
* provided.
|
* provided.
|
||||||
*/
|
*/
|
||||||
template<NamedUnit auto V>
|
template<Unit auto V>
|
||||||
inline constexpr bool unit_can_be_prefixed = true;
|
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
|
* @brief A concept to be used to define prefixes for a unit
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept PrefixableUnit = NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
concept PrefixableUnit = detail::NamedUnit<T> && unit_can_be_prefixed<T{}>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
@@ -100,14 +115,18 @@ inline constexpr bool is_per_of_units = false;
|
|||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
inline constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
inline constexpr bool is_per_of_units<per<Ts...>> = (... && (Unit<Ts> || is_power_of_unit<Ts>));
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept DerivedUnitExpr = Unit<T> || detail::is_power_of_unit<T> || detail::is_per_of_units<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;
|
struct derived_unit;
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
|
||||||
|
requires(!Symbol.empty())
|
||||||
|
struct prefixed_unit;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<auto M, typename U>
|
template<auto M, typename U>
|
||||||
@@ -119,9 +138,28 @@ void is_unit_impl(const named_unit<Symbol, Args...>*);
|
|||||||
template<typename... Expr>
|
template<typename... Expr>
|
||||||
void is_unit_impl(const derived_unit<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>
|
template<typename T>
|
||||||
requires requires(T* t) { is_unit_impl(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>
|
template<Unit U>
|
||||||
[[nodiscard]] consteval bool has_associated_quantity(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
|
* @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.
|
* 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...> {};
|
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>
|
requires detail::non_zero<Den>
|
||||||
[[nodiscard]] consteval Dimension auto pow(D d)
|
[[nodiscard]] consteval Dimension auto pow(D d)
|
||||||
{
|
{
|
||||||
if constexpr (BaseDimension<D>) {
|
if constexpr (detail::BaseDimension<D>) {
|
||||||
if constexpr (Den == 1)
|
if constexpr (Den == 1)
|
||||||
return derived_dimension<power<D, Num>>{};
|
return derived_dimension<power<D, Num>>{};
|
||||||
else
|
else
|
||||||
|
@@ -47,16 +47,15 @@ template<QuantityLike Q>
|
|||||||
using quantity_like_type = quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
using quantity_like_type = quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
|
||||||
|
|
||||||
template<typename T, typename Arg>
|
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>);
|
std::constructible_from<T, Arg> && (treat_as_floating_point<T> || !treat_as_floating_point<Arg>);
|
||||||
|
|
||||||
template<auto UFrom, auto UTo>
|
template<auto UFrom, auto UTo>
|
||||||
concept IntegralConversionFactor = // exposition only
|
concept IntegralConversionFactor = Unit<decltype(UFrom)> && Unit<decltype(UTo)> &&
|
||||||
Unit<decltype(UFrom)> && Unit<decltype(UTo)> &&
|
is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag);
|
||||||
is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag);
|
|
||||||
|
|
||||||
template<typename QFrom, typename QTo>
|
template<typename QFrom, typename QTo>
|
||||||
concept QuantityConvertibleTo = // exposition only
|
concept QuantityConvertibleTo =
|
||||||
Quantity<QFrom> && Quantity<QTo> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
|
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); } &&
|
convertible(QFrom::unit, QTo::unit) && requires(QFrom q) { detail::sudo_cast<QTo>(q); } &&
|
||||||
(treat_as_floating_point<typename QTo::rep> ||
|
(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
|
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
|
||||||
*/
|
*/
|
||||||
#ifdef __cpp_explicit_this_parameter
|
#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)>>)
|
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||||
struct quantity_spec<Dim, Args...> : detail::quantity_spec_interface {
|
struct quantity_spec<Dim, Args...> : detail::quantity_spec_interface {
|
||||||
#else
|
#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)>>)
|
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
|
||||||
struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self> {
|
struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self> {
|
||||||
#endif
|
#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);
|
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
|
* @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.
|
* 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 :
|
struct derived_quantity_spec :
|
||||||
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
|
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
|
||||||
detail::expr_fractions<detail::is_dimensionless, Expr...> {
|
detail::expr_fractions<detail::is_dimensionless, Expr...> {
|
||||||
@@ -426,18 +426,31 @@ struct derived_quantity_spec :
|
|||||||
*/
|
*/
|
||||||
QUANTITY_SPEC(dimensionless, derived_quantity_spec<>{});
|
QUANTITY_SPEC(dimensionless, derived_quantity_spec<>{});
|
||||||
|
|
||||||
|
template<QuantitySpec Q>
|
||||||
|
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Quantity kind specifier
|
* @brief Quantity kind specifier
|
||||||
*
|
*
|
||||||
* Specifies that the provided `Q` should be treated as a quantity kind.
|
* 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>
|
template<detail::QuantitySpecWithNoSpecifiers auto Q>
|
||||||
requires(get_kind(Q) == Q)
|
requires(get_kind(Q) == Q)
|
||||||
#ifdef __cpp_explicit_this_parameter
|
#ifdef __cpp_explicit_this_parameter
|
||||||
struct kind_of_ : Q {
|
struct kind_of_<Q> : Q {
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
struct kind_of_ : quantity_spec<kind_of_<Q>, Q> {
|
struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -492,13 +505,13 @@ template<QuantitySpec Lhs, QuantitySpec Rhs>
|
|||||||
return is_same_v<Lhs, 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)
|
[[nodiscard]] consteval bool operator==(Lhs, Rhs)
|
||||||
{
|
{
|
||||||
return is_same_v<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)
|
[[nodiscard]] consteval bool operator==(Lhs, Rhs rhs)
|
||||||
{
|
{
|
||||||
return is_same_v<Lhs, std::remove_const_t<decltype(remove_kind(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>
|
template<QuantitySpec Q>
|
||||||
[[nodiscard]] consteval auto remove_kind(Q q)
|
[[nodiscard]] consteval auto remove_kind(Q q)
|
||||||
{
|
{
|
||||||
if constexpr (QuantityKindSpec<Q>) {
|
if constexpr (detail::QuantityKindSpec<Q>) {
|
||||||
if constexpr (requires { Q::_parent_; })
|
if constexpr (requires { Q::_parent_; })
|
||||||
return Q::_parent_;
|
return Q::_parent_;
|
||||||
else
|
else
|
||||||
@@ -1393,7 +1406,7 @@ template<QuantitySpec Q>
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if constexpr (QuantityKindSpec<Q>) {
|
if constexpr (detail::QuantityKindSpec<Q>) {
|
||||||
return remove_kind(q);
|
return remove_kind(q);
|
||||||
} else if constexpr (defined_as_kind(q)) {
|
} else if constexpr (defined_as_kind(q)) {
|
||||||
return 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))>,
|
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))>>)
|
std::remove_const_t<decltype(get_kind(q1))>>)
|
||||||
return remove_kind(q2);
|
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> &&
|
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
|
||||||
implicitly_convertible(q1, q2)))
|
implicitly_convertible(q1, q2)))
|
||||||
return 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> &&
|
(detail::NamedQuantitySpec<QQ1> && detail::IntermediateDerivedQuantitySpec<QQ2> &&
|
||||||
implicitly_convertible(q2, q1)))
|
implicitly_convertible(q2, q1)))
|
||||||
return q1;
|
return q1;
|
||||||
|
@@ -109,8 +109,8 @@ struct named_unit;
|
|||||||
* @tparam Symbol a short text representation of the unit
|
* @tparam Symbol a short text representation of the unit
|
||||||
* @tparam QuantitySpec a specification of a base quantity to be measured with this unit
|
* @tparam QuantitySpec a specification of a base quantity to be measured with this unit
|
||||||
*/
|
*/
|
||||||
template<basic_symbol_text Symbol, QuantityKindSpec auto QS>
|
template<basic_symbol_text Symbol, detail::QuantityKindSpec auto QS>
|
||||||
requires(!Symbol.empty()) && BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
|
requires(!Symbol.empty()) && detail::BaseDimension<std::remove_const_t<decltype(QS.dimension)>>
|
||||||
struct named_unit<Symbol, QS> {
|
struct named_unit<Symbol, QS> {
|
||||||
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
static constexpr auto symbol = Symbol; ///< Unique base unit identifier
|
||||||
static constexpr auto quantity_spec = QS;
|
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 Unit a unit for which we provide a special name
|
||||||
* @tparam QuantitySpec a specification of a quantity to be measured with this unit
|
* @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)
|
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
|
||||||
struct named_unit<Symbol, U, QS> : std::remove_const_t<decltype(U)> {
|
struct named_unit<Symbol, U, QS> : std::remove_const_t<decltype(U)> {
|
||||||
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
static constexpr auto symbol = Symbol; ///< Unique unit identifier
|
||||||
@@ -197,17 +197,6 @@ template<basic_symbol_text Symbol, Unit auto U>
|
|||||||
requires(!Symbol.empty())
|
requires(!Symbol.empty())
|
||||||
struct constant_unit : named_unit<'[' + Symbol + ']', U> {};
|
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
|
* @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
|
* @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.
|
* 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...> {};
|
struct derived_unit : detail::expr_fractions<detail::is_one, Expr...> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -328,7 +317,7 @@ struct canonical_unit {
|
|||||||
U reference_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>&);
|
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q>&);
|
||||||
|
|
||||||
template<Unit T, basic_symbol_text Symbol>
|
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};
|
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>&)
|
[[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit<Symbol, Q>&)
|
||||||
{
|
{
|
||||||
return canonical_unit{mag<1>, t};
|
return canonical_unit{mag<1>, t};
|
||||||
|
Reference in New Issue
Block a user