mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-04 12:54:25 +02:00
refactor: reference
now takes NTTPs rather then types
Even though it makes error logs a bit more obscure it simplifies coding a lot.
This commit is contained in:
@@ -78,16 +78,16 @@ static_assert(10 * isq::length[m] / (2 * isq::time[s]) - 5 * isq::speed[m / s] =
|
|||||||
static_assert(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s]) == 0 * isq::speed[m / s]);
|
static_assert(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s]) == 0 * isq::speed[m / s]);
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s]) + 5 * isq::speed[m / s]),
|
is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s]) + 5 * isq::speed[m / s]),
|
||||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
quantity<reference<isq::speed, derived_unit<struct si::metre, per<struct si::second>>{}>{}, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(5 * isq::speed[m / s] + 10 * isq::length[m] / (2 * isq::time[s])),
|
is_same_v<decltype(5 * isq::speed[m / s] + 10 * isq::length[m] / (2 * isq::time[s])),
|
||||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
quantity<reference<isq::speed, derived_unit<struct si::metre, per<struct si::second>>{}>{}, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s]) - 5 * isq::speed[m / s]),
|
is_same_v<decltype(10 * isq::length[m] / (2 * isq::time[s]) - 5 * isq::speed[m / s]),
|
||||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
quantity<reference<isq::speed, derived_unit<struct si::metre, per<struct si::second>>{}>{}, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s])),
|
is_same_v<decltype(5 * isq::speed[m / s] - 10 * isq::length[m] / (2 * isq::time[s])),
|
||||||
quantity<reference<struct isq::speed, derived_unit<struct si::metre, per<struct si::second>>>{}, int>>);
|
quantity<reference<isq::speed, derived_unit<struct si::metre, per<struct si::second>>{}>{}, int>>);
|
||||||
|
|
||||||
// Named and derived dimensions (different units)
|
// Named and derived dimensions (different units)
|
||||||
static_assert(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz] == 10 * isq::frequency[Hz]);
|
static_assert(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz] == 10 * isq::frequency[Hz]);
|
||||||
@@ -95,13 +95,13 @@ static_assert(5 * isq::frequency[Hz] + 10 / (2 * isq::time[s]) == 10 * isq::freq
|
|||||||
static_assert(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz] == 0 * isq::frequency[Hz]);
|
static_assert(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz] == 0 * isq::frequency[Hz]);
|
||||||
static_assert(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s]) == 0 * isq::frequency[Hz]);
|
static_assert(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s]) == 0 * isq::frequency[Hz]);
|
||||||
static_assert(is_same_v<decltype(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz]),
|
static_assert(is_same_v<decltype(10 / (2 * isq::time[s]) + 5 * isq::frequency[Hz]),
|
||||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
quantity<reference<isq::frequency, si::hertz>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(5 * isq::frequency[Hz] + 10 / (2 * isq::time[s])),
|
static_assert(is_same_v<decltype(5 * isq::frequency[Hz] + 10 / (2 * isq::time[s])),
|
||||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
quantity<reference<isq::frequency, si::hertz>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz]),
|
static_assert(is_same_v<decltype(10 / (2 * isq::time[s]) - 5 * isq::frequency[Hz]),
|
||||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
quantity<reference<isq::frequency, si::hertz>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s])),
|
static_assert(is_same_v<decltype(5 * isq::frequency[Hz] - 10 / (2 * isq::time[s])),
|
||||||
quantity<reference<struct isq::frequency, struct si::hertz>{}, int>>);
|
quantity<reference<isq::frequency, si::hertz>{}, int>>);
|
||||||
|
|
||||||
// Different named dimensions
|
// Different named dimensions
|
||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
@@ -118,8 +118,8 @@ constexpr quantity<isq::speed[km / h]> speed = 120 * isq::length[km] / (2 * isq:
|
|||||||
// Explicit casts allow changing all or only a part of the type
|
// Explicit casts allow changing all or only a part of the type
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_same_v<decltype(quantity_cast<isq::speed>(120 * isq::length[km] / (2 * isq::time[h]))),
|
std::is_same_v<decltype(quantity_cast<isq::speed>(120 * isq::length[km] / (2 * isq::time[h]))),
|
||||||
quantity<reference<struct isq::speed, derived_unit<std::remove_const_t<decltype(si::kilo<si::metre>)>,
|
quantity<reference<isq::speed, derived_unit<std::remove_const_t<decltype(si::kilo<si::metre>)>,
|
||||||
per<struct si::hour>>>{},
|
per<struct si::hour>>{}>{},
|
||||||
int>>);
|
int>>);
|
||||||
auto q3 = quantity_cast<m / s>(120 * isq::length[km] / (2 * isq::time[h]));
|
auto q3 = quantity_cast<m / s>(120 * isq::length[km] / (2 * isq::time[h]));
|
||||||
auto q4 = quantity_cast<isq::speed[m / s]>(120 * isq::length[km] / (2 * isq::time[h]));
|
auto q4 = quantity_cast<isq::speed[m / s]>(120 * isq::length[km] / (2 * isq::time[h]));
|
||||||
|
@@ -32,16 +32,26 @@
|
|||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
template<Dimension D, Unit U>
|
template<Dimension auto D, Unit auto U>
|
||||||
struct reference;
|
struct reference;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_specialization_of_reference = false;
|
||||||
|
|
||||||
|
template<Dimension auto D, Unit auto U>
|
||||||
|
inline constexpr bool is_specialization_of_reference<reference<D, U>> = true;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A concept matching all references in the library.
|
* @brief A concept matching all references in the library.
|
||||||
*
|
*
|
||||||
* Satisfied by all specializations of @c reference.
|
* Satisfied by all specializations of @c reference.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept Reference = is_specialization_of<T, reference>;
|
concept Reference = detail::is_specialization_of_reference<T>;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
@@ -91,7 +91,7 @@ struct quantity_values {
|
|||||||
/**
|
/**
|
||||||
* @brief Provides support for external quantity-like types
|
* @brief Provides support for external quantity-like types
|
||||||
*
|
*
|
||||||
* The type trait should provide the following nested type aliases: @c dimension, @c unit, @c rep,
|
* The type trait should provide the following nested values @c dimension, @c unit and type alias @c rep,
|
||||||
* and a static member function @c number(T) that will return the raw value of the quantity.
|
* and a static member function @c number(T) that will return the raw value of the quantity.
|
||||||
*
|
*
|
||||||
* Usage example can be found in @c units/chrono.h header file.
|
* Usage example can be found in @c units/chrono.h header file.
|
||||||
|
@@ -63,7 +63,7 @@ inline constexpr bool is_valid_unit_for_dimension = false;
|
|||||||
template<typename U, typename Dim>
|
template<typename U, typename Dim>
|
||||||
concept valid_unit_for_dimension = Unit<U> && Dimension<Dim> && detail::is_valid_unit_for_dimension<U{}, Dim{}>;
|
concept valid_unit_for_dimension = Unit<U> && Dimension<Dim> && detail::is_valid_unit_for_dimension<U{}, Dim{}>;
|
||||||
|
|
||||||
template<Dimension D, Unit U>
|
template<Dimension auto D, Unit auto U>
|
||||||
struct reference;
|
struct reference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,13 +104,13 @@ struct base_dimension {
|
|||||||
|
|
||||||
#ifdef __cpp_explicit_this_parameter
|
#ifdef __cpp_explicit_this_parameter
|
||||||
template<typename Self, valid_unit_for_dimension<Self> U>
|
template<typename Self, valid_unit_for_dimension<Self> U>
|
||||||
[[nodiscard]] constexpr reference<Self, U> operator[](this const Self, U)
|
[[nodiscard]] constexpr auto operator[](this const Self, U)
|
||||||
#else
|
#else
|
||||||
template<valid_unit_for_dimension<Self> U>
|
template<valid_unit_for_dimension<Self> U>
|
||||||
[[nodiscard]] constexpr reference<Self, U> operator[](U) const
|
[[nodiscard]] constexpr auto operator[](U) const
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
return {};
|
return reference<Self{}, U{}>{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -213,9 +213,9 @@ template<DerivedDimensionSpec... Ds>
|
|||||||
struct derived_dimension : detail::derived_dimension_impl<Ds...> {
|
struct derived_dimension : detail::derived_dimension_impl<Ds...> {
|
||||||
template<typename Self, Unit U>
|
template<typename Self, Unit U>
|
||||||
requires valid_unit_for_dimension<U, Self> || (sizeof...(Ds) == 0 && convertible(U{}, one))
|
requires valid_unit_for_dimension<U, Self> || (sizeof...(Ds) == 0 && convertible(U{}, one))
|
||||||
[[nodiscard]] constexpr reference<Self, U> operator[](this const Self, U)
|
[[nodiscard]] constexpr auto operator[](this const Self, U)
|
||||||
{
|
{
|
||||||
return {};
|
return reference<Self{}, U{}>{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -228,9 +228,9 @@ template<DerivedDimensionSpec... Ds>
|
|||||||
struct derived_dimension<Ds...> : detail::derived_dimension_impl<Ds...> {
|
struct derived_dimension<Ds...> : detail::derived_dimension_impl<Ds...> {
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
requires valid_unit_for_dimension<U, derived_dimension> || (sizeof...(Ds) == 0 && convertible(U{}, one))
|
requires valid_unit_for_dimension<U, derived_dimension> || (sizeof...(Ds) == 0 && convertible(U{}, one))
|
||||||
[[nodiscard]] constexpr reference<derived_dimension, U> operator[](U) const
|
[[nodiscard]] constexpr auto operator[](U) const
|
||||||
{
|
{
|
||||||
return {};
|
return reference<derived_dimension{}, U{}>{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -239,9 +239,9 @@ struct derived_dimension<Self, D> : D {
|
|||||||
template<Unit U>
|
template<Unit U>
|
||||||
requires valid_unit_for_dimension<U, Self> ||
|
requires valid_unit_for_dimension<U, Self> ||
|
||||||
(convertible(derived_dimension{}, derived_dimension<>{}) && convertible(U{}, one))
|
(convertible(derived_dimension{}, derived_dimension<>{}) && convertible(U{}, one))
|
||||||
[[nodiscard]] constexpr reference<Self, U> operator[](U) const
|
[[nodiscard]] constexpr auto operator[](U) const
|
||||||
{
|
{
|
||||||
return {};
|
return reference<Self{}, U{}>{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -85,11 +85,11 @@ concept have_quantity_for_ = Quantity<Q> && (!Quantity<V>) && quantity_value_for
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept QuantityLike = requires(T q) {
|
concept QuantityLike = requires(T q) {
|
||||||
typename quantity_like_traits<T>::dimension;
|
quantity_like_traits<T>::dimension;
|
||||||
typename quantity_like_traits<T>::unit;
|
quantity_like_traits<T>::unit;
|
||||||
typename quantity_like_traits<T>::rep;
|
typename quantity_like_traits<T>::rep;
|
||||||
requires Dimension<typename quantity_like_traits<T>::dimension>;
|
requires Dimension<std::remove_const_t<decltype(quantity_like_traits<T>::dimension)>>;
|
||||||
requires Unit<typename quantity_like_traits<T>::unit>;
|
requires Unit<std::remove_const_t<decltype(quantity_like_traits<T>::unit)>>;
|
||||||
requires Representation<typename quantity_like_traits<T>::rep>;
|
requires Representation<typename quantity_like_traits<T>::rep>;
|
||||||
{
|
{
|
||||||
quantity_like_traits<T>::number(q)
|
quantity_like_traits<T>::number(q)
|
||||||
@@ -97,9 +97,8 @@ concept QuantityLike = requires(T q) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<QuantityLike Q>
|
template<QuantityLike Q>
|
||||||
using quantity_like_type =
|
using quantity_like_type = quantity<reference<quantity_like_traits<Q>::dimension, quantity_like_traits<Q>::unit>{},
|
||||||
quantity<reference<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit>{},
|
typename quantity_like_traits<Q>::rep>;
|
||||||
typename quantity_like_traits<Q>::rep>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A quantity
|
* @brief A quantity
|
||||||
@@ -352,42 +351,42 @@ public:
|
|||||||
[[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator+(const quantity& lhs, const Value& rhs)
|
||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires is_same_v<unit, units::one>;
|
requires unit == ::units::one;
|
||||||
requires invoke_result_convertible_to_<rep, std::plus<>, rep, Value>;
|
requires invoke_result_convertible_to_<rep, std::plus<>, rep, Value>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return units::quantity(lhs.number() + rhs);
|
return ::units::quantity(lhs.number() + rhs);
|
||||||
}
|
}
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const quantity& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const quantity& rhs)
|
||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires is_same_v<unit, units::one>;
|
requires unit == ::units::one;
|
||||||
requires invoke_result_convertible_to_<rep, std::plus<>, Value, rep>;
|
requires invoke_result_convertible_to_<rep, std::plus<>, Value, rep>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return units::quantity(lhs + rhs.number());
|
return ::units::quantity(lhs + rhs.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const Value& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator-(const quantity& lhs, const Value& rhs)
|
||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires is_same_v<unit, units::one>;
|
requires unit == ::units::one;
|
||||||
requires invoke_result_convertible_to_<rep, std::minus<>, rep, Value>;
|
requires invoke_result_convertible_to_<rep, std::minus<>, rep, Value>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return units::quantity(lhs.number() - rhs);
|
return ::units::quantity(lhs.number() - rhs);
|
||||||
}
|
}
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const quantity& rhs)
|
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const quantity& rhs)
|
||||||
requires requires { // TODO: Simplify when Clang catches up.
|
requires requires { // TODO: Simplify when Clang catches up.
|
||||||
requires !Quantity<Value>;
|
requires !Quantity<Value>;
|
||||||
requires is_same_v<unit, units::one>;
|
requires unit == ::units::one;
|
||||||
requires invoke_result_convertible_to_<rep, std::minus<>, Value, rep>;
|
requires invoke_result_convertible_to_<rep, std::minus<>, Value, rep>;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return units::quantity(lhs - rhs.number());
|
return ::units::quantity(lhs - rhs.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Representation Value>
|
template<Representation Value>
|
||||||
@@ -466,13 +465,13 @@ template<Representation Rep>
|
|||||||
explicit(false) quantity(Rep)->quantity<dimension_one[one], Rep>;
|
explicit(false) quantity(Rep)->quantity<dimension_one[one], Rep>;
|
||||||
|
|
||||||
template<QuantityLike Q>
|
template<QuantityLike Q>
|
||||||
explicit quantity(Q)
|
explicit quantity(Q) -> quantity<reference<quantity_like_traits<Q>::dimension, quantity_like_traits<Q>::unit>{},
|
||||||
-> quantity<reference<typename quantity_like_traits<Q>::dimension, typename quantity_like_traits<Q>::unit>{},
|
typename quantity_like_traits<Q>::rep>;
|
||||||
typename quantity_like_traits<Q>::rep>;
|
|
||||||
|
|
||||||
// non-member binary operators
|
// non-member binary operators
|
||||||
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>)
|
requires(convertible(Q1::reference, Q2::reference)) &&
|
||||||
|
quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
||||||
@@ -480,8 +479,9 @@ template<Quantity Q1, std::convertible_to<Q1> Q2>
|
|||||||
return ret(ret(lhs).number() + ret(rhs).number());
|
return ret(ret(lhs).number() + ret(rhs).number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>)
|
requires(convertible(Q1::reference, Q2::reference)) &&
|
||||||
|
quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
||||||
@@ -506,26 +506,28 @@ template<Quantity Q1, Quantity Q2>
|
|||||||
|
|
||||||
template<Quantity Q1, Quantity Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
||||||
(std::convertible_to<Q2, Q1> || quantity_of<Q2, dimension_one>) &&
|
(convertible(Q1::reference, Q2::reference) || quantity_of<Q2, dimension_one>) &&
|
||||||
(quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>)
|
quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||||
using ret = quantity<reference<typename Q1::dimension, typename Q1::unit>{},
|
using ret = quantity<reference<Q1::dimension, Q1::unit>{},
|
||||||
std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
|
std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
|
||||||
return ret(lhs.number() % rhs.number());
|
return ret(lhs.number() % rhs.number());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires std::three_way_comparable_with<typename Q1::rep, typename Q2::rep>
|
requires(convertible(Q1::reference, Q2::reference)) &&
|
||||||
|
std::three_way_comparable_with<typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr auto operator<=>(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
||||||
return quantity_cast<ref>(lhs).number() <=> quantity_cast<ref>(rhs).number();
|
return quantity_cast<ref{}>(lhs).number() <=> quantity_cast<ref{}>(rhs).number();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Quantity Q1, std::convertible_to<Q1> Q2>
|
template<Quantity Q1, Quantity Q2>
|
||||||
requires std::equality_comparable_with<typename Q1::rep, typename Q2::rep>
|
requires(convertible(Q1::reference, Q2::reference)) &&
|
||||||
|
std::equality_comparable_with<typename Q1::rep, typename Q2::rep>
|
||||||
[[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs)
|
[[nodiscard]] constexpr bool operator==(const Q1& lhs, const Q2& rhs)
|
||||||
{
|
{
|
||||||
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
using ref = std::common_type_t<decltype(Q1::reference), decltype(Q2::reference)>;
|
||||||
|
@@ -145,7 +145,7 @@ template<Dimension auto ToD, auto R, typename Rep>
|
|||||||
requires(convertible(ToD, R.dimension))
|
requires(convertible(ToD, R.dimension))
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
constexpr reference<std::remove_const_t<decltype(ToD)>, typename quantity<R, Rep>::unit_t> r;
|
constexpr reference<ToD, quantity<R, Rep>::unit> r;
|
||||||
return quantity_cast<quantity<r, Rep>>(q);
|
return quantity_cast<quantity<r, Rep>>(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ template<Unit auto ToU, auto R, typename Rep>
|
|||||||
requires(convertible(ToU, R.unit))
|
requires(convertible(ToU, R.unit))
|
||||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||||
{
|
{
|
||||||
constexpr reference<typename quantity<R, Rep>::dimension_t, std::remove_const_t<decltype(ToU)>> r;
|
constexpr reference<quantity<R, Rep>::dimension, ToU> r;
|
||||||
return quantity_cast<quantity<r, Rep>>(q);
|
return quantity_cast<quantity<r, Rep>>(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -67,31 +67,28 @@ namespace units {
|
|||||||
* The following syntaxes are not allowed:
|
* The following syntaxes are not allowed:
|
||||||
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
|
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
|
||||||
*/
|
*/
|
||||||
template<Dimension D, Unit U>
|
template<Dimension auto D, Unit auto U>
|
||||||
struct reference {
|
struct reference {
|
||||||
static constexpr D dimension{};
|
static constexpr auto dimension = D;
|
||||||
static constexpr U unit{};
|
static constexpr auto unit = U;
|
||||||
// static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reference
|
// Reference
|
||||||
|
|
||||||
template<Magnitude M, Reference R>
|
template<Magnitude M, Reference R>
|
||||||
[[nodiscard]] consteval reference<decltype(R::dimension), decltype(M{} * R::unit)> operator*(M, R)
|
[[nodiscard]] consteval reference<R::dimension, M{} * R::unit> operator*(M, R)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
template<Reference R1, Reference R2>
|
||||||
[[nodiscard]] consteval reference<decltype(R1::dimension * R2::dimension), decltype(R1::unit * R2::unit)> operator*(R1,
|
[[nodiscard]] consteval reference<R1::dimension * R2::dimension, R1::unit * R2::unit> operator*(R1, R2)
|
||||||
R2)
|
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
template<Reference R1, Reference R2>
|
||||||
[[nodiscard]] consteval reference<decltype(R1::dimension / R2::dimension), decltype(R1::unit / R2::unit)> operator/(R1,
|
[[nodiscard]] consteval reference<R1::dimension / R2::dimension, R1::unit / R2::unit> operator/(R1, R2)
|
||||||
R2)
|
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -119,7 +116,7 @@ struct system_reference {
|
|||||||
|
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
requires(convertible(coherent_unit, U{}))
|
requires(convertible(coherent_unit, U{}))
|
||||||
[[nodiscard]] constexpr reference<std::remove_const_t<decltype(dimension)>, U> operator[](U) const
|
[[nodiscard]] constexpr reference<dimension, U{}> operator[](U) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -139,7 +136,7 @@ private:
|
|||||||
using dim = common_type_t<remove_const_t<decltype(R1::dimension)>, remove_const_t<decltype(R2::dimension)>>;
|
using dim = common_type_t<remove_const_t<decltype(R1::dimension)>, remove_const_t<decltype(R2::dimension)>>;
|
||||||
using unit = common_type_t<remove_const_t<decltype(R1::unit)>, remove_const_t<decltype(R2::unit)>>;
|
using unit = common_type_t<remove_const_t<decltype(R1::unit)>, remove_const_t<decltype(R2::unit)>>;
|
||||||
public:
|
public:
|
||||||
using type = units::reference<dim, unit>;
|
using type = units::reference<dim{}, unit{}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
@@ -91,24 +91,25 @@ inline constexpr struct kilometre_ : decltype(si::kilo<metre>) {} kilometre;
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Named quantity/dimension and unit
|
// Named quantity/dimension and unit
|
||||||
static_assert(is_same_v<decltype(5 * power[watt]), quantity<reference<power_, watt_>{}, int>>);
|
static_assert(is_same_v<decltype(5 * power[watt]), quantity<reference<power, watt>{}, int>>);
|
||||||
|
|
||||||
// Named quantity/dimension and derived (unnamed) unit
|
// Named quantity/dimension and derived (unnamed) unit
|
||||||
static_assert(is_same_v<decltype(5 * speed[metre / second]),
|
static_assert(is_same_v<decltype(5 * speed[metre / second]),
|
||||||
quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
|
quantity<reference<speed, derived_unit<metre_, per<second_>>{}>{}, int>>);
|
||||||
|
|
||||||
// Derived (unnamed) quantity/dimension and derived (unnamed) unit
|
// Derived (unnamed) quantity/dimension and derived (unnamed) unit
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(10 * length[metre] / (2 * time[second])),
|
is_same_v<
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<metre_, per<second_>>>{}, int>>);
|
decltype(10 * length[metre] / (2 * time[second])),
|
||||||
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<metre_, per<second_>>{}>{}, int>>);
|
||||||
|
|
||||||
// Base quantity as a result of dimensional transformation
|
// Base quantity as a result of dimensional transformation
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(5 * speed[metre / second] * (5 * time[second])), quantity<reference<length_, metre_>{}, int>>);
|
is_same_v<decltype(5 * speed[metre / second] * (5 * time[second])), quantity<reference<length, metre>{}, int>>);
|
||||||
|
|
||||||
// dimension_one
|
// dimension_one
|
||||||
static_assert(is_same_v<decltype(20 * speed[metre / second] / (10 * length[metre]) * (5 * time[second])),
|
static_assert(is_same_v<decltype(20 * speed[metre / second] / (10 * length[metre]) * (5 * time[second])),
|
||||||
quantity<reference<dimension_one_, one_>{}, int>>);
|
quantity<reference<dimension_one, one>{}, int>>);
|
||||||
|
|
||||||
template<auto s>
|
template<auto s>
|
||||||
concept invalid_operations = requires {
|
concept invalid_operations = requires {
|
||||||
@@ -139,53 +140,58 @@ concept invalid_operations = requires {
|
|||||||
static_assert(invalid_operations<time[second]>);
|
static_assert(invalid_operations<time[second]>);
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(2 * length[metre] / (1 * time[second])),
|
is_same_v<
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<metre_, per<second_>>>{}, int>>);
|
decltype(2 * length[metre] / (1 * time[second])),
|
||||||
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<metre_, per<second_>>{}>{}, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(2 * (length[metre] / time[second])),
|
is_same_v<
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<metre_, per<second_>>>{}, int>>);
|
decltype(2 * (length[metre] / time[second])),
|
||||||
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<metre_, per<second_>>{}>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(2 * (speed[metre / second])),
|
static_assert(is_same_v<decltype(2 * (speed[metre / second])),
|
||||||
quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
|
quantity<reference<speed, derived_unit<metre_, per<second_>>{}>{}, int>>);
|
||||||
|
|
||||||
constexpr auto m_per_s = speed[metre / second];
|
constexpr auto m_per_s = speed[metre / second];
|
||||||
static_assert(is_same_v<decltype(2 * m_per_s), quantity<reference<speed_, derived_unit<metre_, per<second_>>>{}, int>>);
|
static_assert(
|
||||||
|
is_same_v<decltype(2 * m_per_s), quantity<reference<speed, derived_unit<metre_, per<second_>>{}>{}, int>>);
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<decltype(120 * length[kilometre] / (2 * time[hour])),
|
is_same_v<
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, int>>);
|
decltype(120 * length[kilometre] / (2 * time[hour])),
|
||||||
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<kilometre_, per<hour_>>{}>{}, int>>);
|
||||||
static_assert(120 * length[kilometre] / (2 * time[hour]) == 60 * speed[kilometre / hour]);
|
static_assert(120 * length[kilometre] / (2 * time[hour]) == 60 * speed[kilometre / hour]);
|
||||||
static_assert(
|
|
||||||
is_same_v<decltype([] {
|
|
||||||
const auto distance = 120;
|
|
||||||
const auto duration = 2;
|
|
||||||
return distance * length[kilometre] / (duration * time[hour]);
|
|
||||||
}()),
|
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, int>>);
|
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<
|
is_same_v<
|
||||||
decltype(std::int64_t{120} * length[kilometre] / (2 * time[hour])),
|
decltype([] {
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, std::int64_t>>);
|
const auto distance = 120;
|
||||||
|
const auto duration = 2;
|
||||||
|
return distance * length[kilometre] / (duration * time[hour]);
|
||||||
|
}()),
|
||||||
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<kilometre_, per<hour_>>{}>{}, int>>);
|
||||||
static_assert(
|
static_assert(
|
||||||
is_same_v<
|
is_same_v<decltype(std::int64_t{120} * length[kilometre] / (2 * time[hour])),
|
||||||
decltype(120.L * length[kilometre] / (2 * time[hour])),
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<kilometre_, per<hour_>>{}>{},
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, derived_unit<kilometre_, per<hour_>>>{}, long double>>);
|
std::int64_t>>);
|
||||||
|
static_assert(
|
||||||
|
is_same_v<decltype(120.L * length[kilometre] / (2 * time[hour])),
|
||||||
|
quantity<reference<derived_dimension<length_, per<time_>>{}, derived_unit<kilometre_, per<hour_>>{}>{},
|
||||||
|
long double>>);
|
||||||
|
|
||||||
static_assert(is_same_v<decltype(1. / 4 * area[square<metre>]), decltype(1. * area[square<metre>] / 4)>);
|
static_assert(is_same_v<decltype(1. / 4 * area[square<metre>]), decltype(1. * area[square<metre>] / 4)>);
|
||||||
static_assert(1. / 4 * area[square<metre>] == 1. * area[square<metre>] / 4);
|
static_assert(1. / 4 * area[square<metre>] == 1. * area[square<metre>] / 4);
|
||||||
|
|
||||||
// Natural Units
|
// Natural Units
|
||||||
static_assert(is_same_v<decltype(42 * nu::time[nu::second]), quantity<reference<time_, nu::second_>{}, int>>);
|
static_assert(is_same_v<decltype(42 * nu::time[nu::second]), quantity<reference<time, nu::second>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * nu::time[nu::minute]), quantity<reference<time_, nu::minute_>{}, int>>);
|
static_assert(is_same_v<decltype(42 * nu::time[nu::minute]), quantity<reference<time, nu::minute>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * nu::length[nu::second]), quantity<reference<length_, nu::second_>{}, int>>);
|
static_assert(is_same_v<decltype(42 * nu::length[nu::second]), quantity<reference<length, nu::second>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * nu::length[nu::minute]), quantity<reference<length_, nu::minute_>{}, int>>);
|
static_assert(is_same_v<decltype(42 * nu::length[nu::minute]), quantity<reference<length, nu::minute>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * (nu::length[nu::second] / nu::time[nu::second])),
|
static_assert(is_same_v<decltype(42 * (nu::length[nu::second] / nu::time[nu::second])),
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, one_>{}, int>>);
|
quantity<reference<derived_dimension<length_, per<time_>>{}, one>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * nu::length[nu::second] / (42 * nu::time[nu::second])),
|
static_assert(is_same_v<decltype(42 * nu::length[nu::second] / (42 * nu::time[nu::second])),
|
||||||
quantity<reference<derived_dimension<length_, per<time_>>, one_>{}, int>>);
|
quantity<reference<derived_dimension<length_, per<time_>>{}, one>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * nu::speed[nu::second / nu::second]), quantity<reference<speed_, one_>{}, int>>);
|
static_assert(is_same_v<decltype(42 * nu::speed[nu::second / nu::second]), quantity<reference<speed, one>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * nu::speed[one]), quantity<reference<speed_, one_>{}, int>>);
|
static_assert(is_same_v<decltype(42 * nu::speed[one]), quantity<reference<speed, one>{}, int>>);
|
||||||
static_assert(is_same_v<decltype(42 * mass[kilogram] * (1 * nu::length[nu::second]) / (1 * nu::time[nu::second])),
|
static_assert(is_same_v<decltype(42 * mass[kilogram] * (1 * nu::length[nu::second]) / (1 * nu::time[nu::second])),
|
||||||
quantity<reference<derived_dimension<length_, mass_, per<time_>>, kilogram_>{}, int>>);
|
quantity<reference<derived_dimension<length_, mass_, per<time_>>{}, kilogram>{}, int>>);
|
||||||
|
|
||||||
template<auto dim, auto unit>
|
template<auto dim, auto unit>
|
||||||
concept invalid_nu_unit = !requires { dim[unit]; };
|
concept invalid_nu_unit = !requires { dim[unit]; };
|
||||||
|
Reference in New Issue
Block a user