5 Quantities and units library [quantities]

5.6 Quantity [qty]

5.6.1 General [qty.general]

Subclause [qty] describes the class template quantity that represents the value of a quantity (IEC 60050, 112-01-28) that is an element of a vector space (IEC 60050, 102-03-01,102-03-04).

5.6.2 Interoperability [qty.like]

The interfaces specified in this subclause and subclause [qty.pt.like] are used by quantity and quantity_point to specify conversions with other types representing quantities.
[Note 1: 
[qty.chrono] implements them for std​::​chrono​::​duration and std​::​chrono​::​time_point.
— end note]
template<typename T, template<typename> typename Traits> concept qty-like-impl = requires(const T& qty, const Traits<T>::rep& num) { // exposition only { Traits<T>::to_numerical_value(qty) } -> std::same_as<typename Traits<T>::rep>; { Traits<T>::from_numerical_value(num) } -> std::same_as<T>; requires std::same_as<decltype(Traits<T>::explicit_import), const bool>; requires std::same_as<decltype(Traits<T>::explicit_export), const bool>; typename std::bool_constant<Traits<T>::explicit_import>; typename std::bool_constant<Traits<T>::explicit_export>; }; template<typename T> concept QuantityLike = !Quantity<T> && qty-like-impl<T, quantity_like_traits> && requires { typename quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>; };
In the following descriptions, let
  • Traits be quantity_like_traits or quantity_point_like_traits,
  • Q be a type for which Traits<Q> is specialized,
  • qty be an lvalue of type const Q, and
  • num be an lvalue of type const Traits<Q>​::​rep.
Q models qty-like-impl<Traits> if and only if:
  • Traits<Q>​::​to_numerical_value(qty) returns the numerical value (IEC 60050, 112-01-29) of qty.
  • Traits<Q>​::​from_numerical_value(num) returns a Q with numerical value num.
  • If Traits is quantity_point_like_traits, both numerical values are offset from Traits<Q>​::​point_origin.
If the following expression is true, the specified conversion will be explicit.
  • Traits<Q>​::​explicit_import for the conversion from Q to this library's type.
  • Traits<Q>​::​explicit_export for the conversion from this library's type to Q.

5.6.3 Class template quantity [qty.syn]

namespace mp_units { template<typename T> concept Quantity = (is-derived-from-specialization-of<T, quantity>()); // exposition only template<typename Q, auto QS> concept QuantityOf = // exposition only Quantity<Q> && QuantitySpecOf<decltype(auto(Q::quantity_spec)), QS>; template<Unit UFrom, Unit UTo> consteval bool integral-conversion-factor(UFrom from, UTo to) // exposition only { return is-integral(get-canonical-unit(from).mag / get-canonical-unit(to).mag); } template<typename T> concept IsFloatingPoint = treat_as_floating_point<T>; // exposition only template<typename FromRep, typename ToRep, auto FromUnit = one, auto ToUnit = one> concept ValuePreservingTo = // exposition only Representation<std::remove_cvref_t<FromRep>> && Representation<ToRep> && Unit<decltype(FromUnit)> && Unit<decltype(ToUnit)> && std::assignable_from<ToRep&, FromRep> && (IsFloatingPoint<ToRep> || (!IsFloatingPoint<std::remove_cvref_t<FromRep>> && (integral-conversion-factor(FromUnit, ToUnit)))); template<typename QFrom, typename QTo> concept QuantityConvertibleTo = // exposition only Quantity<QFrom> && Quantity<QTo> && QuantitySpecConvertibleTo<QFrom::quantity_spec, QTo::quantity_spec> && UnitConvertibleTo<QFrom::unit, QTo::unit> && ValuePreservingTo<typename QFrom::rep, typename QTo::rep, QFrom::unit, QTo::unit> && requires(QFrom q) { sudo-cast<QTo>(q); }; // see [qty.non.mem.conv] template<auto QS, typename Func, typename T, typename U> concept InvokeResultOf = // exposition only QuantitySpec<decltype(QS)> && std::regular_invocable<Func, T, U> && RepresentationOf<std::invoke_result_t<Func, T, U>, QS>; template<typename Func, typename Q1, typename Q2, auto QS = std::invoke_result_t<Func, decltype(auto(Q1::quantity_spec)), decltype(auto(Q2::quantity_spec))>{}> concept InvocableQuantities = // exposition only QuantitySpec<decltype(QS)> && Quantity<Q1> && Quantity<Q2> && InvokeResultOf<QS, Func, typename Q1::rep, typename Q2::rep>; template<auto R1, auto R2> concept HaveCommonReference = requires { get_common_reference(R1, R2); }; // exposition only template<typename Func, Quantity Q1, Quantity Q2> using common-quantity-for = // exposition only quantity<get_common_reference(Q1::reference, Q2::reference), std::invoke_result_t<Func, typename Q1::rep, typename Q2::rep>>; template<typename Func, typename Q1, typename Q2> concept CommonlyInvocableQuantities = // exposition only Quantity<Q1> && Quantity<Q2> && HaveCommonReference<Q1::reference, Q2::reference> && std::convertible_to<Q1, common-quantity-for<Func, Q1, Q2>> && std::convertible_to<Q2, common-quantity-for<Func, Q1, Q2>> && InvocableQuantities<Func, Q1, Q2, get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>; template<auto R1, auto R2, typename Rep1, typename Rep2> concept SameValueAs = // exposition only (equivalent(get_unit(R1), get_unit(R2))) && std::convertible_to<Rep1, Rep2>; template<typename T> using quantity-like-type = // exposition only quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>; template<typename T, typename U, typename TT = std::remove_reference_t<T>> concept Mutable = (!std::is_const_v<TT>) && std::derived_from<TT, U>; // exposition only template<Reference auto R, RepresentationOf<get_quantity_spec(R)> Rep = double> class quantity { public: Rep numerical-value; // exposition only // member types and values static constexpr Reference auto reference = R; static constexpr QuantitySpec auto quantity_spec = get_quantity_spec(reference); static constexpr Dimension auto dimension = quantity_spec.dimension; static constexpr Unit auto unit = get_unit(reference); using rep = Rep; // [qty.static], static member functions static constexpr quantity zero() noexcept requires see below; static constexpr quantity one() noexcept requires see below; static constexpr quantity min() noexcept requires see below; static constexpr quantity max() noexcept requires see below; // [qty.cons], constructors and assignment quantity() = default; quantity(const quantity&) = default; quantity(quantity&&) = default; ~quantity() = default; template<typename FwdValue, Reference R2> requires SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep> constexpr quantity(FwdValue&& v, R2); template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>> requires(!SameValueAs<R2{}, R, Value, Rep>) && QuantityConvertibleTo<quantity<R2{}, Value>, quantity> constexpr quantity(FwdValue&& v, R2); template<ValuePreservingTo<Rep> FwdValue> requires(unit == ::mp_units::one) constexpr quantity(FwdValue&& v); template<QuantityConvertibleTo<quantity> Q> constexpr explicit(see below) quantity(const Q& q); template<QuantityLike Q> requires QuantityConvertibleTo<quantity-like-type<Q>, quantity> constexpr explicit(see below) quantity(const Q& q); quantity& operator=(const quantity&) = default; quantity& operator=(quantity&&) = default; template<ValuePreservingTo<Rep> FwdValue> requires(unit == ::mp_units::one) constexpr quantity& operator=(FwdValue&& v); // [qty.conv], conversions template<UnitCompatibleWith<unit, quantity_spec> ToU> requires QuantityConvertibleTo<quantity, quantity<make-reference(quantity_spec, ToU{}), Rep>> constexpr QuantityOf<quantity_spec> auto in(ToU) const; template<RepresentationOf<quantity_spec> ToRep> requires QuantityConvertibleTo<quantity, quantity<reference, ToRep>> constexpr QuantityOf<quantity_spec> auto in() const; template<RepresentationOf<quantity_spec> ToRep, UnitCompatibleWith<unit, quantity_spec> ToU> requires QuantityConvertibleTo<quantity, quantity<make-reference(quantity_spec, ToU{}), ToRep>> constexpr QuantityOf<quantity_spec> auto in(ToU) const; template<UnitCompatibleWith<unit, quantity_spec> ToU> requires requires(const quantity q) { value_cast<ToU{}>(q); } constexpr QuantityOf<quantity_spec> auto force_in(ToU) const; template<RepresentationOf<quantity_spec> ToRep> requires requires(const quantity q) { value_cast<ToRep>(q); } constexpr QuantityOf<quantity_spec> auto force_in() const; template<RepresentationOf<quantity_spec> ToRep, UnitCompatibleWith<unit, quantity_spec> ToU> requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); } constexpr QuantityOf<quantity_spec> auto force_in(ToU) const; // [qty.obs], numerical value observers template<Unit U> requires(equivalent(U{}, unit)) constexpr rep& numerical_value_ref_in(U) & noexcept; template<Unit U> requires(equivalent(U{}, unit)) constexpr const rep& numerical_value_ref_in(U) const & noexcept; template<Unit U> requires(equivalent(U{}, unit)) void numerical_value_ref_in(U) const && = delete; template<UnitCompatibleWith<unit, quantity_spec> U> requires QuantityConvertibleTo<quantity, quantity<make-reference(quantity_spec, U{}), Rep>> constexpr rep numerical_value_in(U) const noexcept; template<UnitCompatibleWith<unit, quantity_spec> U> requires requires(const quantity q) { value_cast<U{}>(q); } constexpr rep force_numerical_value_in(U) const noexcept; // [qty.conv.ops], conversion operations template<typename V_, std::constructible_from<Rep> Value = std::remove_cvref_t<V_>> requires(unit == ::mp_units::one) explicit operator V_() const & noexcept; template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>> requires QuantityConvertibleTo<quantity, quantity-like-type<Q>> constexpr explicit(see below) operator Q_() const noexcept(see below); // [qty.unary.ops], unary operations constexpr QuantityOf<quantity_spec> auto operator+() const requires see below; constexpr QuantityOf<quantity_spec> auto operator-() const requires see below; template<Mutable<quantity> Q> friend constexpr decltype(auto) operator++(Q&& q) requires see below; template<Mutable<quantity> Q> friend constexpr decltype(auto) operator--(Q&& q) requires see below; constexpr QuantityOf<quantity_spec> auto operator++(int) requires see below; constexpr QuantityOf<quantity_spec> auto operator--(int) requires see below; // [qty.assign.ops], compound assignment operations template<Mutable<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs); template<Mutable<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs); template<Mutable<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs); template<Mutable<quantity> Q, ValuePreservingTo<Rep> Value> requires see below friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& rhs); template<Mutable<quantity> Q, ValuePreservingTo<Rep> Value> requires see below friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& rhs); template<Mutable<quantity> Q, QuantityOf<dimensionless> Q2> requires see below friend constexpr decltype(auto) operator*=(Q&& lhs, const Q2& rhs); template<Mutable<quantity> Q, QuantityOf<dimensionless> Q2> requires see below friend constexpr decltype(auto) operator/=(Q&& lhs, const Q2& rhs); // [qty.arith.ops], arithmetic operations template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires CommonlyInvocableQuantities<std::plus<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires CommonlyInvocableQuantities<std::minus<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator-(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) && CommonlyInvocableQuantities<std::modulus<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator%(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&> friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&> friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&> friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&> friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&> friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&> friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires InvocableQuantities<std::multiplies<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator*(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires InvocableQuantities<std::divides<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator/(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, typename Value> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::multiplies<>, Rep, const Value&> friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, typename Value> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::divides<>, Rep, const Value&> friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& lhs, const Value& rhs); template<typename Value, std::derived_from<quantity> Q> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, Rep> friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& lhs, const Q& rhs); template<typename Value, std::derived_from<quantity> Q> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep> friend constexpr Quantity auto operator/(const Value&, const Q&); // [qty.cmp], comparison template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr bool operator==(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr auto operator<=>(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, Representation Value> requires see below friend constexpr bool operator==(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires see below friend constexpr auto operator<=>(const Q& lhs, const Value& rhs); // [qty.val.cmp], value comparison friend constexpr bool is_eq_zero(const quantity& q) requires see below; friend constexpr bool is_neq_zero(const quantity& q) requires see below; friend constexpr bool is_lt_zero(const quantity& q) requires see below; friend constexpr bool is_gt_zero(const quantity& q) requires see below; friend constexpr bool is_lteq_zero(const quantity& q) requires see below; friend constexpr bool is_gteq_zero(const quantity& q) requires see below; }; template<Representation Value, Reference R> quantity(Value, R) -> quantity<R{}, Value>; template<Representation Value> quantity(Value) -> quantity<one, Value>; template<QuantityLike Q> explicit(quantity_like_traits<Q>::explicit_import) quantity(Q) -> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>; }
quantity<R, Rep> is a structural type (N4971, [temp.param]) if Rep is a structural type.

5.6.4 Static member functions [qty.static]

static constexpr quantity zero() noexcept requires see below; static constexpr quantity one() noexcept requires see below; static constexpr quantity min() noexcept requires see below; static constexpr quantity max() noexcept requires see below;
Let F be one of zero, one, min, and max.
Returns: {representation_values<rep>​::​F(), R}.
Remarks: The expression in the requires-clause is equivalent to: requires { representation_values<rep>::F(); }

5.6.5 Constructors and assignment [qty.cons]

template<typename FwdValue, Reference R2> requires SameValueAs<R2{}, R, std::remove_cvref_t<FwdValue>, Rep> constexpr quantity(FwdValue&& v, R2); template<ValuePreservingTo<Rep> FwdValue> requires(unit == ::mp_units::one) constexpr quantity(FwdValue&& v);
Effects: Initializes numerical-value with std​::​forward<FwdValue>(v).
template<typename FwdValue, Reference R2, typename Value = std::remove_cvref_t<FwdValue>> requires(!SameValueAs<R2{}, R, Value, Rep>) && QuantityConvertibleTo<quantity<R2{}, Value>, quantity> constexpr quantity(FwdValue&& v, R2);
Effects: Equivalent to quantity(quantity<R2{}, Value>{std​::​forward<FwdValue>(v), R2{}}).
template<QuantityConvertibleTo<quantity> Q> constexpr explicit(!std::convertible_to<typename Q::rep, Rep>) quantity(const Q& q);
Effects: Equivalent to sudo-cast<quantity>(q) ([qty.non.mem.conv]).
template<QuantityLike Q> requires QuantityConvertibleTo<quantity-like-type<Q>, quantity> constexpr explicit(see below) quantity(const Q& q);
Effects: Equivalent to: quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q), quantity_like_traits<Q>::reference})
Remarks: The expression inside explicit is equivalent to: quantity_like_traits<Q>::explicit_import || !std::convertible_to<typename quantity_like_traits<Q>::rep, Rep>
template<ValuePreservingTo<Rep> FwdValue> requires(unit == ::mp_units::one) constexpr quantity& operator=(FwdValue&& v);
Effects: Equivalent to numerical-value = std​::​forward<FwdValue>(v).
Returns: *this.

