mirror of
https://github.com/mpusz/mp-units.git
synced 2025-06-25 01:01:33 +02:00
feat: quantity_spec
conversions improved
This commit is contained in:
@ -52,24 +52,6 @@ All of the above quantity specifications have to be marked as `final`.
|
||||
`QuantitySpecOf` concept is satisfied when both arguments satisfy a [`QuantitySpec`](#QuantitySpec) concept
|
||||
and when `T` is implicitly convertible to `V`.
|
||||
|
||||
??? info "More details"
|
||||
|
||||
Additionally:
|
||||
|
||||
- `T` should not be a [nested quantity specification of `V`](dimensionless_quantities.md/#nested-quantity-kinds)
|
||||
- either `T` is quantity kind or `V` should not be a
|
||||
[nested quantity specification of `T`](dimensionless_quantities.md/#nested-quantity-kinds)
|
||||
|
||||
Those additional conditions are required to make the following work:
|
||||
|
||||
```cpp
|
||||
static_assert(ReferenceOf<si::radian, isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<si::radian, dimensionless>);
|
||||
static_assert(!ReferenceOf<isq::angular_measure[si::radian], dimensionless>);
|
||||
static_assert(ReferenceOf<one, isq::angular_measure>);
|
||||
static_assert(!ReferenceOf<dimensionless[one], isq::angular_measure>);
|
||||
```
|
||||
|
||||
|
||||
## `Unit<T>` { #Unit }
|
||||
|
||||
@ -123,17 +105,8 @@ Such units can be passed as an argument to a `prefixed_unit` class template.
|
||||
|
||||
### `UnitOf<T, V>` { #UnitOf }
|
||||
|
||||
`UnitOf` concept is satisfied for all units `T` matching an [`AssociatedUnit`](#AssociatedUnit)
|
||||
concept with an associated quantity type implicitly convertible to `V`.
|
||||
|
||||
??? info "More details"
|
||||
|
||||
Additionally, the kind of `V` and the kind of quantity type associated with `T` must be the same,
|
||||
or the quantity type associated with `T` may not be derived from the kind of `V`.
|
||||
|
||||
This condition is required to make `dimensionless[si::radian]` invalid as `si::radian` should
|
||||
be only used for `isq::angular_measure`, which is a
|
||||
[nested quantity kind within the dimensionless quantities tree](dimensionless_quantities.md/#nested-quantity-kinds).
|
||||
`UnitOf` concept is satisfied for all units `T` for which an associated quantity spec is implicitly
|
||||
convertible to the provided [`QuantitySpec`](#QuantitySpec) value.
|
||||
|
||||
|
||||
## `Reference<T>` { #Reference }
|
||||
@ -150,7 +123,7 @@ A `Reference` can either be:
|
||||
### `ReferenceOf<T, V>` { #ReferenceOf }
|
||||
|
||||
`ReferenceOf` concept is satisfied by references `T` which have a quantity specification that satisfies
|
||||
[`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
||||
[`QuantitySpecOf<V>`](#QuantitySpecOf) concept.
|
||||
|
||||
|
||||
## `Representation<T>` { #Representation }
|
||||
@ -205,7 +178,7 @@ satisfied by all types being or deriving from an instantiation of a `quantity` c
|
||||
|
||||
### `QuantityOf<T, V>` { #QuantityOf }
|
||||
|
||||
`QuantityOf` concept is satisfied by all the quantities for which a [`QuantitySpecOf<V>`](#QuantitySpecOf)
|
||||
`QuantityOf` concept is satisfied by all the quantities for which a [`ReferenceOf<V>`](#ReferenceOf)
|
||||
is `true`.
|
||||
|
||||
|
||||
@ -252,10 +225,10 @@ class template.
|
||||
|
||||
`QuantityPointOf` concept is satisfied by all the quantity points `T` that match the following value `V`:
|
||||
|
||||
| `V` | Condition |
|
||||
|----------------|-----------------------------------------------------------------------------------------------------|
|
||||
| `QuantitySpec` | The quantity point quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
|
||||
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
|
||||
| `V` | Condition |
|
||||
|----------------|-----------------------------------------------------------------------------------------------|
|
||||
| `QuantitySpec` | The quantity point quantity specification satisfies [`ReferenceOf<V>`](#ReferenceOf) concept. |
|
||||
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
|
||||
|
||||
|
||||
## `QuantityLike<T>` { #QuantityLike }
|
||||
|
@ -311,3 +311,24 @@ inline constexpr struct bit final : named_unit<"bit", one, kind_of<storage_capac
|
||||
```
|
||||
|
||||
but still allow the usage of `one` and its scaled versions for such quantities.
|
||||
|
||||
!!! info
|
||||
|
||||
It is worth mentioning here that converting up the hierarchy beyond a subkind requires an
|
||||
explicit conversion. For example:
|
||||
|
||||
```cpp
|
||||
static_assert(implicitly_convertible(isq::rotation, dimensionless));
|
||||
static_assert(!implicitly_convertible(isq::angular_measure, dimensionless));
|
||||
static_assert(explicitly_convertible(isq::angular_measure, dimensionless));
|
||||
```
|
||||
|
||||
This increases type safety and prevents accidental quantities with invalid units. For example,
|
||||
a result of a conversion from `isq::angular_measure[rad]` to `dimensionless` would be
|
||||
a reference of `dimensionless[rad]`, which contains an incorrect unit for a `dimensionless`
|
||||
quantity. Such a conversion must be explicit and be preceded by an explicit unit conversion:
|
||||
|
||||
```cpp
|
||||
quantity q1 = isq::angular_measure(42. * rad);
|
||||
quantity<dimensionless[one]> q2 = dimensionless(q1.in(one));
|
||||
```
|
||||
|
@ -193,14 +193,14 @@ distance spherical_distance(position<T> from, position<T> to)
|
||||
// const auto central_angle = 2 * asin(sqrt(0.5 - cos(to_lat - from_lat) / 2 + cos(from_lat) * cos(to_lat) * (1
|
||||
// - cos(lon2_rad - from_lon)) / 2));
|
||||
|
||||
return quantity_cast<isq::distance>(earth_radius * central_angle);
|
||||
return quantity_cast<isq::distance>((earth_radius * central_angle).in(earth_radius.unit));
|
||||
} else {
|
||||
// the haversine formula
|
||||
const quantity sin_lat = sin((to_lat - from_lat) / 2);
|
||||
const quantity sin_lon = sin((to_lon - from_lon) / 2);
|
||||
const quantity central_angle = 2 * asin(sqrt(sin_lat * sin_lat + cos(from_lat) * cos(to_lat) * sin_lon * sin_lon));
|
||||
|
||||
return quantity_cast<isq::distance>(earth_radius * central_angle);
|
||||
return quantity_cast<isq::distance>((earth_radius * central_angle).in(earth_radius.unit));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,12 +58,16 @@ template<QuantitySpec A, QuantitySpec B>
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
[[nodiscard]] consteval bool have_common_base(A a, B b)
|
||||
{
|
||||
constexpr std::size_t a_length = hierarchy_path_length(A{});
|
||||
constexpr std::size_t b_length = hierarchy_path_length(B{});
|
||||
if constexpr (a_length > b_length)
|
||||
return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b);
|
||||
else
|
||||
return have_common_base_in_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b));
|
||||
if constexpr (is_same_v<A, B>)
|
||||
return true;
|
||||
else {
|
||||
constexpr std::size_t a_length = hierarchy_path_length(A{});
|
||||
constexpr std::size_t b_length = hierarchy_path_length(B{});
|
||||
if constexpr (a_length > b_length)
|
||||
return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b);
|
||||
else
|
||||
return have_common_base_in_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b));
|
||||
}
|
||||
}
|
||||
|
||||
template<QuantitySpec A, QuantitySpec B>
|
||||
@ -91,16 +95,20 @@ template<QuantitySpec A, QuantitySpec B>
|
||||
template<QuantitySpec Child, QuantitySpec Parent>
|
||||
[[nodiscard]] consteval bool is_child_of(Child ch, Parent p)
|
||||
{
|
||||
if constexpr (Child{} == Parent{})
|
||||
return std::true_type{};
|
||||
else {
|
||||
constexpr std::size_t child_length = hierarchy_path_length(Child{});
|
||||
constexpr std::size_t parent_length = hierarchy_path_length(Parent{});
|
||||
if constexpr (parent_length > child_length)
|
||||
return false;
|
||||
else
|
||||
return hierarchy_path_advance<child_length - parent_length>(ch) == p;
|
||||
}
|
||||
constexpr std::size_t child_length = hierarchy_path_length(Child{});
|
||||
constexpr std::size_t parent_length = hierarchy_path_length(Parent{});
|
||||
if constexpr (parent_length >= child_length)
|
||||
return false;
|
||||
else
|
||||
return hierarchy_path_advance<child_length - parent_length>(ch) == p;
|
||||
}
|
||||
|
||||
[[nodiscard]] consteval QuantitySpec auto get_hierarchy_root(QuantitySpec auto q)
|
||||
{
|
||||
if constexpr (requires { q._parent_; })
|
||||
return get_hierarchy_root(q._parent_);
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
} // namespace mp_units::detail
|
||||
|
@ -172,6 +172,22 @@ struct type_list_split_half;
|
||||
template<template<typename...> typename List, typename... Types>
|
||||
struct type_list_split_half<List<Types...>> : type_list_split<List<Types...>, (sizeof...(Types) + 1) / 2> {};
|
||||
|
||||
// extract
|
||||
template<TypeList, TypeList>
|
||||
struct type_list_extract_impl;
|
||||
|
||||
template<template<typename...> typename List, typename... Pre, typename Element, typename... Post>
|
||||
struct type_list_extract_impl<List<Pre...>, List<Element, Post...>> {
|
||||
using element = Element;
|
||||
using rest = List<Pre..., Post...>;
|
||||
};
|
||||
|
||||
template<TypeList List, std::size_t N>
|
||||
requires(N >= 0) && (type_list_size<List> > N)
|
||||
struct type_list_extract :
|
||||
type_list_extract_impl<typename type_list_split<List, N>::first_list,
|
||||
typename type_list_split<List, N>::second_list> {};
|
||||
|
||||
// merge_sorted
|
||||
template<typename SortedList1, typename SortedList2, template<typename, typename> typename Pred>
|
||||
struct type_list_merge_sorted_impl;
|
||||
|
@ -76,35 +76,26 @@ struct power_v {
|
||||
static constexpr ratio exponent{Num, Den...};
|
||||
};
|
||||
|
||||
template<typename Element>
|
||||
[[nodiscard]] consteval auto get_base(Element element)
|
||||
template<typename T>
|
||||
[[nodiscard]] consteval auto get_base(T element)
|
||||
{
|
||||
if constexpr (is_specialization_of_v<Element, power_v>)
|
||||
return Element::base;
|
||||
if constexpr (is_specialization_of_v<T, power_v>)
|
||||
return T::base;
|
||||
else
|
||||
return element;
|
||||
}
|
||||
|
||||
template<typename Element>
|
||||
[[nodiscard]] consteval auto get_base_value(Element element)
|
||||
template<typename T>
|
||||
[[nodiscard]] consteval auto get_base_value(T element)
|
||||
{
|
||||
if constexpr (is_specialization_of_v<Element, power_v>)
|
||||
return get_base_value(Element::base);
|
||||
else if constexpr (MagConstant<Element>)
|
||||
if constexpr (is_specialization_of_v<T, power_v>)
|
||||
return get_base_value(T::base);
|
||||
else if constexpr (MagConstant<T>)
|
||||
return element._value_;
|
||||
else
|
||||
return element;
|
||||
}
|
||||
|
||||
template<typename Element>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL ratio get_exponent(Element)
|
||||
{
|
||||
if constexpr (is_specialization_of_v<Element, power_v>)
|
||||
return Element::exponent;
|
||||
else
|
||||
return ratio{1};
|
||||
}
|
||||
|
||||
template<auto V, ratio R>
|
||||
[[nodiscard]] consteval auto power_v_or_T()
|
||||
{
|
||||
|
@ -71,8 +71,8 @@ concept ValuePreservingTo = Representation<std::remove_cvref_t<FromRep>> && Repr
|
||||
|
||||
template<typename QFrom, typename QTo>
|
||||
concept QuantityConvertibleTo =
|
||||
Quantity<QFrom> && Quantity<QTo> && QuantitySpecConvertibleTo<QFrom::quantity_spec, QTo::quantity_spec> &&
|
||||
UnitConvertibleTo<QFrom::unit, QTo::unit> &&
|
||||
Quantity<QFrom> && Quantity<QTo> && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) &&
|
||||
(interconvertible(QFrom::unit, QTo::unit)) &&
|
||||
ValuePreservingTo<typename QFrom::rep, typename QTo::rep, QFrom::unit, QTo::unit> &&
|
||||
// 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)
|
||||
@ -641,6 +641,10 @@ MP_UNITS_EXPORT_END
|
||||
|
||||
} // namespace mp_units
|
||||
|
||||
// This specialization overrides `std` defaults for quantities
|
||||
template<mp_units::Quantity Q1, mp_units::Quantity Q2>
|
||||
struct std::common_type<Q1, Q2> {};
|
||||
|
||||
template<mp_units::Quantity Q1, mp_units::Quantity Q2>
|
||||
requires requires {
|
||||
{ mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference;
|
||||
|
@ -57,7 +57,7 @@ namespace mp_units {
|
||||
* @tparam ToQS a quantity specification to use for a target quantity
|
||||
*/
|
||||
template<QuantitySpec auto ToQS, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires detail::QuantitySpecCastableTo<Q::quantity_spec, ToQS>
|
||||
requires(castable(Q::quantity_spec, ToQS)) && detail::WeakUnitOf<MP_UNITS_NONCONST_TYPE(Q::unit), ToQS>
|
||||
[[nodiscard]] constexpr Quantity auto quantity_cast(FwdQ&& q)
|
||||
{
|
||||
return quantity{std::forward<FwdQ>(q).numerical_value_is_an_implementation_detail_, make_reference(ToQS, Q::unit)};
|
||||
@ -81,7 +81,7 @@ template<QuantitySpec auto ToQS, typename FwdQ, Quantity Q = std::remove_cvref_t
|
||||
* @tparam ToQS a quantity specification to use for a target quantity point
|
||||
*/
|
||||
template<QuantitySpec auto ToQS, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires detail::QuantitySpecCastableTo<QP::quantity_spec, ToQS>
|
||||
requires(castable(QP::quantity_spec, ToQS)) && detail::WeakUnitOf<MP_UNITS_NONCONST_TYPE(QP::unit), ToQS>
|
||||
[[nodiscard]] constexpr QuantityPoint auto quantity_cast(FwdQP&& qp)
|
||||
{
|
||||
return QP{quantity_cast<ToQS>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
|
@ -72,13 +72,13 @@ concept QuantityLikeImpl = requires(const T& qty, const Traits<T>::rep& num) {
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantities with provided quantity spec
|
||||
* @brief A concept matching all quantities of the provided quantity spec
|
||||
*
|
||||
* Satisfied by all quantities with a quantity_spec being the instantiation derived from
|
||||
* the provided quantity_spec type.
|
||||
* Satisfied by all quantities with the reference satisfying @c ReferenceOf<QS>.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename Q, auto QS>
|
||||
concept QuantityOf = Quantity<Q> && QuantitySpecOf<MP_UNITS_NONCONST_TYPE(Q::quantity_spec), QS>;
|
||||
concept QuantityOf = Quantity<Q> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
ReferenceOf<MP_UNITS_NONCONST_TYPE(Q::reference), QS>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all external quantities like types
|
||||
|
@ -117,7 +117,7 @@ concept SameAbsolutePointOriginAs =
|
||||
|
||||
|
||||
/**
|
||||
* @brief A concept matching all quantity points with provided quantity spec
|
||||
* @brief A concept matching all quantity points of the provided property
|
||||
*
|
||||
* Satisfied by all quantity points with a quantity_spec being the instantiation derived from
|
||||
* the provided quantity_spec type, or quantity points having the origin with the same
|
||||
@ -125,7 +125,7 @@ concept SameAbsolutePointOriginAs =
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename QP, auto V>
|
||||
concept QuantityPointOf =
|
||||
QuantityPoint<QP> && (QuantitySpecOf<MP_UNITS_NONCONST_TYPE(QP::quantity_spec), V> ||
|
||||
QuantityPoint<QP> && (ReferenceOf<MP_UNITS_NONCONST_TYPE(QP::reference), V> ||
|
||||
detail::SameAbsolutePointOriginAs<MP_UNITS_NONCONST_TYPE(QP::absolute_point_origin), V>);
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,6 @@
|
||||
// IWYU pragma: private, include <mp-units/framework.h>
|
||||
#include <mp-units/bits/hacks.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/framework/dimension_concepts.h>
|
||||
#include <mp-units/framework/symbolic_expression.h>
|
||||
|
||||
namespace mp_units {
|
||||
@ -39,14 +38,6 @@ struct quantity_spec_interface_base;
|
||||
MP_UNITS_EXPORT template<typename T>
|
||||
concept QuantitySpec = detail::SymbolicConstant<T> && std::derived_from<T, detail::quantity_spec_interface_base>;
|
||||
|
||||
MP_UNITS_EXPORT
|
||||
#if MP_UNITS_API_NO_CRTP
|
||||
template<auto...>
|
||||
#else
|
||||
template<typename, auto...>
|
||||
#endif
|
||||
struct quantity_spec;
|
||||
|
||||
template<typename Q>
|
||||
struct kind_of_;
|
||||
|
||||
@ -55,93 +46,19 @@ namespace detail {
|
||||
template<typename T>
|
||||
concept QuantityKindSpec = QuantitySpec<T> && is_specialization_of<T, kind_of_>;
|
||||
|
||||
#if MP_UNITS_API_NO_CRTP
|
||||
template<auto... Args>
|
||||
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<Args...>*);
|
||||
#else
|
||||
template<typename T, auto... Args>
|
||||
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<T, Args...>*);
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_derived_from_specialization_of_quantity_spec =
|
||||
requires(T* type) { to_base_specialization_of_quantity_spec(type); };
|
||||
MP_UNITS_EXPORT template<QuantitySpec From, QuantitySpec To>
|
||||
[[nodiscard]] consteval bool implicitly_convertible(From from, To to);
|
||||
|
||||
/**
|
||||
* @brief Concept matching all named quantity specification types
|
||||
* @brief A concept matching all quantity specifications of a provided quantity spec value
|
||||
*
|
||||
* Satisfied by all types that derive from `quantity_spec`.
|
||||
* Satisfied by all quantity specifications that are implicitly convertible to the provided @c QS
|
||||
* value.
|
||||
*/
|
||||
template<typename T>
|
||||
concept NamedQuantitySpec =
|
||||
QuantitySpec<T> && is_derived_from_specialization_of_quantity_spec<T> && (!QuantityKindSpec<T>);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<detail::SymbolicConstant... Expr>
|
||||
struct derived_quantity_spec;
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* @brief Concept matching all derived quantity specification types
|
||||
*
|
||||
* Satisfied by all `derived_quantity_spec` specializations.
|
||||
*
|
||||
* @note Deriving a strong type from it is considered a logic error and thus is
|
||||
* explicitly not supported here.
|
||||
*/
|
||||
template<typename T>
|
||||
concept DerivedQuantitySpec =
|
||||
QuantitySpec<T> &&
|
||||
(is_specialization_of<T, derived_quantity_spec> ||
|
||||
(QuantityKindSpec<T> && is_specialization_of<MP_UNITS_NONCONST_TYPE(T::_quantity_spec_), derived_quantity_spec>));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
MP_UNITS_EXPORT template<QuantitySpec Q>
|
||||
[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<QuantitySpec Child, QuantitySpec Parent>
|
||||
[[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>
|
||||
concept NestedQuantityKindSpecOf =
|
||||
QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(From))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(To))> &&
|
||||
(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
|
||||
|
||||
MP_UNITS_EXPORT template<typename T, auto QS>
|
||||
concept QuantitySpecOf =
|
||||
QuantitySpec<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && detail::QuantitySpecConvertibleTo<T{}, QS> &&
|
||||
// the below is to make the following work
|
||||
// static_assert(ReferenceOf<si::radian, isq::angular_measure>);
|
||||
// static_assert(!ReferenceOf<si::radian, dimensionless>);
|
||||
// static_assert(!ReferenceOf<isq::angular_measure[si::radian], dimensionless>
|
||||
// static_assert(ReferenceOf<one, isq::angular_measure>);
|
||||
// static_assert(!ReferenceOf<dimensionless[one], isq::angular_measure>);
|
||||
!detail::NestedQuantityKindSpecOf<T{}, QS> &&
|
||||
(detail::QuantityKindSpec<T> || !detail::NestedQuantityKindSpecOf<QS, T{}>);
|
||||
QuantitySpec<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && (mp_units::implicitly_convertible(T{}, QS));
|
||||
|
||||
} // namespace mp_units
|
||||
|
@ -187,24 +187,6 @@ struct reference {
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename Q2, typename U2>
|
||||
[[nodiscard]] friend consteval bool convertible(reference, reference<Q2, U2>)
|
||||
{
|
||||
return implicitly_convertible(Q{}, Q2{}) && convertible(U{}, U2{});
|
||||
}
|
||||
|
||||
template<AssociatedUnit U2>
|
||||
[[nodiscard]] friend consteval bool convertible(reference, U2 u2)
|
||||
{
|
||||
return implicitly_convertible(Q{}, get_quantity_spec(u2)) && convertible(U{}, u2);
|
||||
}
|
||||
|
||||
template<AssociatedUnit U1>
|
||||
[[nodiscard]] friend consteval bool convertible(U1 u1, reference)
|
||||
{
|
||||
return implicitly_convertible(get_quantity_spec(u1), Q{}) && convertible(u1, U{});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -60,13 +60,13 @@ template<typename T>
|
||||
concept Reference = AssociatedUnit<T> || is_specialization_of<T, reference>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching all references with provided quantity spec
|
||||
* @brief A concept matching all references of the provided quantity spec
|
||||
*
|
||||
* Satisfied by all references with a quantity_spec being the instantiation derived from
|
||||
* the provided quantity_spec type.
|
||||
* Satisfied by all references for which @c QuantitySpecOf<QS> is true.
|
||||
*/
|
||||
template<typename T, auto QS>
|
||||
concept ReferenceOf = Reference<T> && QuantitySpecOf<decltype(get_quantity_spec(T{})), QS>;
|
||||
concept ReferenceOf = Reference<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
QuantitySpecOf<decltype(get_quantity_spec(T{})), QS>;
|
||||
|
||||
MP_UNITS_EXPORT_END
|
||||
|
||||
|
@ -143,8 +143,29 @@ constexpr bool is_specialization_of_power = false;
|
||||
template<typename F, int... Ints>
|
||||
constexpr bool is_specialization_of_power<power<F, Ints...>> = true;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] consteval auto get_factor(T element)
|
||||
{
|
||||
if constexpr (is_specialization_of_power<T>)
|
||||
return typename T::_factor_{};
|
||||
else
|
||||
return element;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] MP_UNITS_CONSTEVAL ratio get_exponent(T)
|
||||
{
|
||||
// this covers both `power` and `power_v`
|
||||
if constexpr (requires { T::_exponent_; })
|
||||
return T::_exponent_;
|
||||
else if constexpr (requires { T::exponent; })
|
||||
return T::exponent;
|
||||
else
|
||||
return ratio{1};
|
||||
};
|
||||
|
||||
template<SymbolicArg T, ratio R>
|
||||
consteval auto power_or_T_impl()
|
||||
[[nodiscard]] consteval auto power_or_T_impl()
|
||||
{
|
||||
if constexpr (is_specialization_of_power<T>) {
|
||||
return power_or_T_impl<typename T::_factor_, T::_exponent_ * R>();
|
||||
|
@ -66,7 +66,7 @@ struct system_reference {
|
||||
static constexpr auto coherent_unit = CoU;
|
||||
|
||||
template<Unit U>
|
||||
requires detail::UnitConvertibleTo<coherent_unit, U{}>
|
||||
requires(interconvertible(coherent_unit, U{}))
|
||||
#if MP_UNITS_COMP_MSVC
|
||||
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
|
||||
#else
|
||||
|
@ -126,30 +126,34 @@ constexpr auto get_canonical_unit_result = get_canonical_unit_impl(U{}, U{});
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename From, typename To>
|
||||
concept PotentiallyConvertibleTo = Unit<From> && Unit<To> &&
|
||||
((AssociatedUnit<From> && AssociatedUnit<To> &&
|
||||
implicitly_convertible(get_quantity_spec(From{}), get_quantity_spec(To{}))) ||
|
||||
(!AssociatedUnit<From> && !AssociatedUnit<To>));
|
||||
// We are using a helper concept to benefit from short-circuiting
|
||||
template<typename U1, typename U2>
|
||||
concept PotentiallyInterConvertibleTo = Unit<U1> && Unit<U2> &&
|
||||
(!AssociatedUnit<U1> || !AssociatedUnit<U2> ||
|
||||
explicitly_convertible(get_quantity_spec(U1{}), get_quantity_spec(U2{})));
|
||||
} // namespace detail
|
||||
|
||||
}
|
||||
|
||||
// convertible
|
||||
template<Unit From, Unit To>
|
||||
[[nodiscard]] consteval bool convertible(From from, To to)
|
||||
// interconvertible
|
||||
template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval bool interconvertible(U1 u1, U2 u2)
|
||||
{
|
||||
if constexpr (is_same_v<From, To>)
|
||||
if constexpr (is_same_v<U1, U2>)
|
||||
return true;
|
||||
else if constexpr (detail::PotentiallyConvertibleTo<From, To>)
|
||||
return is_same_v<decltype(get_canonical_unit(from).reference_unit),
|
||||
decltype(get_canonical_unit(to).reference_unit)>;
|
||||
else if constexpr (detail::PotentiallyInterConvertibleTo<U1, U2>)
|
||||
return is_same_v<decltype(get_canonical_unit(u1).reference_unit), decltype(get_canonical_unit(u2).reference_unit)>;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template<UnitMagnitude auto M, Unit U>
|
||||
requires(M != detail::unit_magnitude<>{} && M != mag<1>)
|
||||
struct scaled_unit;
|
||||
|
||||
template<detail::SymbolicConstant... Expr>
|
||||
struct derived_unit;
|
||||
|
||||
MP_UNITS_EXPORT struct one;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct unit_interface {
|
||||
@ -424,7 +428,7 @@ struct prefixed_unit : decltype(M * U)::_base_type_ {
|
||||
namespace detail {
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
requires(convertible(U1{}, U2{}))
|
||||
requires(interconvertible(U1{}, U2{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_scaled_unit(U1, U2)
|
||||
{
|
||||
constexpr auto canonical_lhs = get_canonical_unit(U1{});
|
||||
@ -668,7 +672,7 @@ inline constexpr auto ppm = parts_per_million;
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(Unit auto u) { return u; }
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
requires(convertible(U1{}, U2{}))
|
||||
requires(interconvertible(U1{}, U2{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(U1 u1, U2 u2)
|
||||
{
|
||||
if constexpr (is_same_v<U1, U2>)
|
||||
@ -729,7 +733,7 @@ using collapse_common_unit = type_list_unique<
|
||||
} // namespace detail
|
||||
|
||||
template<Unit... Us, Unit NewUnit>
|
||||
requires(convertible(common_unit<Us...>{}, NewUnit{}))
|
||||
requires(interconvertible(common_unit<Us...>{}, NewUnit{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(common_unit<Us...>, NewUnit)
|
||||
{
|
||||
using type = detail::collapse_common_unit<NewUnit, Us...>;
|
||||
@ -740,7 +744,7 @@ template<Unit... Us, Unit NewUnit>
|
||||
}
|
||||
|
||||
template<Unit... Us, Unit NewUnit>
|
||||
requires(convertible(common_unit<Us...>{}, NewUnit{}))
|
||||
requires(interconvertible(common_unit<Us...>{}, NewUnit{}))
|
||||
[[nodiscard]] consteval Unit auto get_common_unit(NewUnit nu, common_unit<Us...> cu)
|
||||
{
|
||||
return get_common_unit(cu, nu);
|
||||
|
@ -25,7 +25,6 @@
|
||||
// IWYU pragma: private, include <mp-units/framework.h>
|
||||
#include <mp-units/bits/module_macros.h>
|
||||
#include <mp-units/framework/quantity_spec_concepts.h>
|
||||
#include <mp-units/framework/symbol_text.h>
|
||||
#include <mp-units/framework/symbolic_expression.h>
|
||||
#include <mp-units/framework/unit_magnitude.h>
|
||||
|
||||
@ -45,15 +44,9 @@ struct unit_interface;
|
||||
MP_UNITS_EXPORT template<typename T>
|
||||
concept Unit = detail::SymbolicConstant<T> && std::derived_from<T, detail::unit_interface>;
|
||||
|
||||
template<UnitMagnitude auto M, Unit U>
|
||||
requires(M != detail::unit_magnitude<>{} && M != mag<1>)
|
||||
struct scaled_unit;
|
||||
|
||||
MP_UNITS_EXPORT template<symbol_text Symbol, auto...>
|
||||
struct named_unit;
|
||||
|
||||
MP_UNITS_EXPORT struct one;
|
||||
|
||||
/**
|
||||
* @brief A concept to be used to define prefixes for a unit
|
||||
*/
|
||||
@ -100,24 +93,21 @@ concept AssociatedUnit = Unit<U> && detail::has_associated_quantity(U{});
|
||||
/**
|
||||
* @brief A concept matching all units associated with the provided quantity spec
|
||||
*
|
||||
* Satisfied by all units associated with the quantity_spec being the instantiation derived from
|
||||
* the provided quantity_spec type.
|
||||
* Satisfied by all units for which an associated quantity spec is implicitly convertible to
|
||||
* the provided @c QS value.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename U, auto QS>
|
||||
concept UnitOf =
|
||||
AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
detail::QuantitySpecConvertibleTo<get_quantity_spec(U{}), QS> &&
|
||||
// the below is to make `dimensionless[radian]` invalid
|
||||
(get_kind(QS) == get_kind(get_quantity_spec(U{})) || !detail::NestedQuantityKindSpecOf<get_quantity_spec(U{}), QS>);
|
||||
concept UnitOf = AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
(implicitly_convertible(get_quantity_spec(U{}), QS));
|
||||
|
||||
MP_UNITS_EXPORT template<Unit From, Unit To>
|
||||
[[nodiscard]] consteval bool convertible(From from, To to);
|
||||
MP_UNITS_EXPORT template<Unit U1, Unit U2>
|
||||
[[nodiscard]] consteval bool interconvertible(U1 u1, U2 u2);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<auto From, auto To>
|
||||
concept UnitConvertibleTo =
|
||||
Unit<MP_UNITS_REMOVE_CONST(decltype(From))> && Unit<MP_UNITS_REMOVE_CONST(decltype(To))> && (convertible(From, To));
|
||||
template<typename U, auto QS>
|
||||
concept WeakUnitOf =
|
||||
Unit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && ((!AssociatedUnit<U>) || UnitOf<U, QS>);
|
||||
|
||||
/**
|
||||
* @brief A concept matching all units compatible with the provided unit and quantity spec
|
||||
@ -125,10 +115,10 @@ concept UnitConvertibleTo =
|
||||
* 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>`.
|
||||
*/
|
||||
MP_UNITS_EXPORT template<typename U, auto FromU, auto QS>
|
||||
template<typename U, auto FromU, auto QS>
|
||||
concept UnitCompatibleWith =
|
||||
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(FromU))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
|
||||
(!AssociatedUnit<U> || UnitOf<U, QS>) && detail::UnitConvertibleTo<FromU, U{}>;
|
||||
WeakUnitOf<U, QS> && (interconvertible(FromU, U{}));
|
||||
|
||||
template<typename T>
|
||||
concept OffsetUnit = Unit<T> && requires { T::_point_origin_; };
|
||||
|
@ -44,8 +44,8 @@ namespace mp_units {
|
||||
*
|
||||
* @tparam ToU a unit to use for a target quantity
|
||||
*/
|
||||
template<Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToU))
|
||||
template<auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::unit, Q::quantity_spec>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), typename Q::rep>>(
|
||||
@ -81,16 +81,16 @@ template<Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<F
|
||||
* @tparam ToRep a representation type to use for the target quantity
|
||||
*/
|
||||
template<Unit auto ToU, Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToU)) && RepresentationOf<ToRep, Q::quantity_spec> &&
|
||||
std::constructible_from<ToRep, typename Q::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::unit, Q::quantity_spec> &&
|
||||
RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
return detail::sudo_cast<quantity<detail::make_reference(Q::quantity_spec, ToU), ToRep>>(std::forward<FwdQ>(q));
|
||||
}
|
||||
|
||||
template<Representation ToRep, Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToU)) && RepresentationOf<ToRep, Q::quantity_spec> &&
|
||||
std::constructible_from<ToRep, typename Q::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), Q::unit, Q::quantity_spec> &&
|
||||
RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
return value_cast<ToU, ToRep>(std::forward<FwdQ>(q));
|
||||
@ -112,8 +112,8 @@ template<Representation ToRep, Unit auto ToU, typename FwdQ, Quantity Q = std::r
|
||||
* @tparam ToQ a target quantity type to which to cast the representation
|
||||
*/
|
||||
template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
requires(convertible(Q::reference, ToQ::unit)) &&
|
||||
(ToQ::quantity_spec == Q::quantity_spec) && std::constructible_from<typename ToQ::rep, typename Q::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_NONCONST_TYPE(ToQ::unit), Q::unit, Q::quantity_spec> &&
|
||||
(ToQ::quantity_spec == Q::quantity_spec) && std::constructible_from<typename ToQ::rep, typename Q::rep>
|
||||
[[nodiscard]] constexpr Quantity auto value_cast(FwdQ&& q)
|
||||
{
|
||||
return detail::sudo_cast<ToQ>(std::forward<FwdQ>(q));
|
||||
@ -130,7 +130,7 @@ template<Quantity ToQ, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>>
|
||||
* @tparam ToU a unit to use for a target quantity point
|
||||
*/
|
||||
template<Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToU))
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::unit, QP::quantity_spec>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
@ -167,8 +167,8 @@ template<Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cv
|
||||
* @tparam ToRep a representation type to use for the target quantity
|
||||
*/
|
||||
template<Unit auto ToU, Representation ToRep, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToU)) && RepresentationOf<ToRep, QP::quantity_spec> &&
|
||||
std::constructible_from<ToRep, typename QP::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::unit, QP::quantity_spec> &&
|
||||
RepresentationOf<ToRep, QP::quantity_spec> && std::constructible_from<ToRep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return quantity_point{
|
||||
@ -177,8 +177,8 @@ template<Unit auto ToU, Representation ToRep, typename FwdQP, QuantityPoint QP =
|
||||
}
|
||||
|
||||
template<Representation ToRep, Unit auto ToU, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToU)) && RepresentationOf<ToRep, QP::quantity_spec> &&
|
||||
std::constructible_from<ToRep, typename QP::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_REMOVE_CONST(decltype(ToU)), QP::unit, QP::quantity_spec> &&
|
||||
RepresentationOf<ToRep, QP::quantity_spec> && std::constructible_from<ToRep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return value_cast<ToU, ToRep>(std::forward<FwdQP>(qp));
|
||||
@ -201,8 +201,8 @@ template<Representation ToRep, Unit auto ToU, typename FwdQP, QuantityPoint QP =
|
||||
* @tparam ToQ a target quantity type to which to cast the representation of the point
|
||||
*/
|
||||
template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToQ::unit)) &&
|
||||
(ToQ::quantity_spec == QP::quantity_spec) && std::constructible_from<typename ToQ::rep, typename QP::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_NONCONST_TYPE(ToQ::unit), QP::unit, QP::quantity_spec> &&
|
||||
(ToQ::quantity_spec == QP::quantity_spec) && std::constructible_from<typename ToQ::rep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).quantity_from_origin_is_an_implementation_detail_),
|
||||
@ -238,9 +238,10 @@ template<Quantity ToQ, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<Fw
|
||||
* @tparam ToQP a target quantity point type to which to cast the representation of the point
|
||||
*/
|
||||
template<QuantityPoint ToQP, typename FwdQP, QuantityPoint QP = std::remove_cvref_t<FwdQP>>
|
||||
requires(convertible(QP::reference, ToQP::unit)) && (ToQP::quantity_spec == QP::quantity_spec) &&
|
||||
(detail::same_absolute_point_origins(ToQP::point_origin, QP::point_origin)) &&
|
||||
std::constructible_from<typename ToQP::rep, typename QP::rep>
|
||||
requires detail::UnitCompatibleWith<MP_UNITS_NONCONST_TYPE(ToQP::unit), QP::unit, QP::quantity_spec> &&
|
||||
(ToQP::quantity_spec == QP::quantity_spec) &&
|
||||
(detail::same_absolute_point_origins(ToQP::point_origin, QP::point_origin)) &&
|
||||
std::constructible_from<typename ToQP::rep, typename QP::rep>
|
||||
[[nodiscard]] constexpr QuantityPoint auto value_cast(FwdQP&& qp)
|
||||
{
|
||||
return detail::sudo_cast<ToQP>(std::forward<FwdQP>(qp));
|
||||
|
@ -98,6 +98,32 @@ static_assert(QuantitySpec<MP_UNITS_NONCONST_TYPE(speed)>);
|
||||
static_assert(!QuantitySpec<struct isq::dim_length>);
|
||||
static_assert(!QuantitySpec<int>);
|
||||
|
||||
// QuantitySpecOf
|
||||
static_assert(QuantitySpecOf<struct isq::length, isq::length>);
|
||||
static_assert(QuantitySpecOf<struct isq::height, isq::length>);
|
||||
static_assert(!QuantitySpecOf<struct isq::length, isq::height>);
|
||||
static_assert(QuantitySpecOf<struct isq::displacement, isq::length>);
|
||||
static_assert(!QuantitySpecOf<struct isq::length, isq::displacement>);
|
||||
static_assert(QuantitySpecOf<struct isq::thickness, isq::width>);
|
||||
static_assert(!QuantitySpecOf<struct isq::width, isq::thickness>);
|
||||
static_assert(QuantitySpecOf<kind_of_<struct isq::length>, isq::height>);
|
||||
static_assert(QuantitySpecOf<kind_of_<struct isq::length>, isq::displacement>);
|
||||
|
||||
static_assert(!QuantitySpecOf<struct isq::angular_measure, dimensionless>);
|
||||
static_assert(!QuantitySpecOf<struct isq::angular_measure, kind_of<dimensionless>>);
|
||||
static_assert(!QuantitySpecOf<kind_of_<struct isq::angular_measure>, dimensionless>);
|
||||
static_assert(!QuantitySpecOf<kind_of_<struct isq::angular_measure>, kind_of<dimensionless>>);
|
||||
|
||||
static_assert(!QuantitySpecOf<struct dimensionless, isq::angular_measure>);
|
||||
static_assert(!QuantitySpecOf<struct dimensionless, kind_of<isq::angular_measure>>);
|
||||
static_assert(QuantitySpecOf<kind_of_<struct dimensionless>, isq::angular_measure>);
|
||||
static_assert(QuantitySpecOf<kind_of_<struct dimensionless>, kind_of<isq::angular_measure>>);
|
||||
|
||||
static_assert(!QuantitySpecOf<struct isq::solid_angular_measure, isq::angular_measure>);
|
||||
static_assert(!QuantitySpecOf<struct isq::solid_angular_measure, kind_of<isq::angular_measure>>);
|
||||
static_assert(!QuantitySpecOf<kind_of_<struct isq::solid_angular_measure>, isq::angular_measure>);
|
||||
static_assert(!QuantitySpecOf<kind_of_<struct isq::solid_angular_measure>, kind_of<isq::angular_measure>>);
|
||||
|
||||
// NamedQuantitySpec
|
||||
static_assert(detail::NamedQuantitySpec<struct isq::length>);
|
||||
static_assert(detail::NamedQuantitySpec<struct isq::radius>);
|
||||
@ -134,9 +160,6 @@ static_assert(!detail::QuantityKindSpec<MP_UNITS_NONCONST_TYPE(speed)>);
|
||||
static_assert(!detail::QuantityKindSpec<struct isq::dim_length>);
|
||||
static_assert(!detail::QuantityKindSpec<int>);
|
||||
|
||||
// QuantitySpecOf
|
||||
// TODO add tests
|
||||
|
||||
// Unit
|
||||
static_assert(Unit<struct si::metre>);
|
||||
static_assert(Unit<MP_UNITS_NONCONST_TYPE(si::kilogram)>);
|
||||
@ -229,6 +252,8 @@ static_assert(UnitOf<struct si::radian, isq::angular_measure>);
|
||||
static_assert(UnitOf<struct si::degree, isq::angular_measure>);
|
||||
static_assert(UnitOf<struct one, isq::angular_measure>);
|
||||
static_assert(UnitOf<struct percent, isq::angular_measure>);
|
||||
static_assert(UnitOf<MP_UNITS_NONCONST_TYPE(si::radian / si::second), isq::angular_velocity>);
|
||||
static_assert(UnitOf<MP_UNITS_NONCONST_TYPE(one / si::second), isq::angular_velocity>);
|
||||
static_assert(!UnitOf<struct si::radian, dimensionless>);
|
||||
static_assert(!UnitOf<struct si::metre, isq::time>);
|
||||
static_assert(!UnitOf<struct natural::electronvolt, isq::energy>);
|
||||
|
@ -1697,7 +1697,8 @@ static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], 5 * isq::freq
|
||||
static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], zero_Hz + 5 * isq::frequency[Hz]));
|
||||
|
||||
static_assert(invalid_addition(zero_Bq + 5 * isq::activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz]));
|
||||
static_assert(invalid_addition(5 * isq::activity[Bq], zero_Hz + 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz]));
|
||||
static_assert(invalid_addition(5 * isq::activity[Bq], zero_Hz + 10 / (2 * isq::period_duration[s]),
|
||||
5 * isq::frequency[Hz]));
|
||||
static_assert(invalid_addition(5 * isq::activity[Bq], 10 / (2 * isq::time[s]), zero_Hz + 5 * isq::frequency[Hz]));
|
||||
static_assert(invalid_subtraction(zero_Bq + 5 * isq::activity[Bq], 10 / (2 * isq::time[s]), 5 * isq::frequency[Hz]));
|
||||
|
||||
|
@ -40,6 +40,7 @@ using dim_one_ = struct dimension_one;
|
||||
inline constexpr struct dim_length_ final : base_dimension<"L"> {} dim_length;
|
||||
inline constexpr struct dim_mass_ final : base_dimension<"M"> {} dim_mass;
|
||||
inline constexpr struct dim_time_ final : base_dimension<"T"> {} dim_time;
|
||||
inline constexpr struct dim_electric_current_ final : base_dimension<"I"> {} dim_electric_current;
|
||||
|
||||
// quantities specification
|
||||
QUANTITY_SPEC_(length, dim_length);
|
||||
@ -48,6 +49,7 @@ QUANTITY_SPEC_(time, dim_time);
|
||||
|
||||
inline constexpr struct second_ final : named_unit<"s", kind_of<time>> {} second;
|
||||
|
||||
QUANTITY_SPEC_(horizontal_length, length);
|
||||
QUANTITY_SPEC_(height, length);
|
||||
QUANTITY_SPEC_(width, length);
|
||||
QUANTITY_SPEC_(radius, width);
|
||||
@ -65,12 +67,17 @@ QUANTITY_SPEC_(activity, inverse(time));
|
||||
QUANTITY_SPEC_(area, pow<2>(length));
|
||||
QUANTITY_SPEC_(volume, pow<3>(length));
|
||||
QUANTITY_SPEC_(angular_measure, dimensionless, arc_length / radius, is_kind);
|
||||
QUANTITY_SPEC_(special_angular_measure, angular_measure);
|
||||
QUANTITY_SPEC_(rotational_displacement, angular_measure, path_length / radius);
|
||||
QUANTITY_SPEC_(phase_angle, angular_measure);
|
||||
QUANTITY_SPEC_(solid_angular_measure, dimensionless, area / pow<2>(radius), is_kind);
|
||||
QUANTITY_SPEC_(dimensionless_rate, dimensionless / time);
|
||||
QUANTITY_SPEC_(angular_measure_rate, angular_measure / time);
|
||||
QUANTITY_SPEC_(solid_angular_measure_rate, solid_angular_measure / time);
|
||||
QUANTITY_SPEC_(speed, length / time);
|
||||
QUANTITY_SPEC_(velocity, speed, displacement / time);
|
||||
QUANTITY_SPEC_(special_speed, speed);
|
||||
QUANTITY_SPEC_(horizontal_speed, speed, horizontal_length / time);
|
||||
QUANTITY_SPEC_(rate_of_climb, speed, height / time);
|
||||
QUANTITY_SPEC_(special_rate_of_climb, rate_of_climb);
|
||||
QUANTITY_SPEC_(acceleration, velocity / time);
|
||||
@ -90,6 +97,18 @@ QUANTITY_SPEC_(mechanical_energy, energy);
|
||||
QUANTITY_SPEC_(potential_energy, mechanical_energy);
|
||||
QUANTITY_SPEC_(gravitational_potential_energy, potential_energy, mass * acceleration_of_free_fall * height);
|
||||
QUANTITY_SPEC_(kinetic_energy, mechanical_energy, mass* pow<2>(speed));
|
||||
QUANTITY_SPEC_(electric_current, dim_electric_current);
|
||||
QUANTITY_SPEC_(electric_charge, electric_current* time);
|
||||
QUANTITY_SPEC_(electric_field_strength, force / electric_charge); // vector
|
||||
QUANTITY_SPEC_(electric_potential, electric_field_strength* length, quantity_character::scalar);
|
||||
QUANTITY_SPEC_(voltage, electric_potential);
|
||||
QUANTITY_SPEC_(electromagnetism_power, power, voltage* electric_current);
|
||||
QUANTITY_SPEC_(electric_current_phasor, electric_current, quantity_character::complex);
|
||||
QUANTITY_SPEC_(voltage_phasor, voltage, quantity_character::complex);
|
||||
QUANTITY_SPEC_(active_power, power, inverse(period_duration) * (electromagnetism_power * time));
|
||||
QUANTITY_SPEC_(complex_power, voltage_phasor* electric_current_phasor); // separate kind
|
||||
QUANTITY_SPEC_(apparent_power, complex_power, quantity_character::scalar);
|
||||
|
||||
// clang-format on
|
||||
|
||||
// concepts verification
|
||||
@ -416,6 +435,7 @@ static_assert(get_kind(energy) == kind_of<energy>);
|
||||
static_assert(get_kind(potential_energy) == kind_of<energy>);
|
||||
static_assert(get_kind(kinetic_energy) == kind_of<energy>);
|
||||
static_assert(get_kind(pow<1, 2>(area)) == kind_of<pow<1, 2>(area)>);
|
||||
static_assert(get_kind(dimensionless) == kind_of<dimensionless>);
|
||||
static_assert(get_kind(angular_measure) == kind_of<angular_measure>);
|
||||
static_assert(get_kind(phase_angle) == kind_of<angular_measure>);
|
||||
static_assert(get_kind(rotational_displacement) == kind_of<angular_measure>);
|
||||
@ -446,6 +466,8 @@ static_assert(!defines_equation(potential_energy));
|
||||
static_assert(get_complexity(length) == 0);
|
||||
static_assert(get_complexity(pow<4>(length)) == 0);
|
||||
static_assert(get_complexity(dimensionless) == 0);
|
||||
static_assert(get_complexity(angular_measure) == 1);
|
||||
static_assert(get_complexity(solid_angular_measure) == 2);
|
||||
static_assert(get_complexity(length / time) == 0);
|
||||
static_assert(get_complexity(mass * length / time) == 0);
|
||||
static_assert(get_complexity(frequency) == 1);
|
||||
@ -453,9 +475,15 @@ static_assert(get_complexity(area) == 1);
|
||||
static_assert(get_complexity(pow<2>(area)) == 1);
|
||||
static_assert(get_complexity(volume) == 1);
|
||||
static_assert(get_complexity(speed) == 1);
|
||||
static_assert(get_complexity(special_speed) == 1);
|
||||
static_assert(get_complexity(horizontal_speed) == 1);
|
||||
static_assert(get_complexity(special_rate_of_climb) == 1);
|
||||
static_assert(get_complexity(velocity) == 1);
|
||||
static_assert(get_complexity(acceleration) == 2);
|
||||
static_assert(get_complexity(force) == 3);
|
||||
static_assert(get_complexity(dimensionless_rate) == 1);
|
||||
static_assert(get_complexity(angular_measure_rate) == 2);
|
||||
static_assert(get_complexity(solid_angular_measure_rate) == 3);
|
||||
|
||||
static_assert(get_complexity(acceleration * time) == 2);
|
||||
static_assert(get_complexity(acceleration / time) == 2);
|
||||
@ -470,21 +498,28 @@ static_assert(get_complexity(area / force) == 3);
|
||||
static_assert(get_complexity(speed * area / frequency) == 1);
|
||||
|
||||
// explode
|
||||
static_assert(explode<get_complexity(inverse(time))>(frequency).quantity == inverse(period_duration));
|
||||
static_assert(explode<get_complexity(kind_of<length / time>)>(speed).quantity == length / time);
|
||||
static_assert(explode<get_complexity(kind_of<length / time>)>(velocity).quantity == displacement / time);
|
||||
static_assert(explode<get_complexity(dimensionless)>(angular_measure).quantity == arc_length / radius);
|
||||
static_assert(explode<get_complexity(velocity)>(acceleration * time).quantity == velocity);
|
||||
static_assert(explode<get_complexity(area)>(area).quantity == area);
|
||||
static_assert(explode<get_complexity(area)>(volume / length).quantity == volume / length);
|
||||
static_assert(explode<get_complexity(area)>(volume / height).quantity == volume / height);
|
||||
static_assert(explode<get_complexity(area)>(pow<3>(length) / height).quantity == pow<3>(length) / height);
|
||||
static_assert(explode<get_complexity(area)>(area * time / period_duration).quantity == area * time / period_duration);
|
||||
static_assert(explode<get_complexity(area)>(pow<2>(length) * time / period_duration).quantity ==
|
||||
pow<2>(length) * time / period_duration);
|
||||
static_assert(explode(frequency).equation == inverse(period_duration));
|
||||
static_assert(explode(speed).equation == length / time);
|
||||
static_assert(explode(special_speed).equation == length / time);
|
||||
static_assert(explode(horizontal_speed).equation == horizontal_length / time);
|
||||
static_assert(explode(rate_of_climb).equation == height / time);
|
||||
static_assert(explode(special_rate_of_climb).equation == height / time);
|
||||
static_assert(explode(velocity).equation == displacement / time);
|
||||
|
||||
using enum specs_convertible_result;
|
||||
|
||||
static_assert(have_common_base(width, length));
|
||||
static_assert(have_common_base(width, height));
|
||||
static_assert(have_common_base(angular_measure, dimensionless));
|
||||
static_assert(have_common_base(angular_measure, solid_angular_measure));
|
||||
|
||||
static_assert(convertible_common_base(width, length) == yes);
|
||||
static_assert(convertible_common_base(length, width) == explicit_conversion);
|
||||
static_assert(convertible_common_base(width, height) == cast);
|
||||
static_assert(convertible_common_base(angular_measure, dimensionless) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible_common_base(dimensionless, angular_measure) == explicit_conversion);
|
||||
static_assert(convertible_common_base(angular_measure, solid_angular_measure) == no);
|
||||
|
||||
static_assert(are_ingredients_convertible(length / time, length / time) == yes);
|
||||
static_assert(are_ingredients_convertible(mass * length / time, mass* length / time) == yes);
|
||||
static_assert(are_ingredients_convertible(area / length, area / length) == yes);
|
||||
@ -528,6 +563,7 @@ static_assert(convertible(height, width) == cast);
|
||||
static_assert(convertible(potential_energy, kinetic_energy) == cast);
|
||||
static_assert(convertible(kinetic_energy, potential_energy) == cast);
|
||||
static_assert(convertible(rate_of_climb, velocity) == cast);
|
||||
static_assert(convertible(rate_of_climb, horizontal_speed) == cast);
|
||||
|
||||
// converting to a different kind
|
||||
static_assert(convertible(frequency, activity) == no);
|
||||
@ -547,9 +583,12 @@ static_assert(convertible(special_rate_of_climb, speed) == yes);
|
||||
static_assert(convertible(velocity, speed) == yes);
|
||||
static_assert(convertible(potential_energy, energy) == yes);
|
||||
static_assert(convertible(kinetic_energy, energy) == yes);
|
||||
static_assert(convertible(angular_measure, dimensionless) == yes);
|
||||
|
||||
// upcasting beyond the hierarchy/kind
|
||||
static_assert(convertible(angular_measure, dimensionless) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(angular_measure * time / period_duration, dimensionless) == explicit_conversion_beyond_kind);
|
||||
|
||||
// upcasting to the derived quantity
|
||||
static_assert(convertible(frequency, inverse(time)) == yes);
|
||||
static_assert(convertible(speed, length / time) == yes);
|
||||
static_assert(convertible(speed, length / time) == yes);
|
||||
@ -557,6 +596,8 @@ static_assert(convertible(velocity, length / time) == yes);
|
||||
static_assert(convertible(rate_of_climb, length / time) == yes);
|
||||
static_assert(convertible(rate_of_climb, height / time) == yes);
|
||||
static_assert(convertible(gravitational_potential_energy, mass* acceleration* length) == yes);
|
||||
static_assert(convertible(angular_measure, arc_length / radius) == yes);
|
||||
static_assert(convertible(solid_angular_measure, area / pow<2>(radius)) == yes);
|
||||
|
||||
// downcasting same hierarchy branch
|
||||
static_assert(convertible(length, width) == explicit_conversion);
|
||||
@ -572,12 +613,6 @@ static_assert(convertible(energy, kinetic_energy) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless, rotation) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless, rotational_displacement) == explicit_conversion);
|
||||
|
||||
// downcasting to a different kind
|
||||
static_assert(convertible(dimensionless, angular_measure) == yes);
|
||||
static_assert(convertible(dimensionless, kind_of<angular_measure>) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless>, angular_measure) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless>, kind_of<angular_measure>) == yes);
|
||||
|
||||
// derived quantities to type
|
||||
static_assert(convertible(inverse(frequency), time) == yes);
|
||||
static_assert(convertible(inverse(period_duration), frequency) == yes);
|
||||
@ -612,6 +647,8 @@ static_assert(convertible(pow<1, 2>(area), length) == yes);
|
||||
static_assert(convertible(length, pow<1, 2>(area)) == yes);
|
||||
static_assert(convertible(mass * acceleration_of_free_fall * height, gravitational_potential_energy) == yes);
|
||||
static_assert(convertible(mass * pow<2>(length) / pow<2>(time), kinetic_energy) == yes);
|
||||
static_assert(convertible(arc_length / radius, angular_measure) == yes);
|
||||
static_assert(convertible(area / pow<2>(radius), solid_angular_measure) == yes);
|
||||
|
||||
// additional dimensionless remainder
|
||||
static_assert(convertible(length / speed, time) == yes);
|
||||
@ -624,6 +661,10 @@ static_assert(convertible(length / time, rate_of_climb) == explicit_conversion);
|
||||
static_assert(convertible(acceleration / velocity, frequency) == explicit_conversion);
|
||||
static_assert(convertible(force * length, torque) == explicit_conversion);
|
||||
static_assert(convertible(mass * acceleration * length, gravitational_potential_energy) == explicit_conversion);
|
||||
static_assert(convertible(length / radius, angular_measure) == explicit_conversion);
|
||||
static_assert(convertible(length / length, angular_measure) == explicit_conversion);
|
||||
static_assert(convertible(arc_length / length, angular_measure) == explicit_conversion);
|
||||
static_assert(convertible(area / pow<2>(length), solid_angular_measure) == explicit_conversion);
|
||||
|
||||
// derived quantities to more specialized type
|
||||
static_assert(convertible(force * position_vector, torque) == explicit_conversion);
|
||||
@ -678,17 +719,25 @@ static_assert(convertible(height / period_duration, length / time) == yes);
|
||||
static_assert(convertible(height / width, length / length) == yes);
|
||||
static_assert(convertible(height * width, length* length) == yes);
|
||||
static_assert(convertible(inverse(path_length * distance), inverse(pow<2>(path_length))) == yes);
|
||||
static_assert(convertible(path_length * period_duration, length* time) == yes);
|
||||
|
||||
static_assert(convertible(volume * length, pow<2>(area)) == yes);
|
||||
static_assert(convertible(pow<4>(length), pow<2>(area)) == yes);
|
||||
static_assert(convertible(pow<2>(radius), pow<2>(length)) == yes);
|
||||
|
||||
static_assert(convertible(height * time / period_duration, length) == yes);
|
||||
static_assert(convertible(angular_measure * time / period_duration, arc_length / radius) == yes);
|
||||
static_assert(convertible(special_angular_measure * solid_angular_measure, angular_measure* solid_angular_measure) ==
|
||||
yes);
|
||||
|
||||
// derived to more specialized derived
|
||||
static_assert(convertible(length / time, height / period_duration) == explicit_conversion);
|
||||
static_assert(convertible(length * length, height* width) == explicit_conversion);
|
||||
static_assert(convertible(length * time, radius* period_duration) == explicit_conversion);
|
||||
|
||||
// derived to incompatible specialized derived
|
||||
static_assert(convertible(height / time, distance / time) == cast);
|
||||
static_assert(convertible(path_length * time, radius* period_duration) == cast);
|
||||
|
||||
// when more than one possible combination is present
|
||||
// TODO revise that
|
||||
@ -754,17 +803,18 @@ static_assert(convertible(energy, kind_of<energy>) == yes);
|
||||
static_assert(convertible(potential_energy, kind_of<energy>) == yes);
|
||||
static_assert(convertible(kinetic_energy, kind_of<energy>) == yes);
|
||||
static_assert(convertible(rotation, kind_of<dimensionless>) == yes);
|
||||
static_assert(convertible(angular_measure, kind_of<dimensionless>) == yes);
|
||||
static_assert(convertible(rotational_displacement, kind_of<dimensionless>) == yes);
|
||||
static_assert(convertible(angular_measure, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(rotational_displacement, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
|
||||
// converting derived type to a kind
|
||||
static_assert(convertible(inverse(time), kind_of<frequency>) == yes);
|
||||
static_assert(convertible(inverse(period_duration), kind_of<frequency>) == yes);
|
||||
static_assert(convertible(inverse(time), kind_of<frequency>) == explicit_conversion);
|
||||
static_assert(convertible(length / time, kind_of<speed>) == yes);
|
||||
static_assert(convertible(length / pow<2>(time), kind_of<acceleration>) == yes);
|
||||
static_assert(convertible(length / pow<2>(time), kind_of<acceleration>) == explicit_conversion);
|
||||
|
||||
// converting kind to a kind
|
||||
static_assert(convertible(kind_of<dimensionless>, kind_of<angular_measure>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure>, kind_of<dimensionless>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure>, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
|
||||
// converting derived kind to a kind
|
||||
static_assert(convertible(kind_of<inverse(time)>, kind_of<frequency>) == yes);
|
||||
@ -788,9 +838,181 @@ static_assert(convertible(frequency * period_duration, dimensionless) == yes);
|
||||
static_assert(convertible(frequency * time, dimensionless) == yes);
|
||||
static_assert(convertible(length / length, dimensionless) == yes);
|
||||
static_assert(convertible(length / width, dimensionless) == yes);
|
||||
static_assert(convertible(active_power / apparent_power, dimensionless) == yes);
|
||||
|
||||
static_assert(convertible(efficiency, strain) == cast);
|
||||
|
||||
// nested kinds
|
||||
static_assert(convertible(dimensionless, dimensionless) == yes);
|
||||
static_assert(convertible(angular_measure, dimensionless) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(solid_angular_measure, dimensionless) == explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless>, dimensionless) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure>, dimensionless) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(kind_of<solid_angular_measure>, dimensionless) == explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(dimensionless, kind_of<dimensionless>) == yes);
|
||||
static_assert(convertible(angular_measure, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(solid_angular_measure, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless>, kind_of<dimensionless>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure>, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(kind_of<solid_angular_measure>, kind_of<dimensionless>) == explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(angular_measure, solid_angular_measure) == no);
|
||||
static_assert(convertible(angular_measure, kind_of<solid_angular_measure>) == no);
|
||||
static_assert(convertible(kind_of<angular_measure>, kind_of<solid_angular_measure>) == no);
|
||||
|
||||
static_assert(convertible(dimensionless, angular_measure) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless, solid_angular_measure) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(dimensionless, kind_of<angular_measure>) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless, kind_of<solid_angular_measure>) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless>, angular_measure) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless>, solid_angular_measure) == yes);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless>, kind_of<angular_measure>) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless>, kind_of<solid_angular_measure>) == yes);
|
||||
|
||||
// derived nested kinds
|
||||
static_assert(convertible(dimensionless / time, dimensionless / time) == yes);
|
||||
static_assert(convertible(angular_measure / time, dimensionless / time) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(solid_angular_measure / time, dimensionless / time) == explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, dimensionless / time) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure / time>, dimensionless / time) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(kind_of<solid_angular_measure / time>, dimensionless / time) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(dimensionless / time, kind_of<dimensionless / time>) == yes);
|
||||
static_assert(convertible(angular_measure / time, kind_of<dimensionless / time>) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(solid_angular_measure / time, kind_of<dimensionless / time>) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, kind_of<dimensionless / time>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure / time>, kind_of<dimensionless / time>) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(kind_of<solid_angular_measure / time>, kind_of<dimensionless / time>) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(angular_measure / time, solid_angular_measure / time) == no);
|
||||
static_assert(convertible(angular_measure / time, kind_of<solid_angular_measure / time>) == no);
|
||||
static_assert(convertible(kind_of<angular_measure / time>, kind_of<solid_angular_measure / time>) == no);
|
||||
|
||||
static_assert(convertible(dimensionless / time, angular_measure / time) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless / time, solid_angular_measure / time) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(dimensionless / time, kind_of<angular_measure / time>) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless / time, kind_of<solid_angular_measure / time>) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, angular_measure / time) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless / time>, solid_angular_measure / time) == yes);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, kind_of<angular_measure / time>) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless / time>, kind_of<solid_angular_measure / time>) == yes);
|
||||
|
||||
// named derived nested kinds
|
||||
static_assert(convertible(dimensionless_rate, dimensionless_rate) == yes);
|
||||
static_assert(convertible(angular_measure_rate, dimensionless_rate) == no);
|
||||
static_assert(convertible(solid_angular_measure_rate, dimensionless_rate) == no);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, dimensionless_rate) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure_rate>, dimensionless_rate) == no);
|
||||
static_assert(convertible(kind_of<solid_angular_measure_rate>, dimensionless_rate) == no);
|
||||
|
||||
static_assert(convertible(dimensionless_rate, kind_of<dimensionless_rate>) == yes);
|
||||
static_assert(convertible(angular_measure_rate, kind_of<dimensionless_rate>) == no);
|
||||
static_assert(convertible(solid_angular_measure_rate, kind_of<dimensionless_rate>) == no);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, kind_of<dimensionless_rate>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure_rate>, kind_of<dimensionless_rate>) == no);
|
||||
static_assert(convertible(kind_of<solid_angular_measure_rate>, kind_of<dimensionless_rate>) == no);
|
||||
|
||||
static_assert(convertible(angular_measure_rate, solid_angular_measure_rate) == no);
|
||||
static_assert(convertible(angular_measure_rate, kind_of<solid_angular_measure_rate>) == no);
|
||||
static_assert(convertible(kind_of<angular_measure_rate>, kind_of<solid_angular_measure_rate>) == no);
|
||||
|
||||
static_assert(convertible(dimensionless_rate, angular_measure_rate) == no);
|
||||
static_assert(convertible(dimensionless_rate, solid_angular_measure_rate) == no);
|
||||
|
||||
static_assert(convertible(dimensionless_rate, kind_of<angular_measure_rate>) == no);
|
||||
static_assert(convertible(dimensionless_rate, kind_of<solid_angular_measure_rate>) == no);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, angular_measure_rate) == no);
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, solid_angular_measure_rate) == no);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, kind_of<angular_measure_rate>) == no);
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, kind_of<solid_angular_measure_rate>) == no);
|
||||
|
||||
static_assert(convertible(dimensionless_rate, dimensionless / time) == yes);
|
||||
static_assert(convertible(angular_measure_rate, dimensionless / time) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(solid_angular_measure_rate, dimensionless / time) == explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, dimensionless / time) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure_rate>, dimensionless / time) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(kind_of<solid_angular_measure_rate>, dimensionless / time) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(dimensionless_rate, kind_of<dimensionless / time>) == yes);
|
||||
static_assert(convertible(angular_measure_rate, kind_of<dimensionless / time>) == explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(solid_angular_measure_rate, kind_of<dimensionless / time>) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, kind_of<dimensionless / time>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure_rate>, kind_of<dimensionless / time>) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
static_assert(convertible(kind_of<solid_angular_measure_rate>, kind_of<dimensionless / time>) ==
|
||||
explicit_conversion_beyond_kind);
|
||||
|
||||
static_assert(convertible(angular_measure_rate, solid_angular_measure / time) == no);
|
||||
static_assert(convertible(angular_measure_rate, kind_of<solid_angular_measure / time>) == no);
|
||||
static_assert(convertible(kind_of<angular_measure_rate>, kind_of<solid_angular_measure / time>) == no);
|
||||
|
||||
static_assert(convertible(dimensionless_rate, angular_measure / time) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless_rate, kind_of<angular_measure / time>) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless_rate, solid_angular_measure / time) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless_rate, kind_of<solid_angular_measure / time>) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, angular_measure / time) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, solid_angular_measure / time) == yes);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, kind_of<angular_measure / time>) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless_rate>, kind_of<solid_angular_measure / time>) == yes);
|
||||
|
||||
static_assert(convertible(dimensionless / time, dimensionless_rate) == yes);
|
||||
static_assert(convertible(angular_measure / time, dimensionless_rate) == yes);
|
||||
static_assert(convertible(solid_angular_measure / time, dimensionless_rate) == yes);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, dimensionless_rate) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure / time>, dimensionless_rate) == yes);
|
||||
static_assert(convertible(kind_of<solid_angular_measure / time>, dimensionless_rate) == yes);
|
||||
|
||||
static_assert(convertible(dimensionless / time, kind_of<dimensionless_rate>) == yes);
|
||||
static_assert(convertible(angular_measure / time, kind_of<dimensionless_rate>) == yes);
|
||||
static_assert(convertible(solid_angular_measure / time, kind_of<dimensionless_rate>) == yes);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, kind_of<dimensionless_rate>) == yes);
|
||||
static_assert(convertible(kind_of<angular_measure / time>, kind_of<dimensionless_rate>) == yes);
|
||||
static_assert(convertible(kind_of<solid_angular_measure / time>, kind_of<dimensionless_rate>) == yes);
|
||||
|
||||
static_assert(convertible(angular_measure / time, solid_angular_measure_rate) == no);
|
||||
static_assert(convertible(angular_measure / time, kind_of<solid_angular_measure_rate>) == no);
|
||||
static_assert(convertible(kind_of<angular_measure / time>, kind_of<solid_angular_measure_rate>) == no);
|
||||
|
||||
static_assert(convertible(dimensionless / time, angular_measure_rate) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless / time, solid_angular_measure_rate) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(dimensionless / time, kind_of<angular_measure_rate>) == explicit_conversion);
|
||||
static_assert(convertible(dimensionless / time, kind_of<solid_angular_measure_rate>) == explicit_conversion);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, angular_measure_rate) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless / time>, solid_angular_measure_rate) == yes);
|
||||
|
||||
static_assert(convertible(kind_of<dimensionless / time>, kind_of<angular_measure_rate>) == yes);
|
||||
static_assert(convertible(kind_of<dimensionless / time>, kind_of<solid_angular_measure_rate>) == yes);
|
||||
|
||||
|
||||
// quantity character checks
|
||||
static_assert((displacement / time).character == quantity_character::vector);
|
||||
static_assert((position_vector / position_vector * time).character == quantity_character::scalar);
|
||||
@ -803,6 +1025,8 @@ static_assert(get_common_quantity_spec(kind_of<length>, length) == length);
|
||||
static_assert(get_common_quantity_spec(length, kind_of<length>) == length);
|
||||
static_assert(get_common_quantity_spec(width, kind_of<length>) == width);
|
||||
static_assert(get_common_quantity_spec(kind_of<length>, width) == width);
|
||||
static_assert(get_common_quantity_spec(kind_of<dimensionless>, kind_of<angular_measure>) == kind_of<angular_measure>);
|
||||
static_assert(get_common_quantity_spec(kind_of<dimensionless>, angular_measure) == angular_measure);
|
||||
|
||||
static_assert(get_common_quantity_spec(width, height) == length);
|
||||
static_assert(get_common_quantity_spec(distance, path_length) == path_length);
|
||||
@ -832,11 +1056,21 @@ static_assert(get_common_quantity_spec(mass * acceleration * length, gravitation
|
||||
mass * acceleration * length);
|
||||
|
||||
template<auto T1, auto T2>
|
||||
concept no_common_type = requires {
|
||||
requires !requires { typename std::common_type_t<decltype(T1), decltype(T2)>; };
|
||||
requires !requires { typename std::common_type_t<decltype(T2), decltype(T1)>; };
|
||||
concept no_common_quantity_spec = requires {
|
||||
requires !requires { get_common_quantity_spec(T1, T2); };
|
||||
requires !requires { get_common_quantity_spec(T2, T1); };
|
||||
};
|
||||
static_assert(no_common_type<energy, torque>);
|
||||
static_assert(no_common_type<frequency, activity>);
|
||||
static_assert(no_common_quantity_spec<energy, torque>);
|
||||
static_assert(no_common_quantity_spec<kind_of<energy>, torque>);
|
||||
static_assert(no_common_quantity_spec<frequency, activity>);
|
||||
static_assert(no_common_quantity_spec<kind_of<frequency>, activity>);
|
||||
static_assert(no_common_quantity_spec<frequency, kind_of<activity>>);
|
||||
static_assert(no_common_quantity_spec<kind_of<frequency>, kind_of<activity>>);
|
||||
static_assert(no_common_quantity_spec<dimensionless, angular_measure>);
|
||||
static_assert(no_common_quantity_spec<dimensionless, kind_of<angular_measure>>);
|
||||
static_assert(no_common_quantity_spec<angular_measure, solid_angular_measure>);
|
||||
static_assert(no_common_quantity_spec<kind_of<angular_measure>, solid_angular_measure>);
|
||||
static_assert(no_common_quantity_spec<angular_measure, kind_of<solid_angular_measure>>);
|
||||
static_assert(no_common_quantity_spec<kind_of<angular_measure>, kind_of<solid_angular_measure>>);
|
||||
|
||||
} // namespace
|
||||
|
@ -260,6 +260,12 @@ static_assert(std::convertible_to<quantity<isq::length[km], int>, quantity<isq::
|
||||
static_assert(std::constructible_from<quantity<isq::length[km]>, quantity<isq::length[m], int>>);
|
||||
static_assert(std::convertible_to<quantity<isq::length[m], int>, quantity<isq::length[km]>>);
|
||||
|
||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[rad]>, quantity<dimensionless[one]>>);
|
||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[rad]>, quantity<one>>);
|
||||
static_assert(!std::convertible_to<quantity<rad>, quantity<one>>);
|
||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[one]>, quantity<dimensionless[one]>>);
|
||||
static_assert(!std::convertible_to<quantity<isq::angular_measure[one]>, quantity<one>>);
|
||||
|
||||
///////////////////////
|
||||
// obtaining a number
|
||||
///////////////////////
|
||||
@ -337,6 +343,7 @@ static_assert((15'000. * nm).in(m).numerical_value_in(nm) == 15'000.);
|
||||
// check if unit conversion works - don't bother about the actual result
|
||||
static_assert((1. * rad + 1. * deg).in(rad) != 0 * rad);
|
||||
static_assert((1. * rad + 1. * deg).in(deg) != 0 * deg);
|
||||
static_assert((1. * rad + 1. * deg).in(one) != 0 * one);
|
||||
|
||||
#if MP_UNITS_HOSTED
|
||||
static_assert(((2.f + 1if) * isq::voltage_phasor[V]).in(mV).numerical_value_in(mV) == 2000.f + 1000if);
|
||||
@ -1309,12 +1316,25 @@ static_assert(is_of_type<quantity_cast<isq::distance>(1 * m), quantity<isq::dist
|
||||
static_assert(is_of_type<quantity_cast<isq::distance>(isq::length(1 * m)), quantity<isq::distance[m], int>>);
|
||||
static_assert(is_of_type<quantity_cast<kind_of<isq::length>>(isq::length(1 * m)), quantity<si::metre, int>>);
|
||||
static_assert(is_of_type<quantity_cast<kind_of<isq::length>>(isq::distance(1 * m)), quantity<si::metre, int>>);
|
||||
|
||||
static_assert(is_of_type<quantity_cast<dimensionless>(1. * isq::angular_measure[one]), quantity<dimensionless[one]>>);
|
||||
static_assert(
|
||||
is_of_type<quantity_cast<dimensionless>((1. * isq::angular_measure[rad]).in(one)), quantity<dimensionless[one]>>);
|
||||
static_assert(is_of_type<quantity_cast<dimensionless>((1. * rad).in(one)), quantity<dimensionless[one]>>);
|
||||
|
||||
// lvalue references in quantity_cast
|
||||
namespace lvalue_tests {
|
||||
constexpr quantity<m, int> lvalue_q = 1 * m;
|
||||
static_assert(is_of_type<quantity_cast<isq::distance>(lvalue_q), quantity<isq::distance[m], int>>);
|
||||
} // namespace lvalue_tests
|
||||
|
||||
template<template<auto, typename> typename Q>
|
||||
concept invalid_quantity_cast = requires {
|
||||
requires !requires { quantity_cast<dimensionless>(Q<rad, double>(42. * rad)); };
|
||||
requires !requires { quantity_cast<dimensionless>(Q<isq::angular_measure[rad], double>(42. * rad)); };
|
||||
};
|
||||
static_assert(invalid_quantity_cast<quantity>);
|
||||
|
||||
// QuantityOf
|
||||
static_assert(QuantityOf<quantity<isq::length[m]>, isq::length>);
|
||||
static_assert(QuantityOf<quantity<isq::width[m]>, isq::length>);
|
||||
|
@ -284,14 +284,8 @@ static_assert(invalid_unit<storage_capacity, steradian>);
|
||||
static_assert(is_of_type<get_common_reference(dimensionless[one], one), reference<dimensionless_, one_>>);
|
||||
static_assert(is_of_type<get_common_reference(radian, one), radian_>);
|
||||
static_assert(is_of_type<get_common_reference(one, radian), radian_>);
|
||||
static_assert(is_of_type<get_common_reference(radian, dimensionless[one]), reference<angular_measure_, radian_>>);
|
||||
static_assert(is_of_type<get_common_reference(dimensionless[one], radian), reference<angular_measure_, radian_>>);
|
||||
static_assert(is_of_type<get_common_reference(angular_measure[radian], one), reference<angular_measure_, radian_>>);
|
||||
static_assert(is_of_type<get_common_reference(one, angular_measure[radian]), reference<angular_measure_, radian_>>);
|
||||
static_assert(
|
||||
is_of_type<get_common_reference(angular_measure[radian], dimensionless[one]), reference<angular_measure_, radian_>>);
|
||||
static_assert(
|
||||
is_of_type<get_common_reference(dimensionless[one], angular_measure[radian]), reference<angular_measure_, radian_>>);
|
||||
|
||||
template<auto R1, auto R2>
|
||||
concept no_common_reference = requires {
|
||||
@ -307,43 +301,29 @@ static_assert(no_common_reference<radian, steradian>);
|
||||
static_assert(no_common_reference<angular_measure[radian], steradian>);
|
||||
static_assert(no_common_reference<radian, solid_angular_measure[steradian]>);
|
||||
static_assert(no_common_reference<angular_measure[radian], solid_angular_measure[steradian]>);
|
||||
static_assert(no_common_reference<radian, dimensionless[one]>);
|
||||
static_assert(no_common_reference<angular_measure[radian], dimensionless[one]>);
|
||||
|
||||
// addition of various dimensionless quantities
|
||||
static_assert(is_of_type<1 * radian + 1 * one, quantity<radian, int>>);
|
||||
static_assert(is_of_type<1 * radian + dimensionless(1 * one), quantity<angular_measure[radian], int>>);
|
||||
static_assert(is_of_type<angular_measure(1 * radian) + 1 * one, quantity<angular_measure[radian], int>>);
|
||||
static_assert(is_of_type<angular_measure(1 * radian) + dimensionless(1 * one), quantity<angular_measure[radian], int>>);
|
||||
|
||||
static_assert(is_of_type<1 * steradian + 1 * one, quantity<steradian, int>>);
|
||||
static_assert(is_of_type<1 * steradian + dimensionless(1 * one), quantity<solid_angular_measure[steradian], int>>);
|
||||
static_assert(
|
||||
is_of_type<solid_angular_measure(1 * steradian) + 1 * one, quantity<solid_angular_measure[steradian], int>>);
|
||||
static_assert(is_of_type<solid_angular_measure(1 * steradian) + dimensionless(1 * one),
|
||||
quantity<solid_angular_measure[steradian], int>>);
|
||||
|
||||
// subtraction of various dimensionless quantities
|
||||
static_assert(is_of_type<1 * radian - 1 * one, quantity<radian, int>>);
|
||||
static_assert(is_of_type<1 * radian - dimensionless(1 * one), quantity<angular_measure[radian], int>>);
|
||||
static_assert(is_of_type<angular_measure(1 * radian) - 1 * one, quantity<angular_measure[radian], int>>);
|
||||
static_assert(is_of_type<angular_measure(1 * radian) - dimensionless(1 * one), quantity<angular_measure[radian], int>>);
|
||||
|
||||
static_assert(is_of_type<1 * steradian - 1 * one, quantity<steradian, int>>);
|
||||
static_assert(is_of_type<1 * steradian - dimensionless(1 * one), quantity<solid_angular_measure[steradian], int>>);
|
||||
static_assert(
|
||||
is_of_type<solid_angular_measure(1 * steradian) - 1 * one, quantity<solid_angular_measure[steradian], int>>);
|
||||
static_assert(is_of_type<solid_angular_measure(1 * steradian) - dimensionless(1 * one),
|
||||
quantity<solid_angular_measure[steradian], int>>);
|
||||
|
||||
// comparison of various dimensionless quantities
|
||||
static_assert(1 * radian == 1 * one);
|
||||
static_assert(1 * radian == dimensionless(1 * one));
|
||||
static_assert(angular_measure(1 * radian) == 1 * one);
|
||||
static_assert(angular_measure(1 * radian) == dimensionless(1 * one));
|
||||
|
||||
static_assert(1 * steradian == 1 * one);
|
||||
static_assert(1 * steradian == dimensionless(1 * one));
|
||||
static_assert(solid_angular_measure(1 * steradian) == 1 * one);
|
||||
static_assert(solid_angular_measure(1 * steradian) == dimensionless(1 * one));
|
||||
|
||||
// invalid operations on dimensionless quantities
|
||||
template<auto Q1, auto Q2>
|
||||
@ -358,6 +338,8 @@ static_assert(invalid_addition<1 * radian, 1 * bit>);
|
||||
static_assert(invalid_addition<frequency(1 * hertz), activity(1 * becquerel)>);
|
||||
static_assert(invalid_addition<angular_measure(1 * radian), solid_angular_measure(1 * steradian)>);
|
||||
static_assert(invalid_addition<angular_measure(1 * radian), storage_capacity(1 * bit)>);
|
||||
static_assert(invalid_addition<1 * radian, dimensionless(1 * one)>);
|
||||
static_assert(invalid_addition<angular_measure(1 * radian), dimensionless(1 * one)>);
|
||||
|
||||
template<auto Q1, auto Q2>
|
||||
concept invalid_subtraction = requires {
|
||||
@ -371,6 +353,8 @@ static_assert(invalid_subtraction<1 * radian, 1 * bit>);
|
||||
static_assert(invalid_subtraction<frequency(1 * hertz), activity(1 * becquerel)>);
|
||||
static_assert(invalid_subtraction<angular_measure(1 * radian), solid_angular_measure(1 * steradian)>);
|
||||
static_assert(invalid_subtraction<angular_measure(1 * radian), storage_capacity(1 * bit)>);
|
||||
static_assert(invalid_subtraction<1 * radian, dimensionless(1 * one)>);
|
||||
static_assert(invalid_subtraction<angular_measure(1 * radian), dimensionless(1 * one)>);
|
||||
|
||||
template<auto Q1, auto Q2>
|
||||
concept invalid_comparison = requires {
|
||||
@ -384,6 +368,8 @@ static_assert(invalid_comparison<1 * radian, 1 * bit>);
|
||||
static_assert(invalid_comparison<frequency(1 * hertz), activity(1 * becquerel)>);
|
||||
static_assert(invalid_comparison<angular_measure(1 * radian), solid_angular_measure(1 * steradian)>);
|
||||
static_assert(invalid_comparison<angular_measure(1 * radian), storage_capacity(1 * bit)>);
|
||||
static_assert(invalid_comparison<1 * radian, dimensionless(1 * one)>);
|
||||
static_assert(invalid_comparison<angular_measure(1 * radian), dimensionless(1 * one)>);
|
||||
|
||||
// make_reference
|
||||
static_assert(is_of_type<make_reference(length, metre), reference<length_, metre_>>);
|
||||
|
@ -156,6 +156,17 @@ static_assert(is_same_v<type_list_split_half<type_list<int, long, double, float>
|
||||
static_assert(
|
||||
is_same_v<type_list_split_half<type_list<int, long, double, float>>::second_list, type_list<double, float>>);
|
||||
|
||||
// type_list_extract
|
||||
|
||||
static_assert(is_same_v<type_list_extract<type_list<int>, 0>::element, int>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int>, 0>::rest, type_list<>>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int, long>, 0>::element, int>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int, long>, 0>::rest, type_list<long>>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int, long>, 1>::element, long>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int, long>, 1>::rest, type_list<int>>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int, long, double>, 1>::element, long>);
|
||||
static_assert(is_same_v<type_list_extract<type_list<int, long, double>, 1>::rest, type_list<int, double>>);
|
||||
|
||||
template<auto V>
|
||||
struct constant {
|
||||
static constexpr auto value = V;
|
||||
|
@ -120,15 +120,15 @@ static_assert(!PrefixableUnit<MP_UNITS_NONCONST_TYPE(kilometre)>);
|
||||
static_assert(is_of_type<metre, metre_>);
|
||||
static_assert(is_of_type<get_canonical_unit(metre).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(metre).mag == mag<1>);
|
||||
static_assert(convertible(metre, metre));
|
||||
static_assert(!convertible(metre, second));
|
||||
static_assert(interconvertible(metre, metre));
|
||||
static_assert(!interconvertible(metre, second));
|
||||
static_assert(metre == metre);
|
||||
static_assert(metre != second);
|
||||
|
||||
static_assert(is_of_type<degree_Celsius, degree_Celsius_>);
|
||||
static_assert(is_of_type<get_canonical_unit(degree_Celsius).reference_unit, kelvin_>);
|
||||
static_assert(get_canonical_unit(degree_Celsius).mag == mag<1>);
|
||||
static_assert(convertible(degree_Celsius, kelvin));
|
||||
static_assert(interconvertible(degree_Celsius, kelvin));
|
||||
static_assert(degree_Celsius != kelvin);
|
||||
static_assert(equivalent(degree_Celsius, kelvin));
|
||||
|
||||
@ -139,28 +139,31 @@ static_assert(get_canonical_unit(radian).mag == mag<1>);
|
||||
static_assert(is_of_type<degree, degree_>);
|
||||
static_assert(is_of_type<get_canonical_unit(degree).reference_unit, one_>);
|
||||
static_assert(get_canonical_unit(degree).mag == mag<π> / mag<180>);
|
||||
static_assert(convertible(radian, degree));
|
||||
static_assert(interconvertible(radian, degree));
|
||||
static_assert(radian != degree);
|
||||
static_assert(interconvertible(one, radian));
|
||||
static_assert(interconvertible(radian, one));
|
||||
static_assert(radian != one);
|
||||
|
||||
static_assert(is_of_type<steradian, steradian_>);
|
||||
static_assert(is_of_type<get_canonical_unit(steradian).reference_unit, one_>);
|
||||
static_assert(get_canonical_unit(steradian).mag == mag<1>);
|
||||
static_assert(!convertible(radian, steradian));
|
||||
static_assert(!interconvertible(radian, steradian));
|
||||
static_assert(radian != steradian);
|
||||
|
||||
static_assert(is_of_type<minute, minute_>);
|
||||
static_assert(is_of_type<get_canonical_unit(minute).reference_unit, second_>);
|
||||
static_assert(get_canonical_unit(minute).mag == mag<60>);
|
||||
static_assert(convertible(minute, second));
|
||||
static_assert(interconvertible(minute, second));
|
||||
static_assert(minute != second);
|
||||
|
||||
static_assert(is_of_type<hour, hour_>);
|
||||
static_assert(is_of_type<get_canonical_unit(hour).reference_unit, second_>);
|
||||
static_assert(get_canonical_unit(hour).mag == mag<3600>);
|
||||
static_assert(convertible(hour, second));
|
||||
static_assert(interconvertible(hour, second));
|
||||
|
||||
static_assert(convertible(hour, minute));
|
||||
static_assert(convertible(hour, hour));
|
||||
static_assert(interconvertible(hour, minute));
|
||||
static_assert(interconvertible(hour, hour));
|
||||
static_assert(hour != second);
|
||||
static_assert(hour != minute);
|
||||
static_assert(hour == hour);
|
||||
@ -169,14 +172,14 @@ static_assert(is_of_type<newton, newton_>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(newton).reference_unit, derived_unit<gram_, metre_, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(newton).mag == mag<1000>); // !!! (because of kilogram)
|
||||
static_assert(convertible(newton, newton));
|
||||
static_assert(interconvertible(newton, newton));
|
||||
static_assert(newton == newton);
|
||||
|
||||
static_assert(is_of_type<joule, joule_>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(joule).reference_unit, derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(joule).mag == mag<1000>); // !!! (because of kilogram)
|
||||
static_assert(convertible(joule, joule));
|
||||
static_assert(interconvertible(joule, joule));
|
||||
static_assert(joule == joule);
|
||||
static_assert(joule != newton);
|
||||
|
||||
@ -187,8 +190,8 @@ static_assert(is_of_type<standard_gravity, standard_gravity_>);
|
||||
static_assert(
|
||||
is_of_type<get_canonical_unit(standard_gravity).reference_unit, derived_unit<metre_, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(standard_gravity).mag == mag_ratio<980'665, 100'000>);
|
||||
static_assert(convertible(standard_gravity, standard_gravity));
|
||||
static_assert(convertible(standard_gravity, metre / square(second)));
|
||||
static_assert(interconvertible(standard_gravity, standard_gravity));
|
||||
static_assert(interconvertible(standard_gravity, metre / square(second)));
|
||||
static_assert(standard_gravity == standard_gravity);
|
||||
static_assert(standard_gravity != metre / square(second)); // magnitude is different
|
||||
static_assert(standard_gravity._symbol_ == symbol_text{u8"g₀", "g_0"});
|
||||
@ -197,7 +200,7 @@ static_assert(standard_gravity._symbol_ == symbol_text{u8"g₀", "g_0"});
|
||||
static_assert(is_of_type<kilometre, MP_UNITS_NONCONST_TYPE(kilo<metre>)>);
|
||||
static_assert(is_of_type<get_canonical_unit(kilometre).reference_unit, metre_>);
|
||||
static_assert(get_canonical_unit(kilometre).mag == mag<1000>);
|
||||
static_assert(convertible(kilometre, metre));
|
||||
static_assert(interconvertible(kilometre, metre));
|
||||
static_assert(kilometre != metre);
|
||||
static_assert(kilometre._symbol_ == "km");
|
||||
|
||||
@ -205,7 +208,7 @@ static_assert(is_of_type<kilojoule, MP_UNITS_NONCONST_TYPE(kilo<joule>)>);
|
||||
static_assert(is_of_type<get_canonical_unit(kilojoule).reference_unit,
|
||||
derived_unit<gram_, power<metre_, 2>, per<power<second_, 2>>>>);
|
||||
static_assert(get_canonical_unit(kilojoule).mag == mag<1'000'000>);
|
||||
static_assert(convertible(kilojoule, joule));
|
||||
static_assert(interconvertible(kilojoule, joule));
|
||||
static_assert(kilojoule != joule);
|
||||
static_assert(kilojoule._symbol_ == "kJ");
|
||||
|
||||
@ -448,11 +451,11 @@ static_assert(equivalent(kilo<metre> * milli<metre>, si::deca<metre>* si::deci<m
|
||||
// comparisons of equivalent units (named vs unnamed/derived)
|
||||
static_assert(one / second != hertz);
|
||||
static_assert(equivalent(one / second, hertz));
|
||||
static_assert(convertible(one / second, hertz));
|
||||
static_assert(interconvertible(one / second, hertz));
|
||||
|
||||
// comparisons of equivalent units of different quantities
|
||||
static_assert(hertz != becquerel);
|
||||
static_assert(!convertible(hertz, becquerel));
|
||||
static_assert(!interconvertible(hertz, becquerel));
|
||||
|
||||
// comparisons of scaled units
|
||||
static_assert(kilo<metre> == kilometre);
|
||||
@ -460,23 +463,23 @@ static_assert(mag<1000> * metre != kilo<metre>);
|
||||
static_assert(equivalent(mag<1000> * metre, kilo<metre>));
|
||||
static_assert(mag<1000> * metre != kilometre);
|
||||
static_assert(equivalent(mag<1000> * metre, kilometre));
|
||||
static_assert(convertible(kilo<metre>, kilometre));
|
||||
static_assert(convertible(mag<1000> * metre, kilo<metre>));
|
||||
static_assert(convertible(mag<1000> * metre, kilometre));
|
||||
static_assert(interconvertible(kilo<metre>, kilometre));
|
||||
static_assert(interconvertible(mag<1000> * metre, kilo<metre>));
|
||||
static_assert(interconvertible(mag<1000> * metre, kilometre));
|
||||
|
||||
static_assert(mag<60> * metre / second != metre / (mag_ratio<1, 60> * second));
|
||||
static_assert(equivalent(mag<60> * metre / second, metre / (mag_ratio<1, 60> * second)));
|
||||
|
||||
static_assert(metre != kilometre);
|
||||
static_assert(convertible(metre, kilometre));
|
||||
static_assert(interconvertible(metre, kilometre));
|
||||
static_assert(mag<100> * metre != kilometre);
|
||||
static_assert(convertible(mag<100> * metre, kilometre));
|
||||
static_assert(interconvertible(mag<100> * metre, kilometre));
|
||||
static_assert(milli<metre> != kilometre);
|
||||
static_assert(convertible(milli<metre>, kilometre));
|
||||
static_assert(interconvertible(milli<metre>, kilometre));
|
||||
|
||||
// comparisons of non-convertible units
|
||||
// comparisons of non-interconvertible units
|
||||
static_assert(metre != metre * metre);
|
||||
static_assert(!convertible(metre, metre* metre));
|
||||
static_assert(!interconvertible(metre, metre* metre));
|
||||
|
||||
// one
|
||||
static_assert(is_of_type<metre / metre, one_>);
|
||||
|
Reference in New Issue
Block a user