5 Quantities and units library [quantities]

5.5 Representation [qty.rep]

5.5.1 General [qty.rep.general]

Subclause [qty.rep] specifies the components used to constrain the numerical value of a quantity (IEC 60050, 112-01-29).

5.5.2 Traits [qty.rep.traits]

5.5.2.1 Floating-point [qty.fp.traits]

template<typename T> struct actual-value-type : cond-value-type<T> {}; // see N4971, [readable.traits] template<typename T> requires(!std::is_pointer_v<T> && !std::is_array_v<T>) && requires { typename std::indirectly_readable_traits<T>::value_type; } struct actual-value-type<T> : std::indirectly_readable_traits<T> {}; template<typename T> using actual-value-type-t = actual-value-type<T>::value_type; template<typename Rep> constexpr bool treat_as_floating_point = std::chrono::treat_as_floating_point_v<actual-value-type-t<Rep>>;
quantity and quantity_point use treat_as_floating_point to help determine whether implicit conversions are allowed among them.
Remarks: Pursuant to N4971, [namespace.std] ([spec.ext]), users may specialize treat_as_floating_point for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions (N4971, [expr.const]) and have type const bool.

5.5.2.2 Quantity character [qty.char.traits]

template<typename T> constexpr bool disable_scalar = false; template<typename T> constexpr bool disable_complex = false; template<typename T> constexpr bool disable_vector = false;
Some quantities are defined as having a numerical value (IEC 60050, 112-01-29) of a specific set (IEC 60050, 102-01-02).
The representation concepts use these traits to help determine the sets T represents.
Remarks: Pursuant to N4971, [namespace.std] ([spec.ext]), users may specialize these templates for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions (N4971, [expr.const]) and have type const bool.
[Note 1: 
These templates prevent use of representation types with the library that satisfy but do not in fact model their corresponding concept.
— end note]

5.5.2.3 Values [qty.val.traits]

quantity and quantity_point use representation_values to construct special values of its representation type.
namespace mp_units { template<typename Rep> struct representation_values : std::chrono::duration_values<Rep> { static constexpr Rep one() noexcept; }; }
The requirements on std​::​chrono​::​duration_values<Rep> (N4971, [time.traits.duration.values]) also apply to representation_values<Rep>.
static constexpr Rep one() noexcept;
Returns: Rep(1).
Remarks: The value returned shall be the neutral element for multiplication (IEC 60050, 102-01-19).

5.5.3 Customization point objects [qty.rep.cpos]

5.5.3.2 mp_units​::​real [qty.real.cpo]