5.6.6 Conversions [qty.conv]

template<UnitCompatibleWith<unit, quantity_spec> ToU> requires QuantityConvertibleTo<quantity, quantity<make-reference(quantity_spec, ToU{}), Rep>> constexpr QuantityOf<quantity_spec> auto in(ToU) const;
Effects: Equivalent to: return quantity<make-reference(quantity_spec, ToU{}), Rep>{*this};
template<RepresentationOf<quantity_spec> ToRep> requires QuantityConvertibleTo<quantity, quantity<reference, ToRep>> constexpr QuantityOf<quantity_spec> auto in() const;
Effects: Equivalent to: return quantity<reference, ToRep>{*this};
template<RepresentationOf<quantity_spec> ToRep, UnitCompatibleWith<unit, quantity_spec> ToU> requires QuantityConvertibleTo<quantity, quantity<make-reference(quantity_spec, ToU{}), ToRep>> constexpr QuantityOf<quantity_spec> auto in(ToU) const;
Effects: Equivalent to: return quantity<make-reference(quantity_spec, ToU{}), ToRep>{*this};
template<UnitCompatibleWith<unit, quantity_spec> ToU> requires requires(const quantity q) { value_cast<ToU{}>(q); } constexpr QuantityOf<quantity_spec> auto force_in(ToU) const;
Effects: Equivalent to: return value_cast<ToU{}>(*this);
template<RepresentationOf<quantity_spec> ToRep> requires requires(const quantity q) { value_cast<ToRep>(q); } constexpr QuantityOf<quantity_spec> auto force_in() const;
Effects: Equivalent to: return value_cast<ToRep>(*this);
template<RepresentationOf<quantity_spec> ToRep, UnitCompatibleWith<unit, quantity_spec> ToU> requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); } constexpr QuantityOf<quantity_spec> auto force_in(ToU) const;
Effects: Equivalent to: return value_cast<ToU{}, ToRep>(*this);

