mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-03 20:34:26 +02:00
refactor: RepresentationOf
concept usage added + quantity
concepts cleanup
This commit is contained in:
@@ -36,18 +36,12 @@ UNITS_DIAGNOSTIC_IGNORE_LOSS_OF_DATA
|
||||
|
||||
namespace units {
|
||||
|
||||
template<Reference auto R, Representation Rep>
|
||||
template<Reference auto R, RepresentationOf<R.quantity_spec.character> Rep>
|
||||
class quantity;
|
||||
|
||||
// template<PointOrigin O, UnitOf<typename O::dimension> U, Representation Rep>
|
||||
// class quantity_point;
|
||||
|
||||
// template<Kind K, UnitOf<typename K::dimension> U, Representation Rep>
|
||||
// class quantity_kind;
|
||||
|
||||
// template<PointKind PK, UnitOf<typename PK::dimension> U, Representation Rep>
|
||||
// class quantity_point_kind;
|
||||
|
||||
/**
|
||||
* @brief Explicit cast of a quantity
|
||||
*
|
||||
@@ -180,7 +174,7 @@ template<Unit auto ToU, auto R, typename Rep>
|
||||
* @tparam ToRep a representation type to use for a target quantity
|
||||
*/
|
||||
template<Representation ToRep, auto R, typename Rep>
|
||||
requires std::constructible_from<ToRep, Rep>
|
||||
requires RepresentationOf<ToRep, R.quantity_spec.character> && std::constructible_from<ToRep, Rep>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<R, Rep>& q)
|
||||
{
|
||||
return quantity_cast<quantity<R, ToRep>>(q);
|
||||
@@ -240,128 +234,6 @@ template<Representation ToRep, auto R, typename Rep>
|
||||
// return quantity_point_cast<quantity_point<rebind_point_origin_dimension<O, ToD>, ToU, Rep>>(q);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Explicit cast of a quantity kind
|
||||
// *
|
||||
// * Implicit conversions between quantity kinds of different types are allowed only for "safe"
|
||||
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||
// *
|
||||
// * This cast gets the target (quantity) kind type to cast to or anything that works for quantity_cast. For example:
|
||||
// *
|
||||
// * auto q1 = units::quantity_kind_cast<decltype(ns::width{1 * m})>(quantity_kind{ns::width{1 * mm});
|
||||
// * auto q1 = units::quantity_kind_cast<ns::height_kind>(ns::width{1 * m});
|
||||
// * auto q1 = units::quantity_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::width{1 * mm});
|
||||
// * auto q1 = units::quantity_kind_cast<units::isq::si::dim_acceleration>(ns::rate_of_climb{200 * Gal});
|
||||
// * auto q1 = units::quantity_kind_cast<units::isq::si::metre>(ns::width{1 * mm});
|
||||
// * auto q1 = units::quantity_kind_cast<int>(ns::width{1.0 * mm});
|
||||
// *
|
||||
// * @tparam CastSpec a target (quantity) kind type to cast to or anything that works for quantity_cast
|
||||
// */
|
||||
// template<typename CastSpec, typename K, typename U, typename Rep>
|
||||
// [[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
||||
// requires requires {
|
||||
// requires is_specialization_of<CastSpec, quantity_kind>;
|
||||
// requires requires { quantity_cast<typename CastSpec::quantity_type>(qk.common()); };
|
||||
// } || requires {
|
||||
// requires Kind<CastSpec>;
|
||||
// requires UnitOf<U, typename CastSpec::dimension>;
|
||||
// } || requires { quantity_cast<CastSpec>(qk.common()); } // TODO: Simplify when Clang catches up.
|
||||
// {
|
||||
// if constexpr (is_specialization_of<CastSpec, quantity_kind>)
|
||||
// return CastSpec(quantity_cast<typename CastSpec::quantity_type>(qk.common()));
|
||||
// else if constexpr (Kind<CastSpec>)
|
||||
// return quantity_kind<CastSpec, U, Rep>(qk.common());
|
||||
// else {
|
||||
// auto q{quantity_cast<CastSpec>(qk.common())};
|
||||
// using Q = decltype(q);
|
||||
// return quantity_kind<K, typename Q::unit, typename Q::rep>(static_cast<Q&&>(q));
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Explicit cast of a quantity kind
|
||||
// *
|
||||
// * Implicit conversions between quantity kinds of different types are allowed only for "safe"
|
||||
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||
// *
|
||||
// * This cast gets both the target kind and unit to cast to. For example:
|
||||
// *
|
||||
// * auto q1 = units::quantity_kind_cast<ns::height_kind, units::isq::si::kilometre>(w);
|
||||
// *
|
||||
// * @note This cast is especially useful when working with quantity kinds of unknown kind.
|
||||
// *
|
||||
// * @tparam ToK the kind type to use for the target quantity
|
||||
// * @tparam ToU the unit type to use for the target quantity
|
||||
// */
|
||||
// template<Kind ToK, Unit ToU, typename K, typename U, typename Rep>
|
||||
// requires equivalent<typename ToK::dimension, typename K::dimension> && UnitOf<ToU, typename ToK::dimension>
|
||||
// [[nodiscard]] constexpr QuantityKind auto quantity_kind_cast(const quantity_kind<K, U, Rep>& qk)
|
||||
// {
|
||||
// return quantity_kind_cast<quantity_kind<ToK, ToU, Rep>>(qk);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Explicit cast of a quantity point kind
|
||||
// *
|
||||
// * Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
||||
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||
// *
|
||||
// * This cast gets the target (quantity) point kind type to cast to or anything that works for quantity_kind_cast.
|
||||
// For
|
||||
// * example:
|
||||
// *
|
||||
// * auto q1 = units::quantity_point_kind_cast<decltype(ns::x_coordinate{1 * m))>(ns::x_coordinate{1 * mm});
|
||||
// * auto q1 = units::quantity_point_kind_cast<decltype(ns::width{1 * m})>(ns::x_coordinate{1 * mm});
|
||||
// * auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind>(ns::x_coordinate{1 * m});
|
||||
// * auto q1 = units::quantity_point_kind_cast<ns::height_kind>(ns::x_coordinate{1 * m});
|
||||
// * auto q1 = units::quantity_point_kind_cast<units::isq::si::length<units::isq::si::metre>>(ns::x_coordinate{1 *
|
||||
// mm});
|
||||
// * auto q1 =
|
||||
// units::quantity_point_kind_cast<units::isq::si::dim_acceleration>(quantity_point_kind(ns::rate_of_climb{200
|
||||
// * * Gal})); auto q1 = units::quantity_point_kind_cast<units::isq::si::metre>(ns::x_coordinate{1 * mm}); auto q1 =
|
||||
// * units::quantity_point_kind_cast<int>(ns::x_coordinate{1.0 * mm});
|
||||
// *
|
||||
// * @tparam CastSpec a target (quantity) point kind type to cast to or anything that works for quantity_kind_cast
|
||||
// */
|
||||
// template<typename CastSpec, typename PK, typename U, typename Rep>
|
||||
// [[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
||||
// requires requires {
|
||||
// requires is_specialization_of<CastSpec, quantity_point_kind>;
|
||||
// requires requires { quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()); };
|
||||
// requires equivalent<typename PK::origin, typename CastSpec::point_kind_type::origin>;
|
||||
// } || requires { requires PointKind<CastSpec> && UnitOf<U, typename CastSpec::dimension>; } ||
|
||||
// requires { quantity_kind_cast<CastSpec>(qpk.relative()); } // TODO: Simplify when Clang catches up.
|
||||
// {
|
||||
// if constexpr (is_specialization_of<CastSpec, quantity_point_kind>)
|
||||
// return CastSpec(quantity_kind_cast<typename CastSpec::quantity_kind_type>(qpk.relative()));
|
||||
// else if constexpr (PointKind<CastSpec>)
|
||||
// return quantity_point_kind(quantity_kind_cast<typename CastSpec::base_kind>(qpk.relative()));
|
||||
// else
|
||||
// return quantity_point_kind(quantity_kind_cast<CastSpec>(qpk.relative()));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @brief Explicit cast of a quantity point kind
|
||||
// *
|
||||
// * Implicit conversions between quantity point kinds of different types are allowed only for "safe"
|
||||
// * (i.e. non-truncating) conversion. In other cases an explicit cast has to be used.
|
||||
// *
|
||||
// * This cast gets both the target point kind and unit to cast to. For example:
|
||||
// *
|
||||
// * auto q1 = units::quantity_point_kind_cast<ns::y_coordinate_kind, units::isq::si::kilometre>(x);
|
||||
// *
|
||||
// * @note This cast is especially useful when working with quantity point kinds of unknown point kind.
|
||||
// *
|
||||
// * @tparam ToPK the point kind type to use for the target quantity
|
||||
// * @tparam ToU the unit type to use for the target quantity
|
||||
// */
|
||||
// template<PointKind ToPK, Unit ToU, typename PK, typename U, typename Rep>
|
||||
// requires equivalent<typename ToPK::dimension, typename PK::dimension> && UnitOf<ToU, typename ToPK::dimension>
|
||||
// [[nodiscard]] constexpr QuantityPointKind auto quantity_point_kind_cast(const quantity_point_kind<PK, U, Rep>& qpk)
|
||||
// {
|
||||
// return quantity_point_kind_cast<quantity_point_kind<ToPK, ToU, Rep>>(qpk);
|
||||
// }
|
||||
|
||||
} // namespace units
|
||||
|
||||
UNITS_DIAGNOSTIC_POP
|
||||
|
@@ -126,4 +126,17 @@ concept weak_quantity_of = Quantity<Q> &&
|
||||
(Reference<std::remove_const_t<decltype(V)>> && Q::dimension == V.dimension &&
|
||||
Q::unit == V.unit));
|
||||
|
||||
template<typename T>
|
||||
concept quantity_like = requires(T q) {
|
||||
quantity_like_traits<T>::dimension;
|
||||
quantity_like_traits<T>::unit;
|
||||
typename quantity_like_traits<T>::rep;
|
||||
requires Dimension<std::remove_const_t<decltype(quantity_like_traits<T>::dimension)>>;
|
||||
requires Unit<std::remove_const_t<decltype(quantity_like_traits<T>::unit)>>;
|
||||
requires Representation<typename quantity_like_traits<T>::rep>;
|
||||
{
|
||||
quantity_like_traits<T>::number(q)
|
||||
} -> std::convertible_to<typename quantity_like_traits<T>::rep>;
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
@@ -47,18 +47,13 @@ inline constexpr auto make_quantity = [](Representation auto&& v) {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept quantity_one = Quantity<T> && (T::dimension == dimension_one) && (T::unit == one);
|
||||
concept quantity_one = quantity_of<T, dimensionless[one]>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
concept floating_point_ = // exposition only
|
||||
(Quantity<T> && treat_as_floating_point<typename T::rep>) || (!Quantity<T> && treat_as_floating_point<T>);
|
||||
|
||||
template<typename T, typename Arg>
|
||||
concept rep_safe_constructible_from_ = // exposition only
|
||||
(!Quantity<std::remove_cvref_t<Arg>>) && std::constructible_from<T, Arg> &&
|
||||
(floating_point_<T> || (!floating_point_<Arg>));
|
||||
std::constructible_from<T, Arg> && (treat_as_floating_point<T> || !treat_as_floating_point<Arg>);
|
||||
|
||||
// QFrom ratio is an exact multiple of QTo
|
||||
template<typename QFrom, typename QTo>
|
||||
@@ -69,32 +64,14 @@ concept harmonic_ = // exposition only
|
||||
template<typename QFrom, typename QTo>
|
||||
concept quantity_convertible_to_ = // exposition only
|
||||
Quantity<QFrom> && Quantity<QTo> && requires(QFrom q) { quantity_cast<QTo>(q); } &&
|
||||
(floating_point_<QTo> || (!floating_point_<QFrom> && harmonic_<QFrom, QTo>));
|
||||
(treat_as_floating_point<typename QTo::rep> ||
|
||||
(!treat_as_floating_point<typename QFrom::rep> && harmonic_<QFrom, QTo>));
|
||||
|
||||
template<typename Func, typename T, typename U>
|
||||
concept quantity_value_for_ = std::regular_invocable<Func, T, U> && Representation<std::invoke_result_t<Func, T, U>>;
|
||||
template<quantity_character Ch, typename Func, typename T, typename U>
|
||||
concept invoke_result_of_ =
|
||||
std::regular_invocable<Func, T, U> && RepresentationOf<std::invoke_result_t<Func, T, U>, Ch>;
|
||||
|
||||
template<typename T, typename Func, typename U, typename V>
|
||||
concept invoke_result_convertible_to_ = Representation<T> && quantity_value_for_<Func, U, V> &&
|
||||
rep_safe_constructible_from_<std::invoke_result_t<Func, U, V>, T>;
|
||||
|
||||
template<typename Func, typename Q, typename V>
|
||||
concept have_quantity_for_ = Quantity<Q> && (!Quantity<V>) && quantity_value_for_<Func, typename Q::rep, V>;
|
||||
|
||||
template<typename T>
|
||||
concept QuantityLike = requires(T q) {
|
||||
quantity_like_traits<T>::dimension;
|
||||
quantity_like_traits<T>::unit;
|
||||
typename quantity_like_traits<T>::rep;
|
||||
requires Dimension<std::remove_const_t<decltype(quantity_like_traits<T>::dimension)>>;
|
||||
requires Unit<std::remove_const_t<decltype(quantity_like_traits<T>::unit)>>;
|
||||
requires Representation<typename quantity_like_traits<T>::rep>;
|
||||
{
|
||||
quantity_like_traits<T>::number(q)
|
||||
} -> std::convertible_to<typename quantity_like_traits<T>::rep>;
|
||||
};
|
||||
|
||||
template<QuantityLike Q>
|
||||
template<quantity_like Q>
|
||||
using quantity_like_type = quantity<reference<quantity_like_traits<Q>::dimension, quantity_like_traits<Q>::unit>{},
|
||||
typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
@@ -108,7 +85,7 @@ using quantity_like_type = quantity<reference<quantity_like_traits<Q>::dimension
|
||||
* @tparam U a measurement unit of the quantity
|
||||
* @tparam Rep a type to be used to represent values of a quantity
|
||||
*/
|
||||
template<Reference auto R, Representation Rep = double>
|
||||
template<Reference auto R, RepresentationOf<R.quantity_spec.character> Rep = double>
|
||||
class quantity {
|
||||
Rep number_;
|
||||
public:
|
||||
@@ -160,7 +137,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
template<QuantityLike Q>
|
||||
template<quantity_like Q>
|
||||
requires quantity_convertible_to_<quantity_like_type<Q>, quantity>
|
||||
constexpr explicit quantity(const Q& q) : quantity(quantity_like_type<Q>(quantity_like_traits<Q>::number(q)))
|
||||
{
|
||||
@@ -315,7 +292,7 @@ public:
|
||||
|
||||
template<typename Rep2>
|
||||
constexpr quantity& operator%=(const Rep2& rhs)
|
||||
requires(!floating_point_<rep>) && (!floating_point_<Rep2>) && requires(rep a, const Rep2 b) {
|
||||
requires(!treat_as_floating_point<rep>) && (!treat_as_floating_point<Rep2>) && requires(rep a, const Rep2 b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
@@ -328,7 +305,8 @@ public:
|
||||
|
||||
template<detail::quantity_one Q>
|
||||
constexpr quantity& operator%=(const Q& rhs)
|
||||
requires(!floating_point_<rep>) && (!floating_point_<typename Q::rep>) && requires(rep a, const typename Q::rep b) {
|
||||
requires(!treat_as_floating_point<rep>) && (!treat_as_floating_point<typename Q::rep>) &&
|
||||
requires(rep a, const typename Q::rep b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
@@ -340,7 +318,7 @@ public:
|
||||
}
|
||||
|
||||
constexpr quantity& operator%=(const quantity& q)
|
||||
requires(!floating_point_<rep>) && requires(rep a, rep b) {
|
||||
requires(!treat_as_floating_point<rep>) && requires(rep a, rep b) {
|
||||
{
|
||||
a %= b
|
||||
} -> std::same_as<rep&>;
|
||||
@@ -358,17 +336,18 @@ public:
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires unit == ::units::one;
|
||||
requires invoke_result_convertible_to_<rep, std::plus<>, rep, Value>;
|
||||
requires invoke_result_of_<R.quantity_spec.character, std::plus<>, rep, Value>;
|
||||
}
|
||||
{
|
||||
return ::units::quantity(lhs.number() + rhs);
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator+(const Value& lhs, const quantity& rhs)
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires unit == ::units::one;
|
||||
requires invoke_result_convertible_to_<rep, std::plus<>, Value, rep>;
|
||||
requires invoke_result_of_<R.quantity_spec.character, std::plus<>, Value, rep>;
|
||||
}
|
||||
{
|
||||
return ::units::quantity(lhs + rhs.number());
|
||||
@@ -379,24 +358,25 @@ public:
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires unit == ::units::one;
|
||||
requires invoke_result_convertible_to_<rep, std::minus<>, rep, Value>;
|
||||
requires invoke_result_of_<R.quantity_spec.character, std::minus<>, rep, Value>;
|
||||
}
|
||||
{
|
||||
return ::units::quantity(lhs.number() - rhs);
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator-(const Value& lhs, const quantity& rhs)
|
||||
requires requires { // TODO: Simplify when Clang catches up.
|
||||
requires !Quantity<Value>;
|
||||
requires unit == ::units::one;
|
||||
requires invoke_result_convertible_to_<rep, std::minus<>, Value, rep>;
|
||||
requires invoke_result_of_<R.quantity_spec.character, std::minus<>, Value, rep>;
|
||||
}
|
||||
{
|
||||
return ::units::quantity(lhs - rhs.number());
|
||||
}
|
||||
|
||||
template<Representation Value>
|
||||
requires invoke_result_convertible_to_<rep, std::multiplies<>, rep, const Value&>
|
||||
requires invoke_result_of_<R.quantity_spec.character, std::multiplies<>, rep, const Value&>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator*(const quantity& q, const Value& v)
|
||||
{
|
||||
using ret = quantity<R, std::invoke_result_t<std::multiplies<>, rep, Value>>;
|
||||
@@ -404,7 +384,7 @@ public:
|
||||
}
|
||||
|
||||
template<Representation Value>
|
||||
requires invoke_result_convertible_to_<rep, std::multiplies<>, const Value&, rep>
|
||||
requires invoke_result_of_<R.quantity_spec.character, std::multiplies<>, const Value&, rep>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator*(const Value& v, const quantity& q)
|
||||
{
|
||||
using ret = quantity<R, std::invoke_result_t<std::multiplies<>, Value, rep>>;
|
||||
@@ -412,7 +392,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
requires(!Quantity<Value>) && invoke_result_convertible_to_<rep, std::divides<>, rep, const Value&>
|
||||
requires(!Quantity<Value>) && invoke_result_of_<R.quantity_spec.character, std::divides<>, rep, const Value&>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator/(const quantity& q, const Value& v)
|
||||
{
|
||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||
@@ -421,15 +401,15 @@ public:
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
requires(!Quantity<Value>) && invoke_result_convertible_to_<rep, std::divides<>, const Value&, rep>
|
||||
requires(!Quantity<Value>) && invoke_result_of_<R.quantity_spec.character, std::divides<>, const Value&, rep>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& v, const quantity& q)
|
||||
{
|
||||
return detail::make_quantity<dimensionless[::units::one] / reference>(v / q.number());
|
||||
}
|
||||
|
||||
template<typename Value>
|
||||
requires(!Quantity<Value>) && (!floating_point_<rep>) &&
|
||||
(!floating_point_<Value>) && invoke_result_convertible_to_<rep, std::modulus<>, rep, const Value&>
|
||||
requires(!Quantity<Value>) && (!treat_as_floating_point<rep>) && (!treat_as_floating_point<Value>) &&
|
||||
invoke_result_of_<R.quantity_spec.character, std::modulus<>, rep, const Value&>
|
||||
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& q, const Value& v)
|
||||
{
|
||||
gsl_ExpectsAudit(v != quantity_values<Value>::zero());
|
||||
@@ -438,7 +418,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr Quantity auto operator%(const quantity& lhs, const quantity& rhs)
|
||||
requires(!floating_point_<rep>) && invoke_result_convertible_to_<rep, std::modulus<>, rep, rep>
|
||||
requires(!treat_as_floating_point<rep>) && invoke_result_of_<R.quantity_spec.character, std::modulus<>, rep, rep>
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<rep>::zero());
|
||||
using ret = quantity<R, std::invoke_result_t<std::modulus<>, rep, rep>>;
|
||||
@@ -447,7 +427,7 @@ public:
|
||||
|
||||
[[nodiscard]] friend constexpr auto operator<=>(const quantity& lhs, const quantity& rhs)
|
||||
requires std::three_way_comparable<rep>
|
||||
#if UNITS_COMP_GCC == 10 && UNITS_COMP_GCC_MINOR >= 2
|
||||
#if __cpp_impl_three_way_comparison
|
||||
= default;
|
||||
#else
|
||||
{
|
||||
@@ -462,17 +442,23 @@ public:
|
||||
template<auto R, typename Rep>
|
||||
explicit(false) quantity(quantity<R, Rep>) -> quantity<R, Rep>;
|
||||
|
||||
template<Representation Rep>
|
||||
explicit(false) quantity(Rep)->quantity<dimensionless[one], Rep>;
|
||||
template<RepresentationOf<units::quantity_character::scalar> Rep>
|
||||
explicit(false) quantity(Rep) -> quantity<dimensionless[one], Rep>;
|
||||
|
||||
template<QuantityLike Q>
|
||||
#if !UNITS_COMP_CLANG || UNITS_COMP_CLANG > 16
|
||||
template<auto R, RepresentationOf<R.quantity_spec.character> Rep>
|
||||
explicit(false) quantity(Rep&&) -> quantity<R, Rep>;
|
||||
#endif
|
||||
|
||||
template<quantity_like Q>
|
||||
explicit quantity(Q) -> quantity<reference<quantity_like_traits<Q>::dimension, quantity_like_traits<Q>::unit>{},
|
||||
typename quantity_like_traits<Q>::rep>;
|
||||
|
||||
// non-member binary operators
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires(interconvertible(Q1::reference, Q2::reference)) &&
|
||||
quantity_value_for_<std::plus<>, typename Q1::rep, typename Q2::rep>
|
||||
invoke_result_of_<common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character, std::plus<>,
|
||||
typename Q1::rep, typename Q2::rep>
|
||||
[[nodiscard]] constexpr Quantity auto operator+(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||
@@ -482,7 +468,8 @@ template<Quantity Q1, Quantity Q2>
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires(interconvertible(Q1::reference, Q2::reference)) &&
|
||||
quantity_value_for_<std::minus<>, typename Q1::rep, typename Q2::rep>
|
||||
invoke_result_of_<common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec).character, std::minus<>,
|
||||
typename Q1::rep, typename Q2::rep>
|
||||
[[nodiscard]] constexpr Quantity auto operator-(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
constexpr auto ref = common_reference(Q1::reference, Q2::reference);
|
||||
@@ -491,14 +478,16 @@ template<Quantity Q1, Quantity Q2>
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires quantity_value_for_<std::multiplies<>, typename Q1::rep, typename Q2::rep>
|
||||
requires invoke_result_of_<(Q1::quantity_spec * Q2::quantity_spec).character, std::multiplies<>, typename Q1::rep,
|
||||
typename Q2::rep>
|
||||
[[nodiscard]] constexpr Quantity auto operator*(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
return detail::make_quantity<Q1::reference * Q2::reference>(lhs.number() * rhs.number());
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires quantity_value_for_<std::divides<>, typename Q1::rep, typename Q2::rep>
|
||||
requires invoke_result_of_<(Q1::quantity_spec / Q2::quantity_spec).character, std::divides<>, typename Q1::rep,
|
||||
typename Q2::rep>
|
||||
[[nodiscard]] constexpr Quantity auto operator/(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||
@@ -506,14 +495,13 @@ template<Quantity Q1, Quantity Q2>
|
||||
}
|
||||
|
||||
template<Quantity Q1, Quantity Q2>
|
||||
requires(!floating_point_<typename Q1::rep>) && (!floating_point_<typename Q2::rep>) &&
|
||||
(interconvertible(Q1::reference, Q2::reference) || quantity_of<Q2, dimension_one>) &&
|
||||
quantity_value_for_<std::modulus<>, typename Q1::rep, typename Q2::rep>
|
||||
requires(!treat_as_floating_point<typename Q1::rep>) && (!treat_as_floating_point<typename Q2::rep>) &&
|
||||
(interconvertible(Q1::reference, Q2::reference) || quantity_of<Q2, dimensionless>) &&
|
||||
invoke_result_of_<Q1::reference.character, std::modulus<>, typename Q1::rep, typename Q2::rep>
|
||||
[[nodiscard]] constexpr Quantity auto operator%(const Q1& lhs, const Q2& rhs)
|
||||
{
|
||||
gsl_ExpectsAudit(rhs.number() != quantity_values<typename Q2::rep>::zero());
|
||||
using ret = quantity<reference<Q1::dimension, Q1::unit>{},
|
||||
std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
|
||||
using ret = quantity<Q1::reference, std::invoke_result_t<std::modulus<>, typename Q1::rep, typename Q2::rep>>;
|
||||
return ret(lhs.number() % rhs.number());
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user