The name mp_units​::​real denotes a customization point object (N4971, [customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T does not model WeaklyRegular, mp_units​::​real(E) is ill-formed.
  • If auto(t.real()) is a valid expression whose type models Scalar, mp_units​::​real(E) is expression-equivalent to auto(t.real()).
  • Otherwise, if T is a class or enumeration type and auto(real(t)) is a valid expression whose type models Scalar where the meaning of real is established as-if by performing argument-dependent lookup only (N4971, [basic.lookup.argdep]), then mp_units​::​real(E) is expression-equivalent to that expression.
  • Otherwise, mp_units​::​real(E) is ill-formed.

5.5.3.3 mp_units​::​imag [qty.imag.cpo]

The name mp_units​::​imag denotes a customization point object (N4971, [customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T does not model WeaklyRegular, mp_units​::​imag(E) is ill-formed.
  • If auto(t.imag()) is a valid expression whose type models Scalar, mp_units​::​imag(E) is expression-equivalent to auto(t.imag()).
  • Otherwise, if T is a class or enumeration type and auto(imag(t)) is a valid expression whose type models Scalar where the meaning of imag is established as-if by performing argument-dependent lookup only (N4971, [basic.lookup.argdep]), then mp_units​::​imag(E) is expression-equivalent to that expression.
  • Otherwise, mp_units​::​imag(E) is ill-formed.

5.5.3.4 mp_units​::​modulus [qty.modulus.cpo]

The name mp_units​::​modulus denotes a customization point object (N4971, [customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T does not model WeaklyRegular, mp_units​::​modulus(E) is ill-formed.
  • If auto(t.modulus()) is a valid expression whose type models Scalar, mp_units​::​modulus(E) is expression-equivalent to auto(t.modulus()).
  • Otherwise, if T is a class or enumeration type and auto(modulus(t)) is a valid expression whose type models Scalar where the meaning of modulus is established as-if by performing argument-dependent lookup only (N4971, [basic.lookup.argdep]), then mp_units​::​modulus(E) is expression-equivalent to that expression.
  • If auto(t.abs()) is a valid expression whose type models Scalar, mp_units​::​modulus(E) is expression-equivalent to auto(t.abs()).
  • Otherwise, if T is a class or enumeration type and auto(abs(t)) is a valid expression whose type models Scalar where the meaning of abs is established as-if by performing argument-dependent lookup only (N4971, [basic.lookup.argdep]), then mp_units​::​modulus(E) is expression-equivalent to that expression.
  • Otherwise, mp_units​::​modulus(E) is ill-formed.

5.5.3.5 mp_units​::​magnitude [qty.mag.cpo]

The name mp_units​::​magnitude denotes a customization point object (N4971, [customization.point.object]).
Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E.
Then:
  • If T does not model WeaklyRegular, mp_units​::​magnitude(E) is ill-formed.
  • If auto(t.magnitude()) is a valid expression whose type models Scalar, mp_units​::​magnitude(E) is expression-equivalent to auto(t.magnitude()).
  • Otherwise, if T is a class or enumeration type and auto(magnitude(t)) is a valid expression whose type models Scalar where the meaning of magnitude is established as-if by performing argument-dependent lookup only (N4971, [basic.lookup.argdep]), then mp_units​::​magnitude(E) is expression-equivalent to that expression.
  • Otherwise, if auto(t.abs()) is a valid expression whose type models Scalar, mp_units​::​magnitude(​E) is expression-equivalent to auto(t.abs()).
  • Otherwise, if T is a class or enumeration type and auto(abs(t)) is a valid expression whose type models Scalar where the meaning of magnitude is established as-if by performing argument-dependent lookup only (N4971, [basic.lookup.argdep]), then mp_units​::​magnitude(E) is expression-equivalent to that expression.
  • Otherwise, mp_units​::​magnitude(E) is ill-formed.

5.5.4 Concepts [qty.rep.concepts]

template<typename T> concept WeaklyRegular = std::copyable<T> && std::equality_comparable<T>; // exposition only template<typename T> concept Scalar = (!disable_scalar<T>) && WeaklyRegular<T> && requires(T a, T b) { // exposition only // scalar operations { -a } -> std::common_with<T>; { a + b } -> std::common_with<T>; { a - b } -> std::common_with<T>; { a * b } -> std::common_with<T>; { a / b } -> std::common_with<T>; };
TBD.
template<typename T> using value-type-t = actual-value-type-t<T>; // exposition only, see [qty.fp.traits] template<typename T> concept Complex = // exposition only (!disable_complex<T>) && WeaklyRegular<T> && Scalar<value-type-t<T>> && std::constructible_from<T, value-type-t<T>, value-type-t<T>> && requires(T a, T b, value-type-t<T> s) { // complex operations { -a } -> std::common_with<T>; { a + b } -> std::common_with<T>; { a - b } -> std::common_with<T>; { a * b } -> std::common_with<T>; { a / b } -> std::common_with<T>; { a * s } -> std::common_with<T>; { s * a } -> std::common_with<T>; { a / s } -> std::common_with<T>; ::mp_units::real(a); ::mp_units::imag(a); ::mp_units::modulus(a); };
TBD.
template<typename T> concept Vector = // exposition only (!disable_vector<T>) && WeaklyRegular<T> && Scalar<value-type-t<T>> && requires(T a, T b, value-type-t<T> s) { // vector operations { -a } -> std::common_with<T>; { a + b } -> std::common_with<T>; { a - b } -> std::common_with<T>; { a * s } -> std::common_with<T>; { s * a } -> std::common_with<T>; { a / s } -> std::common_with<T>; ::mp_units::magnitude(a); };
TBD.
template<typename T> using scaling-factor-type-t = // exposition only std::conditional_t<treat_as_floating_point<T>, long double, std::intmax_t>; template<typename T> concept ScalarRepresentation = // exposition only (!is-specialization-of<T, quantity>()) && Scalar<T> && requires(T a, T b, scaling-factor-type-t<T> f) { // scaling { a * f } -> std::common_with<T>; { f * a } -> std::common_with<T>; { a / f } -> std::common_with<T>; };
TBD.
template<typename T> concept ComplexRepresentation = // exposition only (!is-specialization-of<T, quantity>()) && Complex<T> && requires(T a, T b, scaling-factor-type-t<T> f) { // scaling { a * T(f) } -> std::common_with<T>; { T(f) * a } -> std::common_with<T>; { a / T(f) } -> std::common_with<T>; };
TBD.
template<typename T> concept VectorRepresentation = // exposition only (!is-specialization-of<T, quantity>()) && Vector<T>;
TBD.
template<typename T> concept Representation = ScalarRepresentation<T> || ComplexRepresentation<T> || VectorRepresentation<T>;
A type T models Representation if it represents the numerical value of a quantity (IEC 60050, 112-01-29).
template<typename T, quantity_character Ch> concept IsOfCharacter = (Ch == quantity_character::real_scalar && Scalar<T>) || // exposition only (Ch == quantity_character::complex_scalar && Complex<T>) || (Ch == quantity_character::vector && Vector<T>); template<typename T, auto V> concept RepresentationOf = Representation<T> && ((QuantitySpec<decltype(V)> && (QuantityKindSpec<decltype(V)> || IsOfCharacter<T, V.character>)) || (std::same_as<quantity_character, decltype(V)> && IsOfCharacter<T, V>));
A type T models RepresentationOf<V> if T models Representation and
  • V is a kind of quantity, or
  • if V is a quantity, then T represents a value of its character, or
  • if V is a quantity character, then T represents a value of V.