5.6.7 Numerical value observers [qty.obs]

template<Unit U> requires(equivalent(U{}, unit)) constexpr rep& numerical_value_ref_in(U) & noexcept; template<Unit U> requires(equivalent(U{}, unit)) constexpr const rep& numerical_value_ref_in(U) const & noexcept;
Returns: numerical-value.
template<UnitCompatibleWith<unit, quantity_spec> U> requires QuantityConvertibleTo<quantity, quantity<make-reference(quantity_spec, U{}), Rep>> constexpr rep numerical_value_in(U) const noexcept;
Effects: Equivalent to: return (*this).in(U{}).numerical-value;
template<UnitCompatibleWith<unit, quantity_spec> U> requires requires(const quantity q) { value_cast<U{}>(q); } constexpr rep force_numerical_value_in(U) const noexcept;
Effects: Equivalent to: return (*this).force_in(U{}).numerical-value;

5.6.8 Conversion operations [qty.conv.ops]

template<typename V_, std::constructible_from<Rep> Value = std::remove_cvref_t<V_>> requires(unit == ::mp_units::one) explicit operator V_() const & noexcept;
Returns: numerical-value.
template<typename Q_, QuantityLike Q = std::remove_cvref_t<Q_>> requires QuantityConvertibleTo<quantity, quantity-like-type<Q>> constexpr explicit(see below) operator Q_() const noexcept(see below);
Effects: Equivalent to: return quantity_like_traits<Q>::from_numerical_value( numerical_value_in(get_unit(quantity_like_traits<Q>::reference)));
Remarks: The expression inside explicit is equivalent to: quantity_like_traits<Q>::explicit_export || !std::convertible_to<Rep, typename quantity_like_traits<Q>::rep>
The exception specification is equivalent to: noexcept(quantity_like_traits<Q>::from_numerical_value(numerical-value)) && std::is_nothrow_copy_constructible_v<rep>

5.6.9 Unary operations [qty.unary.ops]

In the following descriptions, let @ be the operator.
constexpr QuantityOf<quantity_spec> auto operator+() const requires see below; constexpr QuantityOf<quantity_spec> auto operator-() const requires see below;
Effects: Equivalent to: return ​::​mp_units​::​quantity{@numerical-value, reference};
Remarks: The expression in the requires-clause is equivalent to: requires(const rep v) { { @v } -> std::common_with<rep>; }
template<Mutable<quantity> Q> friend constexpr decltype(auto) operator++(Q&& q) requires see below; template<Mutable<quantity> Q> friend constexpr decltype(auto) operator--(Q&& q) requires see below;
Effects: Equivalent to @q.numerical-value.
Returns: std​::​forward<Q>(q).
Remarks: The expression in the requires-clause is equivalent to: requires(rep& v) { { @v } -> std::same_as<rep&>; }
constexpr QuantityOf<quantity_spec> auto operator++(int) requires see below; constexpr QuantityOf<quantity_spec> auto operator--(int) requires see below;
Effects: Equivalent to: return ​::​mp_units​::​quantity{numerical-value@, reference};
Remarks: The expression in the requires-clause is equivalent to: requires(rep& v) { { v@ } -> std::common_with<rep>; }

5.6.10 Compound assignment operations [qty.assign.ops]

In the following descriptions, let @ be the operator.
template<Mutable<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs); template<Mutable<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs); template<Mutable<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs);
Preconditions: If @ is %=, then is_neq_zero(rhs) is true.
Effects: Equivalent to lhs.numerical-value @ rhs.in(lhs.unit).numerical-value.
Returns: std​::​forward<Q>(lhs).
Remarks: Let C be
  • (!treat_as_floating_point<rep>) if @ is %=, and
  • true otherwise.
The expression in the requires-clause is equivalent to: QuantityConvertibleTo<quantity<R2, Rep2>, quantity> && C && requires(rep& a, const Rep2 b) { { a @ b } -> std::same_as<rep&>; }
Recommended practice: If equivalent(unit, get_unit(rhs.reference)) is true, then the expression rhs.in(lhs.unit) is replaced with rhs.
template<Mutable<quantity> Q, ValuePreservingTo<Rep> Value> requires see below friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& rhs); template<Mutable<quantity> Q, ValuePreservingTo<Rep> Value> requires see below friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& rhs);
Preconditions: If @ is /=, then rhs != representation_values<Value>​::​zero() is true.
Effects: Equivalent to lhs.numerical-value @ rhs.
Returns: std​::​forward<Q>(lhs).
Remarks: The expression in the requires-clause is equivalent to: (!Quantity<Value>) && requires(rep& a, const Value b) { { a @ b } -> std::same_as<rep&>; }
template<Mutable<quantity> Q, QuantityOf<dimensionless> Q2> requires see below friend constexpr decltype(auto) operator*=(Q&& lhs, const Q2& rhs); template<Mutable<quantity> Q, QuantityOf<dimensionless> Q2> requires see below friend constexpr decltype(auto) operator/=(Q&& lhs, const Q2& rhs);
Effects: Equivalent to: return std​::​forward<Q>(lhs) @ rhs.numerical-value;
Remarks: The expression in the requires-clause is equivalent to: (Q2::unit == ::mp_units::one) && ValuePreservingTo<typename Q2::rep, Rep> && requires(rep& a, const Q2::rep b) { { a @ b } -> std::same_as<rep&>; }

5.6.11 Arithmetic operations [qty.arith.ops]

In the following descriptions, let @ be the operator.
template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires CommonlyInvocableQuantities<std::plus<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires CommonlyInvocableQuantities<std::minus<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator-(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) && CommonlyInvocableQuantities<std::modulus<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator%(const Q& lhs, const quantity<R2, Rep2>& rhs);
Let F be the first argument to CommonlyInvocableQuantities.
Preconditions: If @ is %, then is_neq_zero(rhs) is true.
Effects: Equivalent to: using ret = common-quantity-for<F, quantity, quantity<R2, Rep2>>; const ret ret_lhs(lhs); const ret ret_rhs(rhs); return ::mp_units::quantity{ ret_lhs.numerical_value_ref_in(ret::unit) @ ret_rhs.numerical_value_ref_in(ret::unit), ret::reference};
template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&> friend constexpr Quantity auto operator+(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&> friend constexpr Quantity auto operator-(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&> friend constexpr Quantity auto operator%(const Q& lhs, const Value& rhs);
Effects: Equivalent to: return lhs @ ​::​mp_units​::​quantity{rhs};
template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::plus<>, Rep, const Value&> friend constexpr Quantity auto operator+(const Value& lhs, const Q& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::minus<>, Rep, const Value&> friend constexpr Quantity auto operator-(const Value& lhs, const Q& rhs); template<std::derived_from<quantity> Q, Representation Value> requires(Q::unit == ::mp_units::one) && InvokeResultOf<quantity_spec, std::modulus<>, Rep, const Value&> friend constexpr Quantity auto operator%(const Value& lhs, const Q& rhs);
Effects: Equivalent to: return ​::​mp_units​::​quantity{lhs} @ rhs;
template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires InvocableQuantities<std::multiplies<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator*(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires InvocableQuantities<std::divides<>, quantity, quantity<R2, Rep2>> friend constexpr Quantity auto operator/(const Q& lhs, const quantity<R2, Rep2>& rhs);
Preconditions: If @ is /, then is_neq_zero(rhs) is true.
Effects: Equivalent to: return ::mp_units::quantity{ lhs.numerical_value_ref_in(unit) @ rhs.numerical_value_ref_in(rhs.unit), R @ R2};
template<std::derived_from<quantity> Q, typename Value> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::multiplies<>, Rep, const Value&> friend constexpr QuantityOf<quantity_spec> auto operator*(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, typename Value> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::divides<>, Rep, const Value&> friend constexpr QuantityOf<quantity_spec> auto operator/(const Q& lhs, const Value& rhs);
Preconditions: If @ is /, then rhs != representation_values<Value>​::​zero() is true.
Effects: Equivalent to: return ::mp_units::quantity{lhs.numerical_value_ref_in(unit) @ rhs, R};
template<typename Value, std::derived_from<quantity> Q> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::multiplies<>, const Value&, Rep> friend constexpr QuantityOf<quantity_spec> auto operator*(const Value& lhs, const Q& rhs); template<typename Value, std::derived_from<quantity> Q> requires(!Quantity<Value>) && (!Reference<Value>) && InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep> friend constexpr Quantity auto operator/(const Value& lhs, const Q& rhs);
Preconditions: If @ is /, then is_neq_zero(rhs) is true.
Effects: Equivalent to: return ::mp_units::quantity{lhs @ rhs.numerical_value_ref_in(unit), ::mp_units::one @ R};

5.6.12 Comparison [qty.cmp]

In the following descriptions, let @ be the operator.
template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr bool operator==(const Q& lhs, const quantity<R2, Rep2>& rhs); template<std::derived_from<quantity> Q, auto R2, typename Rep2> requires see below friend constexpr auto operator<=>(const Q& lhs, const quantity<R2, Rep2>& rhs);
Let C be std​::​equality_comparable if @ is ==, and std​::​three_way_comparable if @ is <=>.
Effects: Equivalent to: using ct = std::common_type_t<quantity, quantity<R2, Rep2>>; const ct ct_lhs(lhs); const ct ct_rhs(rhs); return ct_lhs.numerical_value_ref_in(ct::unit) @ ct_rhs.numerical_value_ref_in(ct::unit);
Remarks: The expression in the requires-clause is equivalent to: requires { typename std::common_type_t<quantity, quantity<R2, Rep2>>; } && C<typename std::common_type_t<quantity, quantity<R2, Rep2>>::rep>
template<std::derived_from<quantity> Q, Representation Value> requires see below friend constexpr bool operator==(const Q& lhs, const Value& rhs); template<std::derived_from<quantity> Q, Representation Value> requires see below friend constexpr auto operator<=>(const Q& lhs, const Value& rhs);
Let C be std​::​equality_comparable_with if @ is ==, and std​::​three_way_comparable_with if @ is <=>.
Returns: lhs.numerical_value_ref_in(unit) @ rhs.
Remarks: The expression in the requires-clause is equivalent to: (Q::unit == ::mp_units::one) && C<Rep, Value>

5.6.13 Value comparison [qty.val.cmp]

friend constexpr bool is_eq_zero(const quantity& q) requires see below; friend constexpr bool is_neq_zero(const quantity& q) requires see below; friend constexpr bool is_lt_zero(const quantity& q) requires see below; friend constexpr bool is_gt_zero(const quantity& q) requires see below; friend constexpr bool is_lteq_zero(const quantity& q) requires see below; friend constexpr bool is_gteq_zero(const quantity& q) requires see below;
Let is_F_zero be the function name.
Returns:
Remarks: Let C be std​::​equality_comparable_with if F is eq or neq, and std​::​three_way_comparable_with otherwise.
The expression in the requires-clause is equivalent to: requires { { T::zero() } -> C<quantity>; }

5.6.14 Construction helper delta [qty.delta]

namespace mp_units { template<Reference R> struct delta_ { template<typename FwdRep, RepresentationOf<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>> constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const; }; }
template<typename FwdRep, RepresentationOf<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>> constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const;
Effects: Equivalent to: return quantity{std​::​forward<FwdRep>(lhs), R{}};

5.6.15 Non-member conversions [qty.non.mem.conv]

template<Quantity To, typename FwdFrom, Quantity From = std::remove_cvref_t<FwdFrom>> requires see below constexpr To sudo-cast(FwdFrom&& q); // exposition only
Returns: TBD.
value_cast is an explicit cast that allows truncation.
template<Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>> requires(convertible(Q::reference, ToU)) constexpr Quantity auto value_cast(FwdQ&& q);
Effects: Equivalent to: return sudo-cast<quantity<make-reference(Q::quantity_spec, ToU), typename Q::rep>>( std::forward<FwdQ>(q));
template<Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>> requires RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep> constexpr quantity<Q::reference, ToRep> value_cast(FwdQ&& q);
Effects: Equivalent to: return sudo-cast<quantity<Q::reference, ToRep>>(std::forward<FwdQ>(q));
template<Unit auto ToU, Representation ToRep, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>> requires see below constexpr Quantity auto value_cast(FwdQ&& q); template<Representation ToRep, Unit auto ToU, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>> requires see below constexpr Quantity auto value_cast(FwdQ&& q);
Effects: Equivalent to: return sudo-cast<quantity<make-reference(Q::quantity_spec, ToU), ToRep>>( std::forward<FwdQ>(q));
Remarks: The expression in the requires-clause is equivalent to: (convertible(Q::reference, ToU)) && RepresentationOf<ToRep, Q::quantity_spec> && std::constructible_from<ToRep, typename Q::rep>
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> constexpr Quantity auto value_cast(FwdQ&& q);
Effects: Equivalent to: return sudo-cast<ToQ>(std​::​forward<FwdQ>(q));
quantity_cast is an explicit cast that allows converting to more specific quantities.
[Example 1: auto length = isq::length(42 * m); auto distance = quantity_cast<isq::distance>(length); — end example]
template<QuantitySpec auto ToQS, typename FwdQ, Quantity Q = std::remove_cvref_t<FwdQ>> requires QuantitySpecCastableTo<Q::quantity_spec, ToQS> constexpr Quantity auto quantity_cast(FwdQ&& q);
Effects: Equivalent to: return quantity{std::forward<FwdQ>(q).numerical-value, make-reference(ToQS, Q::unit)};

5.6.16 std​::​common_type specializations [qty.common.type]

template<mp_units::Quantity Q1, mp_units::Quantity Q2> requires requires { { mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference; typename std::common_type_t<typename Q1::rep, typename Q2::rep>; requires mp_units::RepresentationOf<std::common_type_t<typename Q1::rep, typename Q2::rep>, mp_units::get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>; } struct std::common_type<Q1, Q2> { using type = mp_units::quantity<mp_units::get_common_reference(Q1::reference, Q2::reference), std::common_type_t<typename Q1::rep, typename Q2::rep>>; }; template<mp_units::Quantity Q, mp_units::Representation Value> requires(Q::unit == mp_units::one) && requires { typename mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>; } struct std::common_type<Q, Value> { using type = mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>; };