Files
mp-units/docs/api_reference/src/quantities.tex
T

6730 lines
226 KiB
TeX
Raw Normal View History

2024-09-08 08:20:26 +02:00
%!TEX root = std.tex
2024-10-12 22:25:53 -04:00
\rSec0[quantities]{Quantities and units library}
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\rSec1[quantities.summary]{Summary}
2024-09-08 08:20:26 +02:00
\pnum
2024-10-12 22:25:53 -04:00
This Clause describes components for dealing with quantities and units,
as summarized in \tref{quantities.summary}.
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\begin{modularlibsumtab}{Quantities and units library summary}{quantities.summary}
\ref{qty.utils} & Utilities & \tcode{mp_units.core} \\
\ref{qty.ref} & Reference & \\
\ref{qty.rep} & Representation & \\
\ref{qty} & Quantity & \\
\ref{qty.pt} & Quantity point & \\ \rowsep
2024-09-08 08:20:26 +02:00
\ref{qty.systems} & Systems & \tcode{mp_units.systems} \\
2024-10-12 22:25:53 -04:00
\ref{qty.chrono} & \tcode{std::chrono} interoperability & \\
2024-09-08 08:20:26 +02:00
\end{modularlibsumtab}
2024-10-12 22:25:53 -04:00
\ednote{
Following the SG16 recommendation at \url{https://lists.isocpp.org/sg16/2024/10/4490.php},
the \fakegrammarterm{universal-character-name}s should be replaced by their UTF-8 code points.
}
\rSec1[mp.units.syns]{mp-units module synopses}
\rSec2[mp.units.syn]{Module \tcode{mp_units} synopsis}
2024-09-08 08:20:26 +02:00
\indexmodule{mp_units}%
\begin{codeblock}
export module mp_units;
export import mp_units.core;
export import mp_units.systems;
\end{codeblock}
2024-10-12 22:25:53 -04:00
\rSec2[mp.units.core.syn]{Module \tcode{mp_units.core} synopsis}
2024-09-08 08:20:26 +02:00
\indexmodule{mp_units.core}%
\begin{codeblock}
2024-10-12 22:25:53 -04:00
// mostly freestanding
2024-09-08 08:20:26 +02:00
export module mp_units.core;
import std;
export namespace mp_units {
2024-10-12 22:25:53 -04:00
// \ref{qty.utils}, utilities
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
// \ref{qty.sym.txt}, symbol text
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
enum class @\libglobal{character_set}@ : std::int8_t { utf8, portable, default_character_set = utf8 };
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
template<std::size_t N, std::size_t M>
class symbol_text;
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
// \ref{qty.sym.expr}, symbolic expressions
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
// \ref{qty.sym.expr.types}, types
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
template<typename T, typename... Ts>
struct per;
template<typename F, int Num, int... Den>
requires @\seebelownc@
struct power;
// \ref{qty.ref}, reference
// \ref{qty.dim}, dimension
// \ref{qty.dim.concepts}, concepts
2024-09-08 08:20:26 +02:00
template<typename T>
2024-10-12 22:25:53 -04:00
concept Dimension = @\seebelownc@;
template<typename T, auto D>
concept DimensionOf = @\seebelownc@;
// \ref{qty.dim.types}, types
template<symbol_text Symbol>
struct base_dimension;
template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_dimension;
struct dimension_one;
inline constexpr dimension_one @\libglobal{dimension_one}@{};
// \ref{qty.dim.ops}, operations
consteval @\libconcept{Dimension}@ auto inverse(@\libconcept{Dimension}@ auto d);
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Dimension}@ D>
requires(Den != 0)
consteval @\libconcept{Dimension}@ auto pow(D d);
consteval @\libconcept{Dimension}@ auto sqrt(@\libconcept{Dimension}@ auto d);
consteval @\libconcept{Dimension}@ auto cbrt(@\libconcept{Dimension}@ auto d);
// \ref{qty.dim.sym.fmt}, symbol formatting
struct @\libglobal{dimension_symbol_formatting}@ {
character_set char_set = character_set::default_character_set;
};
template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Dimension}@ D>
constexpr Out dimension_symbol_to(Out out, D d, const dimension_symbol_formatting& fmt = {});
template<dimension_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Dimension}@ D>
consteval std::string_view dimension_symbol(D);
// \ref{qty.spec}, quantity specification
// \ref{qty.spec.concepts}, concepts
2024-09-08 08:20:26 +02:00
template<typename T>
2024-10-12 22:25:53 -04:00
concept QuantitySpec = @\seebelownc@;
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
template<typename T, auto QS>
concept QuantitySpecOf = @\seebelownc@;
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
// \ref{qty.spec.types}, types
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
// \ref{named.qty}, named
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
struct is_kind;
inline constexpr is_kind @\libglobal{is_kind}@{};
2024-09-08 08:20:26 +02:00
template<auto...>
2024-10-12 22:25:53 -04:00
struct quantity_spec; // \notdef
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
template<@\exposconceptnc{BaseDimension}@ auto Dim, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Dim, Args...>;
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
template<@\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Eq, Args...>;
template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<QS, Args...>;
template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<QS, Eq, Args...>;
// \ref{derived.qty}, derived
template<@\exposconceptnc{SymbolicConstant}@... Expr>
2024-09-08 08:20:26 +02:00
struct derived_quantity_spec;
2024-10-12 22:25:53 -04:00
// \ref{dimless.qty}, base quantity of dimension one
struct dimensionless;
inline constexpr dimensionless @\libglobal{dimensionless}@{};
// \ref{kind.of.qty}, kind of
template<@\libconcept{QuantitySpec}@ Q>
requires @\seebelownc@
struct kind_of_;
template<@\libconcept{QuantitySpec}@ auto Q>
requires requires { typename kind_of_<decltype(Q)>; }
inline constexpr kind_of_<decltype(Q)> @\libglobal{kind_of}@{};
// \ref{qty.spec.ops}, operations
consteval @\libconcept{QuantitySpec}@ auto inverse(@\libconcept{QuantitySpec}@ auto q);
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{QuantitySpec}@ Q>
requires(Den != 0)
consteval @\libconcept{QuantitySpec}@ auto pow(Q q);
consteval @\libconcept{QuantitySpec}@ auto sqrt(@\libconcept{QuantitySpec}@ auto q);
consteval @\libconcept{QuantitySpec}@ auto cbrt(@\libconcept{QuantitySpec}@ auto q);
// \ref{qty.spec.hier.algos}, hierarchy algorithms
// \ref{qty.spec.conv}, conversion
consteval bool implicitly_convertible(@\libconcept{QuantitySpec}@ auto from, @\libconcept{QuantitySpec}@ auto to);
consteval bool explicitly_convertible(@\libconcept{QuantitySpec}@ auto from, @\libconcept{QuantitySpec}@ auto to);
consteval bool castable(@\libconcept{QuantitySpec}@ auto from, @\libconcept{QuantitySpec}@ auto to);
consteval bool interconvertible(@\libconcept{QuantitySpec}@ auto qs1, @\libconcept{QuantitySpec}@ auto qs2);
// \ref{qty.get.kind}, \tcode{get_kind}
template<@\libconcept{QuantitySpec}@ Q>
consteval @\seebelownc@ get_kind(Q);
// \ref{get.common.qty.spec}, \tcode{get_common_quantity_spec}
consteval @\libconcept{QuantitySpec}@ auto get_common_quantity_spec(@\libconcept{QuantitySpec}@ auto... qs)
requires @\seebelownc@;
// \ref{qty.unit}, unit
// \ref{qty.unit.mag}, magnitude
// \ref{qty.unit.mag.concepts}, concepts
template<typename T>
concept MagConstant = @\seebelownc@;
template<typename T>
concept UnitMagnitude = @\seebelownc@;
// \ref{qty.unit.mag.types}, types
template<symbol_text Symbol, long double Value>
requires(Value > 0)
struct mag_constant;
// \ref{qty.unit.mag.ops}, operations
template<@\exposconceptnc{MagArg}@ auto V>
constexpr @\libconcept{UnitMagnitude}@ auto mag = @\seebelownc@;
template<std::intmax_t N, std::intmax_t D>
requires(N > 0)
constexpr @\libconcept{UnitMagnitude}@ auto mag_ratio = @\seebelownc@;
template<@\exposconceptnc{MagArg}@ auto Base, int Num, int Den = 1>
constexpr @\libconcept{UnitMagnitude}@ auto mag_power = @\seebelownc@;
// constants
inline constexpr struct @\libglobal{pi}@ final :
mag_constant<{u8"\u03C0" /* @\unicode{03c0}{GREEK SMALL LETTER PI}@ */, "pi"},
std::numbers::pi_v<long double>> {
} @\libglobal{pi}@;
inline constexpr auto \u03C0 /* @\unicode{03c0}{GREEK SMALL LETTER PI}@ */ = pi;
// \ref{qty.unit.traits}, traits
template<@\libconcept{Unit}@ auto U>
constexpr bool space_before_unit_symbol = true;
template<>
inline constexpr bool @\libspec{space_before_unit_symbol}{one}@<one> = false;
// \ref{qty.unit.concepts}, concepts
template<typename T>
concept Unit = @\seebelownc@;
template<typename T>
concept PrefixableUnit = @\seebelownc@;
template<typename T>
concept AssociatedUnit = @\seebelownc@;
template<typename U, auto QS>
concept UnitOf = @\seebelownc@;
// \ref{qty.unit.types}, types
// \ref{qty.scaled.unit}, scaled
template<@\libconcept{UnitMagnitude}@ auto M, @\libconcept{Unit}@ U>
requires @\seebelownc@
struct scaled_unit;
// \ref{qty.named.unit}, named
template<symbol_text Symbol, auto...>
struct named_unit; // \notdef
template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS>
requires @\seebelownc@
struct named_unit<Symbol, QS>;
template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS, @\libconcept{PointOrigin}@ auto PO>
requires @\seebelownc@
struct named_unit<Symbol, QS, PO>;
template<symbol_text Symbol>
requires @\seebelownc@
struct named_unit<Symbol>;
template<symbol_text Symbol, @\libconcept{Unit}@ auto U>
requires @\seebelownc@
struct named_unit<Symbol, U>;
template<symbol_text Symbol, @\libconcept{Unit}@ auto U, @\libconcept{PointOrigin}@ auto PO>
requires @\seebelownc@
struct named_unit<Symbol, U, PO>;
template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS>
requires @\seebelownc@
struct named_unit<Symbol, U, QS>;
template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS,
@\libconcept{PointOrigin}@ auto PO>
requires @\seebelownc@
struct named_unit<Symbol, U, QS, PO>;
// \ref{qty.prefixed.unit}, prefixed
template<symbol_text Symbol, @\libconcept{UnitMagnitude}@ auto M, @\libconcept{PrefixableUnit}@ auto U>
requires @\seebelownc@
struct prefixed_unit;
// \ref{qty.common.unit}, common
template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
struct common_unit;
// \ref{qty.derived.unit}, derived
template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_unit;
// \ref{qty.unit.one}, one
struct one;
inline constexpr one @\libglobal{one}@{};
// named derived units of a quantity of dimension one
inline constexpr struct @\libglobal{percent}@ final : named_unit<"%", mag_ratio<1, 100> * one> {
} @\libglobal{percent}@;
inline constexpr struct @\libglobal{per_mille}@ final :
named_unit<symbol_text{u8"\u2030" /* @\unicode{2030}{PER MILLE SIGN}@ */, "%o"},
mag_ratio<1, 1000> * one> {
} @\libglobal{per_mille}@;
inline constexpr struct @\libglobal{parts_per_million}@ final :
named_unit<"ppm", mag_ratio<1, 1'000'000> * one> {
} @\libglobal{parts_per_million}@;
inline constexpr auto @\libglobal{ppm}@ = parts_per_million;
// \ref{qty.unit.ops}, operations
consteval @\libconcept{Unit}@ auto inverse(@\libconcept{Unit}@ auto u);
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Unit}@ U>
requires @\seebelownc@
consteval @\libconcept{Unit}@ auto pow(U u);
consteval @\libconcept{Unit}@ auto sqrt(@\libconcept{Unit}@ auto u);
consteval @\libconcept{Unit}@ auto cbrt(@\libconcept{Unit}@ auto u);
consteval @\libconcept{Unit}@ auto square(@\libconcept{Unit}@ auto u);
consteval @\libconcept{Unit}@ auto cubic(@\libconcept{Unit}@ auto u);
// \ref{qty.unit.cmp}, comparison
template<@\libconcept{Unit}@ From, @\libconcept{Unit}@ To>
consteval bool convertible(From from, To to);
// \ref{qty.unit.obs}, observers
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(@\libconcept{AssociatedUnit}@ auto u);
consteval @\libconcept{Unit}@ auto get_unit(@\libconcept{AssociatedUnit}@ auto u);
consteval @\libconcept{Unit}@ auto get_common_unit(@\libconcept{Unit}@ auto... us)
requires @\seebelownc@;
// \ref{qty.unit.sym.fmt}, symbol formatting
enum class @\libglobal{unit_symbol_solidus}@ : std::int8_t {
one_denominator,
always,
never,
default_denominator = one_denominator
};
enum class @\libglobal{unit_symbol_separator}@ : std::int8_t {
space,
half_high_dot,
default_separator = space
};
struct @\libglobal{unit_symbol_formatting}@ {
character_set char_set = character_set::default_character_set;
unit_symbol_solidus solidus = unit_symbol_solidus::default_denominator;
unit_symbol_separator separator = unit_symbol_separator::default_separator;
};
template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Unit}@ U>
constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {});
template<unit_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Unit}@ U>
consteval std::string_view unit_symbol(U);
// \ref{qty.ref.concepts}, concepts
template<typename T>
concept @\deflibconcept{Reference}@ = @\seebelownc@;
template<typename T, auto QS>
concept @\deflibconcept{ReferenceOf}@ = @\seebelownc@;
// \ref{qty.ref.syn}, class template \tcode{reference}
template<@\libconcept{QuantitySpec}@ Q, @\libconcept{Unit}@ U>
struct reference;
// \ref{qty.ref.ops}, operations
template<typename FwdRep, @\libconcept{Reference}@ R,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr quantity<R{}, Rep> operator*(FwdRep&& lhs, R r);
template<typename FwdRep, @\libconcept{Reference}@ R,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr @\libconcept{Quantity}@ auto operator/(FwdRep&& lhs, R);
template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator*(FwdQ&& q, R);
template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator/(FwdQ&& q, R);
template<@\libconcept{Reference}@ R, typename Rep>
requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator*(R, Rep&&) = delete;
template<@\libconcept{Reference}@ R, typename Rep>
requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator/(R, Rep&&) = delete;
template<@\libconcept{Reference}@ R, typename Q>
requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator*(R, Q&&) = delete;
template<@\libconcept{Reference}@ R, typename Q>
requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator/(R, Q&&) = delete;
// \ref{qty.ref.obs}, observers
template<typename Q, typename U>
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(reference<Q, U>);
template<typename Q, typename U>
consteval @\libconcept{Unit}@ auto get_unit(reference<Q, U>);
consteval @\libconcept{AssociatedUnit}@ auto get_common_reference(@\libconcept{AssociatedUnit}@ auto u1,
@\libconcept{AssociatedUnit}@ auto u2,
@\libconcept{AssociatedUnit}@ auto... rest)
requires @\seebelownc@;
template<@\libconcept{Reference}@ R1, @\libconcept{Reference}@ R2, @\libconcept{Reference}@... Rest>
consteval @\libconcept{Reference}@ auto get_common_reference(R1 r1, R2 r2, Rest... rest)
requires @\seebelownc@;
// \ref{qty.rep}, representation
enum class @\libglobal{quantity_character}@ { scalar, complex, vector, tensor };
// \ref{qty.rep.traits}, traits
// \ref{qty.fp.traits}, floating-point
template<typename Rep>
constexpr bool treat_as_floating_point = @\seebelownc@;
// \ref{qty.char.traits}, quantity character
template<typename T>
constexpr bool disable_scalar = false;
template<>
inline constexpr bool @\libspec{disable_scalar}{bool}@<bool> = true;
template<typename T>
constexpr bool @\libspec{disable_scalar}{std::complex}@<std::complex<T>> = true;
template<typename T>
constexpr bool disable_complex = false;
template<typename T>
constexpr bool disable_vector = false;
// \ref{qty.val.traits}, values
template<typename Rep>
struct representation_values;
// \ref{qty.rep.cpos}, customization point objects
inline namespace @\unspec@ {
inline constexpr @\unspec@ real = @\unspec@;
inline constexpr @\unspec@ imag = @\unspec@;
inline constexpr @\unspec@ modulus = @\unspec@;
inline constexpr @\unspec@ magnitude = @\unspec@;
}
// \ref{qty.rep.concepts}, concepts
template<typename T>
concept Representation = @\seebelownc@;
template<typename T, quantity_character Ch>
concept RepresentationOf = @\seebelownc@;
// \ref{qty}, quantity
// \ref{qty.like}, interoperability
template<typename T>
struct quantity_like_traits; // \notdef
template<typename T>
concept QuantityLike = @\seebelownc@;
// \ref{qty.syn}, class template \tcode{quantity}
template<typename T>
concept Quantity = @\seebelownc@;
template<typename Q, auto QS>
concept QuantityOf = @\seebelownc@;
template<@\libconcept{Reference}@ auto R, @\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
2024-09-08 08:20:26 +02:00
class quantity;
2024-10-12 22:25:53 -04:00
// \ref{qty.delta}, construction helper \tcode{delta}
template<@\libconcept{Reference}@ R>
struct delta_;
template<@\libconcept{Reference}@ auto R>
constexpr delta_<decltype(R)> @\libglobal{delta}@{};
// \ref{qty.non.mem.conv}, non-member conversions
template<@\libconcept{Unit}@ auto ToU, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);
template<@\libconcept{Representation}@ ToRep, @\seebelownc@>
requires @\seebelownc@
constexpr quantity<@\seebelownc@, ToRep> value_cast(@\seebelownc@ q);
template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);
template<@\libconcept{Quantity}@ ToQ, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(@\seebelownc@ q);
template<@\libconcept{QuantitySpec}@ auto ToQS, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto quantity_cast(@\seebelownc@ q);
}
// \ref{qty.common.type}, \tcode{std::common_type} specializations
template<mp_units::@\libconcept{Quantity}@ Q1, mp_units::@\libconcept{Quantity}@ Q2>
requires @\seebelownc@
struct std::common_type<Q1, Q2>;
template<mp_units::@\libconcept{Quantity}@ Q, mp_units::@\libconcept{Representation}@ Value>
requires @\seebelownc@
struct std::common_type<Q, Value>;
template<mp_units::@\libconcept{Quantity}@ Q, mp_units::@\libconcept{Representation}@ Value>
requires requires { typename std::common_type<Q, Value>; }
struct @\libspec{std::common_type}{quantity}@<Value, Q> : std::common_type<Q, Value> {};
namespace mp_units {
// \ref{qty.pt}, quantity point
// \ref{qty.pt.orig}, point origin
// \ref{qty.pt.orig.concepts}, concepts
template<typename T>
concept PointOrigin = @\seebelownc@;
template<typename T, auto QS>
concept PointOriginFor = @\seebelownc@;
// \ref{qty.pt.orig.types}, types
// \ref{qty.abs.pt.orig}, absolute
template<@\libconcept{QuantitySpec}@ auto QS>
struct absolute_point_origin;
// \ref{qty.rel.pt.orig}, relative
template<@\libconcept{QuantityPoint}@ auto QP>
struct relative_point_origin;
// \ref{qty.zeroth.pt.orig}, zeroth
template<@\libconcept{QuantitySpec}@ auto QS>
struct zeroth_point_origin_;
template<@\libconcept{QuantitySpec}@ auto QS>
constexpr zeroth_point_origin_<QS> @\libglobal{zeroth_point_origin}@{};
// \ref{qty.def.pt.orig}, default
template<@\libconcept{Reference}@ R>
consteval @\libconcept{PointOriginFor}@<get_quantity_spec(R{})> auto default_point_origin(R);
// \ref{qty.pt.like}, interoperability
template<typename T>
struct quantity_point_like_traits; // \notdef
template<typename T>
concept QuantityPointLike = @\seebelownc@;
// \ref{qty.pt.syn}, class template \tcode{quantity_point}
template<typename T>
concept QuantityPoint = @\seebelownc@;
template<typename QP, auto V>
concept QuantityPointOf = @\seebelownc@;
template<@\libconcept{Reference}@ auto R,
@\libconcept{PointOriginFor}@<get_quantity_spec(R)> auto PO = default_point_origin(R),
@\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
2024-09-08 08:20:26 +02:00
class quantity_point;
2024-10-12 22:25:53 -04:00
// \ref{qty.point}, construction helper \tcode{point}
template<@\libconcept{Reference}@ R>
struct point_;
template<@\libconcept{Reference}@ auto R>
constexpr point_<decltype(R)> @\libglobal{point}@{};
// \ref{qty.pt.non.mem.conv}, non-member conversions
template<@\libconcept{Unit}@ auto ToU, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);
template<@\libconcept{Representation}@ ToRep, @\seebelownc@>
requires @\seebelownc@
constexpr quantity_point<@\seebelownc@, @\seebelownc@, ToRep> value_cast(@\seebelownc@ qp);
template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);
template<@\libconcept{Quantity}@ ToQ, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);
template<@\libconcept{QuantityPoint}@ ToQP, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(@\seebelownc@ qp);
template<@\libconcept{QuantitySpec}@ auto ToQS, @\seebelownc@>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto quantity_cast(@\seebelownc@ qp);
2024-09-08 08:20:26 +02:00
}
\end{codeblock}
2024-10-12 22:25:53 -04:00
\rSec2[mp.units.systems.syn]{Module \tcode{mp_units.systems} synopsis}
2024-09-08 08:20:26 +02:00
\indexmodule{mp_units.systems}%
\begin{codeblock}
export module mp_units.systems;
export import mp_units.core;
import std;
export namespace mp_units {
2024-10-12 22:25:53 -04:00
// \ref{qty.chrono}, \tcode{std::chrono} interoperability
template<typename Rep, typename Period>
struct quantity_like_traits<std::chrono::duration<Rep, Period>>;
template<typename Clock>
struct chrono_point_origin_;
template<typename Clock>
constexpr chrono_point_origin_<Clock> @\libglobal{chrono_point_origin}@{};
template<typename Clock, typename Rep, typename Period>
struct quantity_point_like_traits<
std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>>;
2024-09-08 08:20:26 +02:00
}
\end{codeblock}
2024-10-12 22:25:53 -04:00
\rSec1[qty.utils]{Utilities}
\rSec2[qty.utils.non.types]{Non-types}
\indexlibraryglobalexpos{is-specialization-of}
\indexlibraryglobalexpos{is-derived-from-specialization-of}
\begin{itemdecl}
template<typename T, template<@\seebelow@> typename U>
consteval bool @\exposidnc{is-specialization-of}@(); // \expos
template<typename T, template<@\seebelow@> typename U>
consteval bool @\exposidnc{is-derived-from-specialization-of}@(); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
For the first signature,
\tcode{true} of \tcode{T} is a specialization of \tcode{U}, and
\tcode{false} otherwise.
\item
For the second signature,
\tcode{true} if \tcode{T} has exactly one public base class
that is a specialization of \tcode{U}
and has no other base class that is a specialization of \tcode{U}, and
\tcode{false} otherwise.
\end{itemize}
\pnum
\remarks
An implementation provides enough overloads for all arguments to \tcode{U}.
\end{itemdescr}
\rSec2[qty.ratio]{Ratio}
\indexlibraryglobalexpos{ratio}
\indexlibrarymemberexpos{operator==}{ratio}
\indexlibrarymemberexpos{operator<=>}{ratio}
\indexlibrarymemberexpos{operator-}{ratio}
\indexlibrarymemberexpos{operator+}{ratio}
\indexlibrarymemberexpos{operator/}{ratio}
\indexlibraryexposmemberexpos{is-integral}{ratio}
\begin{codeblock}
namespace mp_units {
struct @\exposidnc{ratio}@ { // \expos
std::intmax_t num;
std::intmax_t den;
consteval @\exposidnc{ratio}@(std::intmax_t n, std::intmax_t d = 1);
friend consteval bool operator==(@\exposidnc{ratio}@, @\exposidnc{ratio}@) = default;
friend consteval auto operator<=>(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs) { return (lhs - rhs).num <=> 0; }
friend consteval @\exposidnc{ratio}@ operator-(@\exposidnc{ratio}@ r) { return {-r.num, r.den}; }
friend consteval @\exposidnc{ratio}@ operator+(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs)
{
return {lhs.num * rhs.den + lhs.den * rhs.num, lhs.den * rhs.den};
}
friend consteval @\exposidnc{ratio}@ operator-(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs) { return lhs + (-rhs); }
friend consteval @\exposidnc{ratio}@ operator*(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs);
friend consteval @\exposidnc{ratio}@ operator/(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs)
{
return lhs * @\exposidnc{ratio}@{rhs.den, rhs.num};
}
};
consteval bool @\exposidnc{is-integral}@(@\exposidnc{ratio}@ r) { return r.num % r.den == 0; }
consteval @\exposidnc{ratio}@ @\exposidnc{common-ratio}@(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2);
}
\end{codeblock}
\pnum
\exposid{ratio} represents the rational number $\tcode{num}/\tcode{den}$.
\pnum
Unless otherwise specified,
in the following descriptions,
let \tcode{R(r)} be \tcode{std::ratio<N, D>},
where \tcode{N} and \tcode{D} are the values of \tcode{r.num} and \tcode{r.den}.
\indexlibraryctorexpos{ratio}
\begin{itemdecl}
consteval @\exposidnc{ratio}@(std::intmax_t n, std::intmax_t d = 1);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{N} and \tcode{D} be the values of \tcode{n} and \tcode{d}.
Let \tcode{R} be \tcode{std::ratio<N, D>}.
\pnum
\effects
Equivalent to
\tcode{R}.
\pnum
\ensures
\tcode{num == R::num \&\& den == R::den} is \tcode{true}.
\end{itemdescr}
\indexlibrarymemberexpos{operator*}{ratio}
\begin{itemdecl}
friend consteval @\exposidnc{ratio}@ operator*(@\exposidnc{ratio}@ lhs, @\exposidnc{ratio}@ rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{Res} be \tcode{std::ratio_multiply<R(lhs), R(rhs)>}.
\pnum
\effects
Equivalent to:
\tcode{return \{Res::num, Res::den\};}
\end{itemdescr}
\indexlibraryexposmemberexpos{common-ratio}{ratio}
\begin{itemdecl}
consteval @\exposidnc{ratio}@ @\exposidnc{common-ratio}@(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{Res} be equal to
\begin{codeblock}
std::common_type<std::chrono::duration<int, R(r1)>,
std::chrono::duration<int, R(r2)>>::type::period
\end{codeblock}
\pnum
\effects
Equivalent to:
\tcode{return \{Res::num, Res::den\};}
\end{itemdescr}
\rSec2[qty.sym.txt]{Symbol text}
\indexlibraryglobal{symbol_text}
\begin{codeblock}
namespace mp_units {
template<std::size_t N, std::size_t M>
class symbol_text {
public:
std::fixed_u8string<N> @\exposidnc{utf8}@; // \expos
std::fixed_string<M> @\exposidnc{portable}@; // \expos
// constructors
constexpr symbol_text(char portable);
consteval symbol_text(const char (&portable)[N + 1]);
constexpr symbol_text(const std::fixed_string<N>& portable);
consteval symbol_text(const char8_t (&utf8)[N + 1], const char (&portable)[M + 1]);
constexpr symbol_text(const std::fixed_u8string<N>& utf8,
const std::fixed_string<M>& portable);
// observers
constexpr const auto& @\libmember{utf8}{symbol_text}@() const { return @\exposidnc{utf8}@; }
constexpr const auto& @\libmember{portable}{symbol_text}@() const { return @\exposidnc{portable}@; }
constexpr bool @\libmember{empty}{symbol_text}@() const { return utf8().empty(); }
// string operations
template<std::size_t N2, std::size_t M2>
friend constexpr symbol_text<N + N2, M + M2> operator+(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs);
// comparison
template<std::size_t N2, std::size_t M2>
friend constexpr bool operator==(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs) noexcept;
template<std::size_t N2, std::size_t M2>
friend constexpr auto operator<=>(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs) noexcept;
};
symbol_text(char) -> symbol_text<1, 1>;
template<std::size_t N>
symbol_text(const char (&)[N]) -> symbol_text<N - 1, N - 1>;
template<std::size_t N>
symbol_text(const std::fixed_string<N>&) -> symbol_text<N, N>;
template<std::size_t N, std::size_t M>
symbol_text(const char8_t (&)[N], const char (&)[M]) -> symbol_text<N - 1, M - 1>;
template<std::size_t N, std::size_t M>
symbol_text(const std::fixed_u8string<N>&, const std::fixed_string<M>&) -> symbol_text<N, M>;
}
\end{codeblock}
\pnum
\tcode{symbol_text} represents a symbol text.
\exposid{utf8} stores its UTF-8 representation, and
\exposid{portable} stores its portable representation.
\tcode{symbol_text<N, M>} is a structural type\irefcppx{temp.param}{term.structural.type}.
\pnum
In the descriptions that follow,
it is a \Fundescx{Precondition} that
\begin{itemize}
\item
values of \tcode{char} are in the basic literal character set\irefcpp{lex.charset}, and
\item
for a parameter of the form \tcode{const \placeholdernc{CharT} (\&\placeholdernc{txt})[\placeholder{M}]},
\tcode{(\placeholdernc{txt}[\placeholdernc{M} - 1] == \placeholdernc{CharT}())} is \tcode{true}.
\end{itemize}
\indexlibraryctor{symbol_text}
\begin{itemdecl}
constexpr symbol_text(char portable);
consteval symbol_text(const char (&portable)[N + 1]);
constexpr symbol_text(const std::fixed_string<N>& portable);
consteval symbol_text(const char8_t (&utf8)[N + 1], const char (&portable)[M + 1]);
constexpr symbol_text(const std::fixed_u8string<N>& utf8, const std::fixed_string<M>& portable);
\end{itemdecl}
\begin{itemdescr}
\pnum
For the constructors without a parameter named \tcode{utf8},
let \tcode{utf8} be:
\begin{codeblock}
std::bit_cast<std::fixed_u8string<N>>(std::basic_fixed_string(portable))
\end{codeblock}
\pnum
\effects
Equivalent to the \fakegrammarterm{mem-initializer-list}:
\begin{codeblock}
@\exposid{utf8}@{utf8}, @\exposidnc{portable}@{portable}
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator+}{symbol_text}
\begin{itemdecl}
template<std::size_t N2, std::size_t M2>
friend constexpr symbol_text<N + N2, M + M2> operator+(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return symbol_text<N + N2, M + M2>(lhs.utf8() + rhs.utf8(),
lhs.portable() + rhs.portable());
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator==}{symbol_text}
\indexlibrarymember{operator<=>}{symbol_text}
\begin{itemdecl}
template<std::size_t N2, std::size_t M2>
friend constexpr bool operator==(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs) noexcept;
template<std::size_t N2, std::size_t M2>
friend constexpr auto operator<=>(const symbol_text& lhs,
const symbol_text<N2, M2>& rhs) noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return std::make_tuple(std::cref(lhs.utf8()), std::cref(lhs.portable())) @\atsign@
std::make_tuple(std::cref(rhs.utf8()), std::cref(rhs.portable()));
\end{codeblock}
\end{itemdescr}
\rSec2[qty.sym.expr]{Symbolic expressions}
\rSec3[qty.sym.expr.general]{General}
\pnum
Subclause \ref{qty.sym.expr} specifies the components
used to maintain ordered, simplified, and readable
argument lists in the names of specializations.
\begin{example}
\begin{codeblock}
using namespace si::unit_symbols;
int x = kg * km / square(h); // error: cannot construct from
// \tcode{derived_unit<si::kilo_<si::gram>, si::kilo_<si::metre>, per<power<non_si::hour, 2>>>}
\end{codeblock}
The library ensures \tcode{decltype(kg * km / square(h))} is styled-like as commented in diagnostics,
provided that, in the implementation-defined total order of types,
\tcode{decltype(kg)} is less than \tcode{decltype(km)}.
\end{example}
\rSec3[qty.sym.expr.concepts]{Concept \ecname{SymbolicConstant}}
2024-09-08 08:20:26 +02:00
\begin{itemdecl}
2024-10-12 22:25:53 -04:00
template<typename T>
concept @\defexposconceptnc{SymbolicConstant}@ = // \expos
std::is_empty_v<T> && std::is_final_v<T> && std::is_trivially_default_constructible_v<T> &&
std::is_trivially_copy_constructible_v<T> && std::is_trivially_move_constructible_v<T> &&
std::is_trivially_destructible_v<T>;
\end{itemdecl}
\pnum
The concept \exposconcept{SymbolicConstant}
is used to constrain the types
that are used in symbolic expressions.
\rSec3[qty.sym.expr.types]{Types}
\indexlibraryglobal{per}
\begin{codeblock}
namespace mp_units {
template<typename T, typename... Ts>
struct per final {};
}
\end{codeblock}
\pnum
\tcode{per} is used to store arguments with negative exponents.
A specialization of \tcode{per}
represents the product of the inverse of its template arguments.
A program that instantiates a specialization of \tcode{per}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.
\indexlibraryglobal{power}
\begin{codeblock}
namespace mp_units {
template<typename F, int Num, int... Den>
requires @\seebelownc@
struct power final {
using @\exposidnc{factor}@ = F; // \expos
static constexpr @\exposidnc{ratio}@ @\exposidnc{exponent}@{Num, Den...}; // \expos
};
}
\end{codeblock}
\pnum
\tcode{power} represents a power\irefiev{102-02-08}
of the form $\tcode{F}^{\tcode{Num}/\tcode{Den}}$.
\begin{note}
\tcode{Den} is optional to shorten the type name when \tcode{Den} is \tcode{1}.
\end{note}
A program that instantiates a specialization of \tcode{power}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.
\pnum
Let \tcode{r} be \tcode{\exposidnc{ratio}\{Num, Den...\}}.
Let \tcode{\placeholder{is-valid-ratio}} be
\tcode{true} if \tcode{r} is a valid constant expression, and
\tcode{false} otherwise.
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\placeholdernc{is-valid-ratio}@ && (r > @\exposidnc{ratio}@{0}) && (r != @\exposidnc{ratio}@{1})
\end{codeblock}
\rSec3[qty.sym.expr.algos]{Algorithms}
\indexlibraryglobalexpos{expr-type}
\begin{codeblock}
template<typename T>
using @\exposidnc{expr-type}@ = @\seebelownc@; // \expos
\end{codeblock}
\pnum
\tcode{\exposidnc{expr-type}<T>} denotes
\tcode{U} if \tcode{T} is of the form \tcode{power<U, Ints...>}, and
\tcode{T} otherwise.
\indexlibraryglobalexpos{type-less-impl}
\begin{itemdecl}
template<typename T, typename U>
consteval bool @\exposidnc{type-less-impl}@(); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{true} if \tcode{T} is less than \tcode{U}
in an implementation-defined total order for types, and
\tcode{false} otherwise.
\end{itemdescr}
\indexlibraryglobalexpos{type-less}
\begin{codeblock}
template<typename Lhs, typename Rhs>
struct @\exposidnc{type-less}@ : // \expos
std::bool_constant<@\exposidnc{is-specialization-of}@<Rhs, power>() ||
@\exposidnc{type-less-impl}@<@\exposidnc{expr-type}@<Lhs>, @\exposidnc{expr-type}@<Rhs>>()> {};
\end{codeblock}
\pnum
\exposid{type-less} meets the requirements of
the \tcode{Pred} parameter of the symbolic expression algorithms below.
\indexlibraryglobalexpos{type-list}
\indexlibraryglobalexpos{expr-fractions}
\begin{codeblock}
template<typename... Ts>
struct @\exposidnc{type-list}@ {}; // \expos
template<typename OneType, typename... Ts>
struct @\exposidnc{expr-fractions}@ { // \expos
using @\exposidnc{num}@ = @\seebelownc@; // \expos
using @\exposidnc{den}@ = @\seebelownc@; // \expos
}
\end{codeblock}
\pnum
\exposid{expr-fractions} divides a symbolic expression to numerator and denominator parts.
Let \tcode{EF} be a specialization of \exposid{expr-fractions}.
\begin{itemize}
\item
If \tcode{EF} is of the form \tcode{\exposidnc{expr-fractions}<OneType, Ts..., per<Us...>>},
then
\begin{itemize}
\item
\tcode{EF::\exposidnc{num}} denotes \tcode{\exposidnc{type-list}<Ts...>}, and
\item
\tcode{EF::\exposidnc{den}} denotes \tcode{\exposidnc{type-list}<Us...>}.
\end{itemize}
\item
Otherwise, \tcode{EF} is of the form \tcode{\exposidnc{expr-fractions}<OneType, Ts...>}, and
\begin{itemize}
\item
\tcode{EF::\exposidnc{num}} denotes \tcode{\exposidnc{type-list}<Ts...>}, and
\item
\tcode{EF::\exposidnc{den}} denotes \tcode{\exposidnc{type-list}<>}.
\end{itemize}
\end{itemize}
\pnum
The symbolic expression algorithms perform operations on symbolic constants.
A symbolic constant is a type that is a model of \exposconcept{SymbolicConstant}.
\begin{example}
The dimension \tcode{dim_length}, the quantity \tcode{time}, and the unit \tcode{one} are symbolic constants.
\end{example}
The algorithms also support
powers with a symbolic constant base and a rational exponent,
products thereof, and
fractions thereof.
\indexlibraryglobalexpos{expr-multiply}
\indexlibraryglobalexpos{expr-divide}
\indexlibraryglobalexpos{expr-invert}
\indexlibraryglobalexpos{expr-pow}
\begin{itemdecl}
template<template<typename...> typename To, typename OneType,
template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename Lhs, typename Rhs>
consteval auto @\exposidnc{expr-multiply}@(Lhs, Rhs); // \expos
template<template<typename...> typename To, typename OneType,
template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename Lhs, typename Rhs>
consteval auto @\exposidnc{expr-divide}@(Lhs lhs, Rhs rhs); // \expos
template<template<typename...> typename To, typename OneType, typename T>
consteval auto @\exposidnc{expr-invert}@(T); // \expos
template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To,
typename OneType, template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename T>
requires(Den != 0)
consteval auto @\exposidnc{expr-pow}@(T); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\mandates
\begin{itemize}
\item
\tcode{OneType} is the neutral element\irefiev{102-01-19} of the operation, and
\item
\tcode{Pred} is a \oldconcept{BinaryTypeTrait}\irefcpp{meta.rqmts}
with a base characteristic of \tcode{std::bool_constant<B>}.
\tcode{Pred<T, U>} implements a total order for types;
\tcode{B} is \tcode{true} if \tcode{T} is ordered before \tcode{U}, and \tcode{false} otherwise.
\end{itemize}
\pnum
\effects
\pnum
First, inputs to the operations are obtained from the types of the function parameters.
If the type of a function parameter is:
\begin{itemize}
\item
A specialization of \tcode{To},
then its input is the product of its template arguments, and
the following also apply.
\item
A specialization of \tcode{per},
then its input is the product of the inverse of its template arguments, and
the following also apply.
\item
A specialization of the form \tcode{power<F, Num>},
then its input is $\tcode{F}^\tcode{Num}$, or
a specialization of the form \tcode{power<F, Num, Den>},
then its input is $\tcode{F}^{\tcode{Num}/\tcode{Den}}$, and
the following also applies.
\item
Otherwise, the input is the symbolic constant itself.
\end{itemize}
\begin{example}
Item by item, this algorithm step goes from the \Cpp{} parameter type
\tcode{decltype(km / square(h))},
styled in diagnostics like
\tcode{derived_unit<si::kilo_<si::metre>, per<power<non_si::hour, 2>>},
\begin{itemize}
\item
to $\tcode{decltype(km)} \times \tcode{per<power<decltype(h), 2>}$ (product of \tcode{To}'s arguments),
\item
to $\tcode{decltype(km)} \times 1/\tcode{power<decltype(h), 2>}$ (product of inverse of \tcode{per}'s arguments),
\item
to $\tcode{decltype(km)} \times 1/\tcode{decltype(h)}^2$ (\tcode{power}s as powers),
\item
to $\txtrm{a} \times 1/\txtrm{b}^2$ where $\txtrm{a} = \tcode{decltype(km)}$ and $\txtrm{b} = \tcode{decltype(h)}$ (symbolic substitution)
in the mathematical domain.
\end{itemize}
\end{example}
\pnum
Then, the operation takes place:
\begin{itemize}
\item
\exposid{expr-multiply} multiplies its inputs,
\item
\exposid{expr-divide} divides the input of its first parameter by the input of its second parameter,
\item
\exposid{expr-invert} divides $1$ by its input, and
\item
\exposid{expr-pow} raises its input to the $\tcode{Num}/\tcode{Den}$.
\end{itemize}
\pnum
Finally, let $r$ be the result of the operation simplified as follows:
\begin{itemize}
\item
All terms are part of the same fraction (if any).
\item
There is at most a single term with a given symbolic constant.
\item
There are no negative exponents.
\item
$1$ is only present as $r$ and as a numerator with a denominator not equal to $1$.
\end{itemize}
\begin{example}
Item by item: \\
$x \times 1/y \times 1/x^2$ \\
$= x/(y x^2)$ (single fraction) \\
$= x^{-1}/y$ (unique symbolic constants) \\
$= 1/(x^1 y)$ (positive exponents) \\
$= 1/(xy)$ (non-redundant $1$s) \\
\end{example}
\pnum
\returns
$r$ is mapped to the return type:
\begin{itemize}
\item
If $r = 1$, returns \tcode{OneType\{\}}.
\item
Otherwise, if $r$ is a symbolic constant, returns $r$.
\item
Otherwise, first applies the following mappings to the terms of $r$:
\begin{itemize}
\item
$x^{n/d}$ is mapped to \tcode{power<$x$, $n$, $d$>}, and
$x^{n}$ is mapped to \tcode{power<$x$, $n$>}, and
\item
$1$ is mapped to \tcode{OneType\{\}}.
\end{itemize}
\item
Then, a denominator $x$ of $r$ (if any) is mapped to \tcode{per<$x$>}.
\item
Then, sorts $r$ without \tcode{per} (if any) and
the template arguments of \tcode{per} (if any)
according to \tcode{Pred}.
\item
Finally, returns \tcode{To<$r$>\{\}}, where \tcode{per} (if any) is the last argument.
\end{itemize}
\pnum
\remarks
A valid template argument list for \tcode{To} and \tcode{per}
is formed by interspersing commas between each mapped term.
If a mapping to \tcode{std::intmax_t} is not representable,
the program is ill-formed.
\end{itemdescr}
\pnum
\exposid{expr-map} maps the contents of one symbolic expression to another resulting in a different type list.
\indexlibraryglobalexpos{expr-map}
\begin{itemdecl}
template<template<typename> typename Proj, template<typename...> typename To, typename OneType,
template<typename, typename> typename Pred = @\exposidnc{type-less}@, typename T>
consteval auto @\exposidnc{expr-map}@(T); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
\tcode{\exposidnc{expr-type-map}<U>} be
\tcode{power<Proj<F>, Ints...>} if \tcode{U} is of the form \tcode{power<F, Ints...>}, and
\tcode{Proj<U>} otherwise,
\item
\tcode{\exposidnc{map-power}(u)} be
\tcode{pow<Ints...>(F\{\})} if \tcode{decltype(u)} is of the form \tcode{power<F, Ints...>}, and
\tcode{u} otherwise, and
\item
\tcode{Nums} and \tcode{Dens}
be packs denoting the template arguments of
\tcode{T::\exposidnc{nums}} and \tcode{T::\exposidnc{dens}}, respectively.
\end{itemize}
\pnum
\returns
\begin{codeblock}
(OneType{} * ... * @\exposidnc{map-power}@(@\exposidnc{expr-type-map}@<Nums>{})) /
(OneType{} * ... * @\exposidnc{map-power}@(@\exposidnc{expr-type-map}@<Dens>{}))
\end{codeblock}
\end{itemdescr}
\rSec1[qty.ref]{Reference}
\rSec2[qty.ref.general]{General}
\pnum
Subclause \ref{qty.ref} specifies the components
for describing the reference of a quantity\irefiev{112-01-01}.
\rSec2[qty.dim]{Dimension}
\rSec3[qty.dim.general]{General}
\pnum
Subclause \ref{qty.dim} specifies the components
for defining the dimension of a quantity\irefiev{112-01-11}.
\rSec3[qty.dim.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Dimension}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{dimension-interface}@>;
template<typename T>
concept @\defexposconceptnc{BaseDimension}@ = // \expos
@\libconcept{Dimension}@<T> && (@\exposidnc{is-derived-from-specialization-of}@<T, base_dimension>());
template<typename T, auto D>
concept @\deflibconcept{DimensionOf}@ = @\libconcept{Dimension}@<T> && @\libconcept{Dimension}@<decltype(D)> && (T{} == D);
\end{itemdecl}
\rSec3[qty.dim.types]{Types}
\begin{codeblock}
namespace mp_units {
template<symbol_text Symbol>
struct @\libglobal{base_dimension}@ : @\exposidnc{dimension-interface}@ {
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
};
}
\end{codeblock}
\pnum
\tcode{base_dimension} is used
to define the dimension of a base quantity\irefiev{112-01-08}.
\tcode{Symbol} is its symbolic representation.
\begin{example}
\begin{codeblock}
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
\end{codeblock}
\end{example}
\indexlibraryglobal{derived_dimension}
\begin{codeblock}
namespace mp_units {
template<typename... Expr>
struct @\exposidnc{derived-dimension-impl}@ // \expos
: @\exposidnc{expr-fractions}@<struct dimension_one, Expr...> {};
template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_dimension final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<Expr...> {};
}
\end{codeblock}
\pnum
\tcode{derived_dimension} is used by the library
to represent the dimension of a derived quantity\irefiev{112-01-10}.
\begin{example}
\begin{codeblock}
constexpr auto dim_acceleration = isq::speed.dimension / isq::dim_time;
int x = dim_acceleration; // error: cannot construct from
// \tcode{derived_dimension<isq::dim_length, per<power<isq::dim_time, 2>>>}
\end{codeblock}
\end{example}
A program that instantiates a specialization of \tcode{derived_dimension}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.
\indexlibraryglobal{dimension_one}
\begin{codeblock}
namespace mp_units {
struct dimension_one final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<> {};
}
\end{codeblock}
\pnum
\tcode{dimension_one} represents the dimension of a quantity of dimension one\irefiev{112-01-13}.
\rSec3[qty.dim.ops]{Operations}
\indexlibraryglobalexpos{dimension-interface}
\begin{codeblock}
namespace mp_units {
struct @\exposidnc{dimension-interface}@ { // \expos
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval @\libconcept{Dimension}@ auto operator*(Lhs, Rhs);
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval @\libconcept{Dimension}@ auto operator/(Lhs, Rhs);
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
};
}
\end{codeblock}
\indexlibrarymember{operator*}{Dimension}
\begin{itemdecl}
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval @\libconcept{Dimension}@ auto operator*(Lhs, Rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-multiply}<derived_dimension, struct dimension_one>(Lhs\{\}, Rhs\{\})}.
\end{itemdescr}
\indexlibrarymember{operator/}{Dimension}
\begin{itemdecl}
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval @\libconcept{Dimension}@ auto operator/(Lhs, Rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-divide}<derived_dimension, struct dimension_one>(Lhs\{\}, Rhs\{\})}.
\end{itemdescr}
\indexlibrarymember{operator==}{Dimension}
\begin{itemdecl}
template<@\libconcept{Dimension}@ Lhs, @\libconcept{Dimension}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<Lhs, Rhs>}.
\end{itemdescr}
\indexlibrarymember{inverse}{Dimension}
\begin{itemdecl}
consteval @\libconcept{Dimension}@ auto inverse(@\libconcept{Dimension}@ auto d);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{dimension_one / d}.
\end{itemdescr}
\indexlibrarymember{pow}{Dimension}
\begin{itemdecl}
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Dimension}@ D>
requires(Den != 0)
consteval @\libconcept{Dimension}@ auto pow(D d);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-pow}<Num, Den, derived_dimension, struct dimension_one>(d)}.
\end{itemdescr}
\indexlibrarymember{sqrt}{Dimension}
\begin{itemdecl}
consteval @\libconcept{Dimension}@ auto sqrt(@\libconcept{Dimension}@ auto d);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 2>(d)}.
\end{itemdescr}
\indexlibrarymember{cbrt}{Dimension}
\begin{itemdecl}
consteval @\libconcept{Dimension}@ auto cbrt(@\libconcept{Dimension}@ auto d);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 3>(d)}.
\end{itemdescr}
\rSec3[qty.dim.sym.fmt]{Symbol formatting}
\indexlibrarymember{dimension_symbol_to}{Dimension}
\begin{itemdecl}
template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Dimension}@ D>
constexpr Out dimension_symbol_to(Out out, D d, const dimension_symbol_formatting& fmt = {});
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
TBD.
\pnum
\returns
TBD.
\end{itemdescr}
\indexlibrarymember{dimension_symbol}{Dimension}
\begin{itemdecl}
template<dimension_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Dimension}@ D>
consteval std::string_view dimension_symbol(D);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
TBD.
\end{codeblock}
\end{itemdescr}
\rSec2[qty.spec]{Quantity specification}
\rSec3[qty.spec.general]{General}
\pnum
Subclause \ref{qty.spec} specifies the components
for defining a quantity\irefiev{112-01-01}.
\rSec3[qty.spec.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{QuantitySpec}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{quantity-spec-interface}@>;
template<typename T>
concept @\defexposconceptnc{QuantityKindSpec}@ = // \expos
@\libconcept{QuantitySpec}@<T> && @\exposidnc{is-specialization-of}@<T, kind_of_>();
template<typename T>
concept @\defexposconceptnc{NamedQuantitySpec}@ = // \expos
@\libconcept{QuantitySpec}@<T> && @\exposidnc{is-derived-from-specialization-of}@<T, quantity_spec>() &&
(!@\exposconceptnc{QuantityKindSpec}@<T>);
template<typename T>
concept @\defexposconceptnc{DerivedQuantitySpec}@ = // \expos
@\libconcept{QuantitySpec}@<T> &&
(@\exposidnc{is-specialization-of}@<T, derived_quantity_spec>() ||
(@\exposconceptnc{QuantityKindSpec}@<T> &&
@\exposidnc{is-specialization-of}@<decltype(auto(T::@\exposidnc{quantity-spec}@)), derived_quantity_spec>()));
template<auto Child, auto Parent>
concept @\defexposconceptnc{ChildQuantitySpecOf}@ = (@\exposidnc{is-child-of}@(Child, Parent)); // \expos
template<auto To, auto From>
concept @\defexposconceptnc{NestedQuantityKindSpecOf}@ = // \expos
@\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> &&
(get_kind(From) != get_kind(To)) && @\exposconceptnc{ChildQuantitySpecOf}@<To, get_kind(From).@\exposidnc{quantity-spec}@>;
template<auto From, auto To>
concept @\defexposconceptnc{QuantitySpecConvertibleTo}@ = // \expos
@\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> && implicitly_convertible(From, To);
template<auto From, auto To>
concept @\defexposconceptnc{QuantitySpecExplicitlyConvertibleTo}@ = // \expos
@\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> && explicitly_convertible(From, To);
template<auto From, auto To>
concept @\defexposconceptnc{QuantitySpecCastableTo}@ = // \expos
@\libconcept{QuantitySpec}@<decltype(From)> && @\libconcept{QuantitySpec}@<decltype(To)> && castable(From, To);
template<typename T, auto QS>
concept @\deflibconcept{QuantitySpecOf}@ =
@\libconcept{QuantitySpec}@<T> && @\libconcept{QuantitySpec}@<decltype(QS)> && @\exposconceptnc{QuantitySpecConvertibleTo}@<T{}, QS> &&
!@\exposconceptnc{NestedQuantityKindSpecOf}@<T{}, QS> &&
(@\exposconceptnc{QuantityKindSpec}@<T> || !@\exposconceptnc{NestedQuantityKindSpecOf}@<QS, T{}>);
template<typename T>
concept @\defexposconceptnc{QSProperty}@ = (!@\libconcept{QuantitySpec}@<T>); // \expos
\end{itemdecl}
\rSec3[qty.spec.types]{Types}
\rSec4[named.qty]{Named}
\indexlibraryglobal{is_kind}
\indexlibraryglobal{quantity_spec}
\begin{codeblock}
namespace mp_units {
struct is_kind {};
template<@\exposconceptnc{BaseDimension}@ auto Dim, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Dim, Args...> : @\exposidnc{quantity-spec-interface}@ {
using @\exposidnc{base-type}@ = quantity_spec;
static constexpr @\exposconceptnc{BaseDimension}@ auto dimension = Dim;
static constexpr quantity_character character = @\seebelownc@;
};
template<@\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<Eq, Args...> : @\exposidnc{quantity-spec-interface}@ {
using @\exposidnc{base-type}@ = quantity_spec;
static constexpr auto @\exposidnc{equation}@ = Eq;
static constexpr @\libconcept{Dimension}@ auto dimension = Eq.dimension;
static constexpr quantity_character character = @\seebelownc@;
};
template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{QSProperty}@ auto... Args>
struct quantity_spec<QS, Args...> : @\exposidnc{quantity-spec-interface}@ {
using @\exposidnc{base-type}@ = quantity_spec;
static constexpr auto @\exposidnc{parent}@ = QS;
static constexpr auto @\exposidnc{equation}@ = @\exposidnc{parent}@.@\exposidnc{equation}@; // \expos, present only
// if the \fakegrammarterm{qualified-id} \tcode{\exposidnc{parent}.\exposidnc{equation}} is valid and denotes an object
static constexpr @\libconcept{Dimension}@ auto dimension = @\exposidnc{parent}@.dimension;
static constexpr quantity_character character = @\seebelownc@;
};
template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args>
requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@<Eq, QS>
struct quantity_spec<QS, Eq, Args...> : @\exposidnc{quantity-spec-interface}@ {
using @\exposidnc{base-type}@ = quantity_spec;
static constexpr auto @\exposidnc{parent}@ = QS;
static constexpr auto @\exposidnc{equation}@ = Eq;
static constexpr @\libconcept{Dimension}@ auto dimension = @\exposidnc{parent}@.dimension;
static constexpr quantity_character character = @\seebelownc@;
};
}
\end{codeblock}
\pnum
A \defnadj{named}{quantity} is a type that models \exposconceptnc{NamedQuantitySpec}.
A specialization of \tcode{quantity_spec} is used as a base type when defining a named quantity.
\pnum
In the following descriptions, let \tcode{Q} be a named quantity defined with an alluded signature.
The identifier of \tcode{Q} represents its quantity name\irefiev{112-01-02}.
\pnum
Let \tcode{Ch} be an enumerator value of \tcode{quantity_character}.
The possible arguments to \tcode{quantity_spec} are
\begin{itemize}
\item
$(\text{a base quantity dimension}, \opt{\tcode{Ch}})$,
\item
$(\text{a quantity calculus}, \opt{\tcode{Ch}})$,
\item
$(\text{a named quantity}, \opt{\tcode{Ch}}, \opt{\tcode{is_kind}})$, and
\item
$(\text{a named quantity}, \text{a quantity calculus}, \opt{\tcode{Ch}}, \opt{\tcode{is_kind}})$.
\end{itemize}
\pnum
If the first argument is a base quantity dimension,
then \tcode{Q} is that base quantity\irefiev{112-01-08}.
If an argument is a quantity calculus\irefiev{112-01-30} \placeholder{C},
then \tcode{Q} is implicitly convertible from \placeholder{C}.
If the first argument is a named quantity,
then \tcode{Q} is of its kind\irefiev{112-01-04}.
\pnum
The member \tcode{character} represents
the set of the numerical value of \tcode{Q}\iref{qty.char.traits}
and is equal to
\begin{itemize}
\item
\tcode{Ch} if specified,
\item
otherwise, \tcode{quantity_character::scalar} for the first signature, and
\item
otherwise, \tcode{(BC).character},
where \tcode{BC} is the argument preceding \tcode{Ch} in the signatures above.
\end{itemize}
\pnum
\tcode{is_kind} specifies \tcode{Q} to start a new hierarchy tree of a kind.
\pnum
Optional arguments may appear in any order.
\pnum
\begin{example}
\begin{codeblock}
// The first signature defines a base quantity.
inline constexpr struct length final : quantity_spec<dim_length> {
} length; // Length is a base quantity.
// The second signature defines a derived quantity.
inline constexpr struct area final : quantity_spec<pow<2>(length)> {
} area; // An area equals length by length.
// The third and fourth signatures add a leaf to a hierarchy of kinds.
inline constexpr struct width final : quantity_spec<length> {
} width; // Width is a kind of length.
// The fourth signature also refines the calculus required for implicit conversions.
inline constexpr struct angular_measure final :
quantity_spec<dimensionless, arc_length / radius, is_kind> {
} angular_measure; // Requires an arc length per radius, not just any quantity of dimension one.
\end{codeblock}
\end{example}
\rSec4[derived.qty]{Derived}
\indexlibraryglobal{derived_quantity_spec}
\begin{codeblock}
namespace mp_units {
template<@\defexposconceptnc{NamedQuantitySpec}@ Q>
using @\exposidnc{to-dimension}@ = decltype(auto(Q::dimension)); // \expos
template<typename... Expr>
struct @\exposidnc{derived-quantity-spec-impl}@ : // \expos
@\exposidnc{quantity-spec-interface}@,
@\exposidnc{expr-fractions}@<struct dimensionless, Expr...> {
using @\exposidnc{base-type}@ = @\exposidnc{derived-quantity-spec-impl}@;
using @\exposidnc{base}@ = @\exposidnc{expr-fractions}@<struct dimensionless, Expr...>;
static constexpr @\libconcept{Dimension}@ auto dimension =
@\exposidnc{expr-map}@<@\exposidnc{to-dimension}@, derived_dimension, struct dimension_one>(@\exposidnc{base}@{});
static constexpr quantity_character character = @\seebelownc@;
};
template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_quantity_spec final : @\exposidnc{derived-quantity-spec-impl}@<Expr...> {};
}
\end{codeblock}
\pnum
\tcode{derived_quantity_spec} is used by the library
to represent the result of a quantity calculus not equal to a named quantity.
\begin{example}
\begin{codeblock}
constexpr auto area = pow<2>(isq::length);
int x = area; // error: cannot construct from \tcode{derived_quantity_spec<power<isq::length, 2>>}
\end{codeblock}
\end{example}
A program that instantiates a specialization of \tcode{derived_quantity_spec}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.
\pnum
Let
\begin{itemize}
\item
\tcode{Nums} and \tcode{Dens}
be packs denoting the template arguments of
\tcode{\exposidnc{base}::\exposidnc{nums}} and \tcode{\exposidnc{base}::\exposidnc{dens}}, respectively,
\item
\tcode{\placeholdernc{QUANTITY-CHARACTER-OF}(Pack)} be
\begin{codeblock}
std::max({quantity_character::scalar, @\exposidnc{expr-type}@<Pack>::character...})
\end{codeblock}
and
\item
\tcode{num_char} be \tcode{\placeholdernc{QUANTITY-CHARACTER-OF}(Nums)} and
\tcode{den_char} be \tcode{\placeholdernc{QUANTITY-CHARACTER-OF}(Dens)}.
\end{itemize}
The member \tcode{character} is equal to
\tcode{quantity_character::scalar} if \tcode{num_char == den_char} is \tcode{true}, and
\tcode{std::max(num_char, den_char)} otherwise.
\rSec4[dimless.qty]{Base quantity of dimension one}
\indexlibraryglobal{dimensionless}
\begin{codeblock}
namespace mp_units {
struct dimensionless final : quantity_spec<derived_quantity_spec<>> {};
}
\end{codeblock}
\pnum
\tcode{dimensionless} represents the base quantity of dimension one\irefiev{112-01-13}.
\rSec4[kind.of.qty]{Kind of}
\indexlibraryglobal{kind_of_}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{QuantitySpec}@ Q>
requires(!@\exposconceptnc{QuantityKindSpec}@<Q>) && (@\exposidnc{get-kind-tree-root}@(Q{}) == Q{})
struct kind_of_ final : Q::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = kind_of_; // \expos
static constexpr auto @\exposidnc{quantity-spec}@ = Q{}; // \expos
};
}
\end{codeblock}
\pnum
\tcode{kind_of<Q>} represents a kind of quantity\irefiev{112-01-04} \tcode{Q}.
\rSec3[qty.spec.utils]{Utilities}
\indexlibrarymemberexpos{QuantitySpec}{clone-kind-of}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto... From, @\libconcept{QuantitySpec}@ Q>
consteval @\libconcept{QuantitySpec}@ auto @\exposidnc{clone-kind-of}@(Q q); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr ((... && @\exposconceptnc{QuantityKindSpec}@<decltype(From)>))
return kind_of<Q{}>;
else
return q;
\end{codeblock}
\end{itemdescr}
\indexlibrarymemberexpos{QuantitySpec}{remove-kind}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Q>
consteval auto @\exposidnc{remove-kind}@(Q q); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposconceptnc{QuantityKindSpec}@<Q>)
return Q::@\exposidnc{quantity-spec}@;
else
return q;
\end{codeblock}
\end{itemdescr}
\indexlibrarymemberexpos{QuantitySpec}{make-reference}
\indexlibrarymemberexpos{Unit}{make-reference}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ QS, @\libconcept{Unit}@ U>
requires(!@\libconcept{AssociatedUnit}@<U>) || @\libconcept{UnitOf}@<U, QS{}>
consteval @\libconcept{Reference}@ auto @\exposidnc{make-reference}@(QS, U u); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (requires { requires get_quantity_spec(U{}) == QS{}; })
return u;
else
return reference<QS, U>{};
\end{codeblock}
\end{itemdescr}
\rSec3[qty.spec.ops]{Operations}
\indexlibraryglobalexpos{quantity-spec-interface}
\begin{codeblock}
namespace mp_units {
struct @\exposidnc{quantity-spec-interface}@ { // \expos
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval @\libconcept{QuantitySpec}@ auto operator*(Lhs lhs, Rhs rhs);
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval @\libconcept{QuantitySpec}@ auto operator/(Lhs lhs, Rhs rhs);
template<typename Self, @\libconcept{UnitOf}@<Self{}> U>
consteval @\libconcept{Reference}@ auto operator[](this Self self, U u);
template<typename Self, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@<Q::quantity_spec, Self{}>
constexpr @\libconcept{Quantity}@ auto operator()(this Self self, FwdQ&& q);
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
};
}
\end{codeblock}
\indexlibrarymember{operator*}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval @\libconcept{QuantitySpec}@ auto operator*(Lhs lhs, Rhs rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{clone-kind-of}@<Lhs{}, Rhs{}>(@\exposidnc{expr-multiply}@<derived_quantity_spec, struct dimensionless>(
@\exposidnc{remove-kind}@(lhs), @\exposidnc{remove-kind}@(rhs)))
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator/}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval @\libconcept{QuantitySpec}@ auto operator/(Lhs lhs, Rhs rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{clone-kind-of}@<Lhs{}, Rhs{}>(@\exposidnc{expr-divide}@<derived_quantity_spec, struct dimensionless>(
@\exposidnc{remove-kind}@(lhs), @\exposidnc{remove-kind}@(rhs)))
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator[]}{QuantitySpec}
\begin{itemdecl}
template<typename Self, @\libconcept{UnitOf}@<Self{}> U>
consteval @\libconcept{Reference}@ auto operator[](this Self self, U u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{make-reference}(self, u)}.
\end{itemdescr}
\indexlibrarymember{operator()}{QuantitySpec}
\begin{itemdecl}
template<typename Self, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@<Q::quantity_spec, Self{}>
constexpr @\libconcept{Quantity}@ auto operator()(this Self self, FwdQ&& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
quantity{std::forward<FwdQ>(q).@\exposidnc{numerical-value}@, @\exposidnc{make-reference}@(self, Q::unit)}
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator==}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Lhs, @\libconcept{QuantitySpec}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<Lhs, Rhs>}.
\end{itemdescr}
\indexlibrarymember{inverse}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto inverse(@\libconcept{QuantitySpec}@ auto q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{dimensionless / q}.
\end{itemdescr}
\indexlibrarymember{pow}{QuantitySpec}
\begin{itemdecl}
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{QuantitySpec}@ Q>
requires(Den != 0)
consteval @\libconcept{QuantitySpec}@ auto pow(Q q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{clone-kind-of}@<Q{}>(
@\exposidnc{expr-pow}@<Num, Den, derived_quantity_spec, struct dimensionless>(@\exposidnc{remove-kind}@(q)));
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{sqrt}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto sqrt(@\libconcept{QuantitySpec}@ auto q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 2>(q)}.
\end{itemdescr}
\indexlibrarymember{cbrt}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto cbrt(@\libconcept{QuantitySpec}@ auto q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 3>(q)}.
\end{itemdescr}
\rSec3[qty.spec.hier.algos]{Hierarchy algorithms}
\rSec4[qty.spec.conv]{Conversion}
\indexlibrarymember{implicitly_convertible}{QuantitySpec}
\begin{itemdecl}
consteval bool implicitly_convertible(QuantitySpec auto from, QuantitySpec auto to);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}
\indexlibrarymember{explicitly_convertible}{QuantitySpec}
\begin{itemdecl}
consteval bool explicitly_convertible(QuantitySpec auto from, QuantitySpec auto to);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}
\indexlibrarymember{castable}{QuantitySpec}
\begin{itemdecl}
consteval bool castable(QuantitySpec auto from, QuantitySpec auto to);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}
\indexlibrarymember{interconvertible}{QuantitySpec}
\begin{itemdecl}
consteval bool interconvertible(QuantitySpec auto qs1, QuantitySpec auto qs2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(qs1, qs2) \&\& implicitly_convertible(qs2, qs1)}.
\end{itemdescr}
\rSec4[qty.get.kind]{Get kind}
\indexlibrarymemberexpos{QuantitySpec}{get-kind-tree-root}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Q>
consteval @\libconcept{QuantitySpec}@ auto @\exposidnc{get-kind-tree-root}@(Q q); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{\exposconceptnc{QuantityKindSpec}<Q>} is \tcode{true},
returns \tcode{\exposidnc{remove-kind}(q)}.
\item
Otherwise, if
\tcode{\exposidnc{is-derived-from-specialization-of}<Q, quantity_spec>()}
is \tcode{true}, and
the specialization of \tcode{Q::quantity_spec} has a template argument equal to \tcode{is_kind},
returns \tcode{q}.
\item
Otherwise, if \tcode{Q::\exposidnc{parent}} is a valid expression,
returns \tcode{\exposidnc{get-kind-tree-root}(Q::\exposidnc{parent})}.
\item
Otherwise, if \tcode{\exposconceptnc{DerivedQuantitySpec}<Q>} is \tcode{true},
returns
\begin{codeblock}
@\exposidnc{expr-map}@<@\exposidnc{to-kind}@, derived_quantity_spec, struct dimensionless>(q)
\end{codeblock}
where \exposid{to-kind} is defined as follows:
\begin{codeblock}
template<@\libconcept{QuantitySpec}@ Q>
using @\exposidnc{to-kind}@ = decltype(@\exposidnc{get-kind-tree-root}@(Q{})); // \expos
\end{codeblock}
\item
Otherwise, returns \tcode{q}.
\end{itemize}
\end{itemdescr}
\indexlibrarymember{get_kind}{QuantitySpec}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Q>
consteval @\exposconceptnc{QuantityKindSpec}@ auto get_kind(Q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{kind_of<\exposidnc{get-kind-tree-root}(Q\{\})>}.
\end{itemdescr}
\rSec4[get.common.qty.spec]{Get common quantity specification}
\indexlibrarymember{get_common_quantity_spec}{QuantitySpec}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto get_common_quantity_spec(@\libconcept{QuantitySpec}@ auto... qs)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
\tcode{q1} be \tcode{qs...[0]},
\item
\tcode{q2} be \tcode{qs...[1]},
\item
\tcode{Q1} be \tcode{decltype(q1)},
\item
\tcode{Q2} be \tcode{decltype(q2)}, and
\item
\tcode{rest} be a pack denoting the elements of \tcode{qs} without \tcode{q1} and \tcode{q2}.
\end{itemize}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (sizeof...(qs) == 1)
return q1;
else if constexpr (sizeof...(qs) == 2) {
using QQ1 = decltype(@\exposidnc{remove-kind}@(q1));
using QQ2 = decltype(@\exposidnc{remove-kind}@(q2));
if constexpr (std::is_same_v<Q1, Q2>)
return q1;
else if constexpr (@\exposconceptnc{NestedQuantityKindSpecOf}@<Q1{}, Q2{}>)
return QQ1{};
else if constexpr (@\exposconceptnc{NestedQuantityKindSpecOf}@<Q2{}, Q1{}>)
return QQ2{};
else if constexpr ((@\exposconceptnc{QuantityKindSpec}@<Q1> && !@\exposconceptnc{QuantityKindSpec}@<Q2>) ||
(@\exposconceptnc{DerivedQuantitySpec}@<QQ1> && @\exposconceptnc{NamedQuantitySpec}@<QQ2> &&
implicitly_convertible(Q1{}, Q2{})))
return q2;
else if constexpr ((!@\exposconceptnc{QuantityKindSpec}@<Q1> && @\exposconceptnc{QuantityKindSpec}@<Q2>) ||
(@\exposconceptnc{NamedQuantitySpec}@<QQ1> && @\exposconceptnc{DerivedQuantitySpec}@<QQ2> &&
implicitly_convertible(Q2{}, Q1{})))
return q1;
else if constexpr (constexpr auto common_base = @\exposidnc{get-common-base}@<Q1{}, Q2{}>())
return *common_base;
else if constexpr (implicitly_convertible(Q1{}, Q2{}))
return q2;
else if constexpr (implicitly_convertible(Q2{}, Q1{}))
return q1;
else if constexpr (implicitly_convertible(@\exposidnc{get-kind-tree-root}@(Q1{}),
@\exposidnc{get-kind-tree-root}@(Q2{})))
return @\exposidnc{get-kind-tree-root}@(q2);
else
return @\exposidnc{get-kind-tree-root}@(q1);
} else
return get_common_quantity_spec(get_common_quantity_spec(q1, q2), rest...);
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(sizeof...(qs) != 0 &&
(sizeof...(qs) == 1 ||
(sizeof...(qs) == 2 &&
(@\exposconceptnc{QuantitySpecConvertibleTo}@<@\exposidnc{get-kind-tree-root}@(Q1{}), @\exposidnc{get-kind-tree-root}@(Q2{})> ||
@\exposconceptnc{QuantitySpecConvertibleTo}@<@\exposidnc{get-kind-tree-root}@(Q2{}), @\exposidnc{get-kind-tree-root}@(Q1{})>)) ||
requires { get_common_quantity_spec(get_common_quantity_spec(q1, q2), rest...); }))
\end{codeblock}
\end{itemdescr}
\rSec4[qty.get.common.base]{Get common base}
\pnum
In this subclause and \ref{qty.is.child.of},
let the kind of quantity\irefiev{112-01-04} hierarchy of \tcode{q} be the tuple
$h(\tcode{q}) = ( \tcode{q}, \tcode{q.par}, \tcode{q.par.par}, \ldots )$,
where \tcode{par} is \exposidnc{parent}.
\indexlibrarymemberexpos{QuantitySpec}{get-common-base}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto A, @\libconcept{QuantitySpec}@ auto B>
consteval auto @\exposidnc{get-common-base}@(); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
$a_s$ be the number of elements in $h(\tcode{A})$,
\item
$b_s$ be the number of elements in $h(\tcode{B})$,
\item
$s$ be $\operatorname{min}(a_s, b_s)$,
\item
$A$ be a tuple of the last $s$ elements of $h(\tcode{A})$, and
\item
$B$ be a tuple of the last $s$ elements of $h(\tcode{B})$.
\end{itemize}
\pnum
\effects
Looks for $x$, the first pair-wise equal element in $A$ and $B$.
\pnum
\returns
\tcode{std::optional($x$)}, if $x$ is found, and \tcode{std::optional<\unspec>()} otherwise.
\end{itemdescr}
\rSec4[qty.is.child.of]{Is child of}
\indexlibrarymemberexpos{QuantitySpec}{is-child-of}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ Child, @\libconcept{QuantitySpec}@ Parent>
consteval bool @\exposidnc{is-child-of}@(Child ch, Parent p); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
If $h(\tcode{p})$ has more elements than $h(\tcode{ch})$, returns \tcode{false}.
Otherwise, let $C$ be a tuple of the last $s$ elements of $h(\tcode{ch})$,
where $s$ is the number of elements in $h(\tcode{p})$.
Returns \tcode{$C_0$ == p}.
\end{itemdescr}
\rSec2[qty.unit]{Unit}
\rSec3[qty.unit.general]{General}
\pnum
Subclause \ref{qty.unit} specifies the components
for defining a unit of measurement\irefiev{112-01-14}.
\rSec3[qty.unit.mag]{Magnitude}
\rSec4[qty.unit.mag.general]{General}
\pnum
Subclause \ref{qty.unit.mag} specifies the components
used to represent the numerical value\irefiev{112-01-29} of a unit
with support for powers\irefiev{102-02-08} of real numbers\irefiev{102-02-05}.
\rSec4[qty.unit.mag.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{MagConstant}@ = @\exposconceptnc{SymbolicConstant}@<T> && @\exposidnc{is-derived-from-specialization-of}@<T, mag_constant>();
template<typename T>
concept @\deflibconcept{UnitMagnitude}@ = (@\exposidnc{is-specialization-of}@<T, @\exposidnc{unit-magnitude}@>());
template<typename T>
concept @\defexposconceptnc{MagArg}@ = std::@\stdconcept{integral}@<T> || @\libconcept{MagConstant}@<T>; // \expos
\end{itemdecl}
\rSec4[qty.unit.mag.types]{Types}
\indexlibraryglobal{mag_constant}
\begin{codeblock}
namespace mp_units {
template<symbol_text Symbol, long double Value>
requires(Value > 0)
struct mag_constant {
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
static constexpr long double @\exposidnc{value}@ = Value; // \expos
};
}
\end{codeblock}
A specialization of \tcode{mag_constant} represents a real number\irefiev{102-02-05}.
\tcode{Symbol} is its symbol, and
\tcode{Value} is (an approximation of) its value.
\indexlibraryglobalexpos{unit-magnitude}
\begin{codeblock}
namespace mp_units {
template<auto... Ms>
struct @\exposidnc{unit-magnitude}@ { // \expos
// \ref{qty.unit.mag.ops}, operations
template<@\libconcept{UnitMagnitude}@ M>
friend consteval @\libconcept{UnitMagnitude}@ auto operator*(@\exposidnc{unit-magnitude}@ lhs, M rhs);
friend consteval auto operator/(@\exposidnc{unit-magnitude}@ lhs, @\libconcept{UnitMagnitude}@ auto rhs);
template<@\libconcept{UnitMagnitude}@ Rhs>
friend consteval bool operator==(@\exposidnc{unit-magnitude}@, Rhs);
template<int Num, int Den = 1>
friend consteval auto @\exposidnc{pow}@(@\exposidnc{unit-magnitude}@); // \expos
// \ref{qty.unit.mag.utils}, utilities
friend consteval bool @\exposidnc{is-positive-integral-power}@(@\exposidnc{unit-magnitude}@); // \expos
template<auto... Ms2>
friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@, // \expos
@\exposidnc{unit-magnitude}@<Ms2...>);
};
}
\end{codeblock}
\pnum
A specialization of \exposid{unit-magnitude}
represents the product of its template arguments.
\pnum
For the purposes of specifying the implementation-defined limits,
let the representation of the terms of \exposid{unit-magnitude} be the structure
\begin{codeblock}
struct {
@\exposidnc{ratio}@ exp;
@\exposidnc{base-type}@ base;
};
\end{codeblock}
representing the number $\tcode{base}^\tcode{exp}$,
where \exposid{base-type} is a model of \exposconcept{MagArg}.
\begin{itemize}
\item
There is a single term for each \exposid{base-type}.
\item
\tcode{exp.num} is not expanded into base.
\begin{note}
$2^3 = 8$ is not permitted.
\end{note}
\item
\tcode{exp.den} can reduce the base.
\begin{note}
$4^{1/2} = 2$ is permitted.
\end{note}
\item
If the result of an operation on \tcode{std::intmax_t} values is undefined,
the behavior is
\impldef{behavior of \exposid{unit-magnitude} operations that do not fit in a \tcode{std::intmax_t}}.
\end{itemize}
\rSec4[qty.unit.mag.ops]{Operations}
\indexlibrarymember{operator*}{UnitMagnitude}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ M>
friend consteval @\libconcept{UnitMagnitude}@ auto operator*(@\exposidnc{unit-magnitude}@ lhs, M rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{sizeof...(Ms) == 0} is \tcode{true}, returns \tcode{rhs}.
\item
Otherwise, if \tcode{std::is_same_v<M, \exposidnc{unit-magnitude}<>>}, returns \tcode{lhs}.
\item
Otherwise, returns an unspecified value equal to $\tcode{lhs} \times \tcode{rhs}$.
\end{itemize}
\end{itemdescr}
\indexlibrarymember{operator/}{UnitMagnitude}
\begin{itemdecl}
friend consteval auto operator/(@\exposidnc{unit-magnitude}@ lhs, @\libconcept{UnitMagnitude}@ auto rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{lhs * \exposid{pow}<-1>(rhs)}.
\end{itemdescr}
\indexlibrarymember{operator==}{UnitMagnitude}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ Rhs>
friend consteval bool operator==(@\exposidnc{unit-magnitude}@, Rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<\exposidnc{unit-magnitude}, Rhs>}.
\end{itemdescr}
\indexlibrarymemberexpos{UnitMagnitude}{pow}
\begin{itemdecl}
template<int Num, int Den = 1>
friend consteval auto @\exposidnc{pow}@(@\exposidnc{unit-magnitude}@ base); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{Num == 0} is \tcode{true}, returns \tcode{\exposidnc{unit-magnitude}<>\{\}}.
\item
Otherwise, returns an unspecified value equal to $\tcode{base}^{\tcode{Num}/\tcode{Den}}$.
\end{itemize}
\end{itemdescr}
\indexlibraryglobal{mag}
\begin{itemdecl}
template<@\exposconceptnc{MagArg}@ auto V>
constexpr @\libconcept{UnitMagnitude}@ auto mag = @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\constraints
\tcode{V} is greater than $0$.
\pnum
\effects
If \tcode{\libconcept{MagConstant}<decltype(V)>} is satisfied,
initializes \tcode{mag} with \tcode{\exposidnc{unit-magnitude}<V>\{\}}.
Otherwise, initializes \tcode{mag} with
an unspecified value equal to \tcode{V}.
\end{itemdescr}
\indexlibraryglobal{mag_ratio}
\begin{itemdecl}
template<std::intmax_t N, std::intmax_t D>
requires(N > 0)
constexpr @\libconcept{UnitMagnitude}@ auto mag_ratio = @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Initializes \tcode{mag_ratio} with
an unspecified value equal to $\tcode{N}/\tcode{D}$.
\end{itemdescr}
\indexlibraryglobal{mag_power}
\begin{itemdecl}
template<@\exposconceptnc{MagArg}@ auto Base, int Num, int Den = 1>
constexpr @\libconcept{UnitMagnitude}@ auto mag_power = @\exposidnc{pow}@<Num, Den>(mag<Base>);
\end{itemdecl}
\begin{itemdescr}
\pnum
\constraints
\tcode{Base} is greater than $0$.
\end{itemdescr}
\rSec4[qty.unit.mag.utils]{Utilities}
\indexlibrarymemberexpos{UnitMagnitude}{is-positive-integral-power}
\begin{itemdecl}
friend consteval bool @\exposidnc{is-positive-integral-power}@(@\exposidnc{unit-magnitude}@ x); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{false} if \tcode{x} has a negative or rational exponent, and
\tcode{true} otherwise.
\end{itemdescr}
\indexlibrarymemberexpos{UnitMagnitude}{common-magnitude}
\begin{itemdecl}
template<auto... Ms2>
friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@, @\exposidnc{unit-magnitude}@<Ms2...>); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
The largest magnitude \tcode{C}
such that each input magnitude is expressible
by only positive powers relative to \tcode{C}.
\end{itemdescr}
\rSec3[qty.unit.traits]{Traits}
\indexlibraryglobal{space_before_unit_symbol}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto U>
constexpr bool space_before_unit_symbol = true;
\end{itemdecl}
\begin{itemdescr}
\pnum
The formatting functions\iref{qty.unit.sym.fmt} use \tcode{space_before_unit_symbol}
to determine whether there is a space
between the numerical value and the unit symbol.
\pnum
\remarks
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
users may specialize \tcode{space_before_unit_symbol}
for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions\irefcpp{expr.const}
and have type \tcode{const bool}.
\end{itemdescr}
\rSec3[qty.unit.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Unit}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{unit-interface}@>;
template<typename T>
concept @\deflibconcept{PrefixableUnit}@ = @\libconcept{Unit}@<T> && @\exposidnc{is-derived-from-specialization-of}@<T, named_unit>();
template<typename T>
concept @\deflibconcept{AssociatedUnit}@ = @\libconcept{Unit}@<U> && @\exposidnc{has-associated-quantity}@(U{});
template<typename U, auto QS>
concept @\deflibconcept{UnitOf}@ = @\libconcept{AssociatedUnit}@<U> && @\libconcept{QuantitySpec}@<decltype(QS)> &&
@\exposconceptnc{QuantitySpecConvertibleTo}@<get_quantity_spec(U{}), QS> &&
(get_kind(QS) == get_kind(get_quantity_spec(U{})) ||
!@\exposconceptnc{NestedQuantityKindSpecOf}@<get_quantity_spec(U{}), QS>);
template<auto From, auto To>
concept @\defexposconceptnc{UnitConvertibleTo}@ = // \expos
@\libconcept{Unit}@<decltype(From)> && @\libconcept{Unit}@<decltype(To)> && (convertible(From, To));
template<typename U, auto FromU, auto QS>
concept @\defexposconceptnc{UnitCompatibleWith}@ = // \expos
@\libconcept{Unit}@<U> && @\libconcept{Unit}@<decltype(FromU)> && @\libconcept{QuantitySpec}@<decltype(QS)> &&
(!@\libconcept{AssociatedUnit}@<U> || @\libconcept{UnitOf}@<U, QS>) && @\exposconceptnc{UnitConvertibleTo}@<FromU, U{}>;
template<typename T>
concept @\defexposconceptnc{OffsetUnit}@ = @\libconcept{Unit}@<T> && requires { T::@\exposidnc{point-origin}@; }; // \expos
template<typename From, typename To>
concept @\defexposconceptnc{PotentiallyConvertibleTo}@ = // \expos
@\libconcept{Unit}@<From> && @\libconcept{Unit}@<To> &&
((@\libconcept{AssociatedUnit}@<From> && @\libconcept{AssociatedUnit}@<To> &&
implicitly_convertible(get_quantity_spec(From{}), get_quantity_spec(To{}))) ||
(!@\libconcept{AssociatedUnit}@<From> && !@\libconcept{AssociatedUnit}@<To>));
\end{itemdecl}
\rSec3[qty.unit.types]{Types}
\rSec4[qty.canon.unit]{Canonical}
\indexlibraryglobalexpos{canonical-unit}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
struct @\exposidnc{canonical-unit}@ { // \expos
M mag;
U reference_unit;
};
}
\end{codeblock}
\pnum
\exposid{canonical-unit} represents a unit expressed in terms of base units\irefiev{112-01-18}.
\begin{note}
Other types representing units are equal only if they have the same type.
\exposid{canonical-unit} is used to implement binary relations other than equality.
\end{note}
\tcode{reference_unit} is simplified\iref{qty.sym.expr.algos}.
\indexlibrarymemberexpos{Unit}{get-canonical-unit}
\begin{itemdecl}
consteval auto @\exposidnc{get-canonical-unit}@(@\libconcept{Unit}@ auto u); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
The instantiation of \exposid{canonical-unit} for \tcode{u}.
\end{itemdescr}
\rSec4[qty.scaled.unit]{Scaled}
\indexlibraryglobal{scaled_unit}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{UnitMagnitude}@ auto M, @\libconcept{Unit}@ U>
requires(M != @\exposidnc{unit-magnitude}@<>{} && M != mag<1>)
struct scaled_unit final : @\exposidnc{unit-interface}@ {
using @\exposidnc{base-type}@ = scaled_unit; // \expos
static constexpr @\libconcept{UnitMagnitude}@ auto @\exposidnc{mag}@ = M; // \expos
static constexpr U @\exposidnc{reference-unit}@{}; // \expos
static constexpr auto @\exposidnc{point-origin}@ = U::point_origin; // \expos, present only
// if the \fakegrammarterm{qualified-id} \tcode{U::point_origin} is valid and denotes an object
};
}
\end{codeblock}
\pnum
\tcode{scaled_unit<M, U>} is used by the library
to represent the unit $\tcode{M} \times \tcode{U}$.
\rSec4[qty.named.unit]{Named}
\indexlibraryglobal{named_unit}
\begin{codeblock}
namespace mp_units {
template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS>
requires(!Symbol.empty()) && @\exposconceptnc{BaseDimension}@<decltype(auto(QS.dimension))>
struct named_unit<Symbol, QS> : @\exposidnc{unit-interface}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
static constexpr auto @\exposidnc{quantity-spec}@ = QS; // \expos
};
template<symbol_text Symbol, @\exposconceptnc{QuantityKindSpec}@ auto QS, @\libconcept{PointOrigin}@ auto PO>
requires(!Symbol.empty()) && @\exposconceptnc{BaseDimension}@<decltype(auto(QS.dimension))>
struct named_unit<Symbol, QS, PO> : @\exposidnc{unit-interface}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
static constexpr auto @\exposidnc{quantity-spec}@ = QS; // \expos
static constexpr auto @\exposidnc{point-origin}@ = PO; // \expos
};
template<symbol_text Symbol>
requires(!Symbol.empty())
struct named_unit<Symbol> : @\exposidnc{unit-interface}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
};
template<symbol_text Symbol, @\libconcept{Unit}@ auto U>
requires(!Symbol.empty())
struct named_unit<Symbol, U> : decltype(U)::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
};
template<symbol_text Symbol, @\libconcept{Unit}@ auto U, @\libconcept{PointOrigin}@ auto PO>
requires(!Symbol.empty())
struct named_unit<Symbol, U, PO> : decltype(U)::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
static constexpr auto @\exposidnc{point-origin}@ = PO; // \expos
};
template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS>
requires(!Symbol.empty()) && (QS.dimension == @\exposidnc{get-associated-quantity}@(U).dimension)
struct named_unit<Symbol, U, QS> : decltype(U)::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
static constexpr auto @\exposidnc{quantity-spec}@ = QS; // \expos
};
template<symbol_text Symbol, @\libconcept{AssociatedUnit}@ auto U, @\exposconceptnc{QuantityKindSpec}@ auto QS,
@\libconcept{PointOrigin}@ auto PO>
requires(!Symbol.empty()) && (QS.dimension == @\exposidnc{get-associated-quantity}@(U).dimension)
struct named_unit<Symbol, U, QS, PO> : decltype(U)::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = named_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos
static constexpr auto @\exposidnc{quantity-spec}@ = QS; // \expos
static constexpr auto @\exposidnc{point-origin}@ = PO; // \expos
};
}
\end{codeblock}
\pnum
A \defnadj{named}{unit} is a type that models \libconcept{PrefixableUnit}.
A specialization of \tcode{named_unit} is used as a base type when defining a named unit.
\pnum
In the following descriptions, let \tcode{U} be a named unit defined with an alluded signature.
The identifier of \tcode{U} represents
its unit name\irefiev{112-01-15}
or special unit name\irefiev{112-01-16}.
\tcode{Symbol} is its unit symbol\irefiev{112-01-17}.
\pnum
The possible arguments to \tcode{named_unit} are
\begin{itemize}
\item
$(\text{the unit symbol}, \text{a kind of base quantity}, \opt{\text{a point origin}})$,
\item
$(\text{the unit symbol})$,
\item
$(\text{the unit symbol}, \text{a unit expression}, \opt{\text{a point origin}})$, and
\item
$(\text{the unit symbol}, \text{a unit expression}, \text{a kind of quantity}, \opt{\text{a point origin}})$.
\end{itemize}
\pnum
The first signature defines the unit of a base quantity
without a unit prefix\irefiev{112-01-26}.
The second signature defines a unit
that can be reused by several base quantities.
The third and fourth signatures with a unit expression argument \placeholder{E}
define \tcode{U} as implicitly convertible from \placeholder{E}.
The first and fourth signatures with a kind of quantity\irefiev{112-01-04} \placeholder{Q}
also restrict \tcode{U} to \placeholder{Q}.
\pnum
A point origin argument specifies the default point origin of \tcode{U}\iref{qty.pt.syn}.
\pnum
\begin{example}
\begin{codeblock}
// The first signature defines a base unit restricted to a kind of base quantity.
inline constexpr struct second final : named_unit<"s", kind_of<time>> {
} second;
// The third and fourth signatures give a name to the unit argument.
inline constexpr struct minute final : named_unit<"min", mag<60> * second> {
} minute; // $\txtrm{min} = 60 \txtrm{ s}$.
// The fourth signature also further restricts the kind of quantity.
inline constexpr struct hertz final : named_unit<"Hz", inverse(second), kind_of<frequency>> {
} hertz; // $\txtrm{Hz}$ can't measure becquerel, activity,
// or any other quantity with dimension $\txtrm{T}^{-1}$
// that isn't a kind of frequency.
\end{codeblock}
\end{example}
\rSec4[qty.prefixed.unit]{Prefixed}
\indexlibraryglobal{prefixed_unit}
\begin{codeblock}
namespace mp_units {
template<symbol_text Symbol, @\libconcept{UnitMagnitude}@ auto M, @\libconcept{PrefixableUnit}@ auto U>
requires(!Symbol.empty())
struct prefixed_unit : decltype(M * U)::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = prefixed_unit; // \expos
static constexpr auto @\exposidnc{symbol}@ = Symbol + U.@\exposidnc{symbol}@; // \expos
};
}
\end{codeblock}
\pnum
\tcode{prefixed_unit<Symbol, M, U>} represents the unit \tcode{U} with a unit prefix\irefiev{112-01-26}.
\tcode{Symbol} is the symbol of the unit prefix.
\tcode{M} is the factor of the unit prefix.
A specialization of \tcode{prefixed_unit} is used as a base type when defining a unit prefix.
\begin{example}
\begin{codeblock}
template<@\libconcept{PrefixableUnit}@ auto U>
struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U> {};
template<@\libconcept{PrefixableUnit}@ auto U>
constexpr kilo_<U> kilo;
inline constexpr auto kilogram = kilo<si::gram>;
\end{codeblock}
\end{example}
\rSec4[qty.common.unit]{Common}
\indexlibraryglobal{common_unit}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
struct common_unit final : decltype(@\exposidnc{get-common-scaled-unit}@(U1{}, U2{}, Rest{}...))::@\exposidnc{base-type}@
{
using @\exposidnc{base-type}@ = common_unit; // \expos
static constexpr auto @\exposidnc{common-unit}@ = // \expos
@\exposidnc{get-common-scaled-unit}@(U1{}, U2{}, Rest{}...);
};
}
\end{codeblock}
\pnum
\tcode{common_unit} is used by the library
to encapsulate a conversion factor between units\irefiev{112-01-33}
common to the operands of quantity addition.
\begin{example}
The result of \tcode{1 * km + 1 * mi}
has a common unit $[8/125] \txtrm{ m}$
encapsulated by \tcode{common_unit<mi, km>}.
\end{example}
A program that instantiates a specialization of \tcode{common_unit}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.
\begin{itemdecl}
template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
consteval @\libconcept{Unit}@ auto @\exposidnc{get-common-scaled-unit}@(U1, U2, Rest... rest) // \expos
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
constexpr auto res = [] {
constexpr auto canonical_lhs = @\exposidnc{get-canonical-unit}@(U1{});
constexpr auto canonical_rhs = @\exposidnc{get-canonical-unit}@(U2{});
constexpr auto common_mag = @\exposidnc{common-magnitude}@(canonical_lhs.mag, canonical_rhs.mag);
if constexpr (common_mag == mag<1>)
return canonical_lhs.reference_unit;
else
return scaled_unit<common_mag, decltype(auto(canonical_lhs.reference_unit))>{};
}();
if constexpr (sizeof...(rest) == 0)
return res;
else
return @\exposidnc{get-common-scaled-unit}@(res, rest...);
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(convertible(U1{}, U2{}) && (sizeof...(Rest) == 0 || requires {
@\exposidnc{get-common-scaled-unit}@(@\exposidnc{get-common-scaled-unit}@(u1, u2), rest...);
}))
\end{codeblock}
\end{itemdescr}
\rSec4[qty.derived.unit]{Derived}
\indexlibraryglobal{derived_unit}
\begin{codeblock}
namespace mp_units {
template<typename... Expr>
struct @\exposidnc{derived-unit-impl}@ : // \expos
@\exposidnc{unit-interface}@,
@\exposidnc{expr-fractions}@<struct one, Expr...> {
using @\exposidnc{base-type}@ = @\exposidnc{derived-unit-impl}@; // \expos
};
template<@\exposconceptnc{SymbolicConstant}@... Expr>
struct derived_unit final : @\exposidnc{derived-unit-impl}@<Expr...> {};
}
\end{codeblock}
\pnum
\tcode{derived_unit} is used by the library
to represent a derived unit\irefiev{112-01-19}.
\begin{example}
\begin{codeblock}
using namespace si::unit_symbols;
int x = m * m; // error: cannot construct from \tcode{derived_unit<power<si::metre, 2>>}
int y = m * s; // error: cannot construct from \tcode{derived_unit<si::metre, si::second>}
int z = m / s; // error: cannot construct from \tcode{derived_unit<si::metre, per<si::second>>}
\end{codeblock}
\end{example}
A program that instantiates a specialization of \tcode{derived_unit}
that is not a possible result of the library specifications
is ill-formed, no diagnostic required.
\rSec4[qty.unit.one]{One}
\indexlibraryglobal{one}
\begin{codeblock}
namespace mp_units {
struct one final : @\exposidnc{derived-unit-impl}@<> {};
}
\end{codeblock}
\pnum
\tcode{one} represents the base unit\irefiev{112-01-18} of a quantity of dimension one\irefiev{112-01-13}.
\rSec3[qty.unit.ops]{Operations}
\indexlibraryglobalexpos{unit-interface}
\begin{codeblock}
namespace mp_units {
struct @\exposidnc{unit-interface}@ { // \expos
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
friend consteval @\libconcept{Unit}@ auto operator*(M, U u);
friend consteval @\libconcept{Unit}@ auto operator*(@\libconcept{Unit}@ auto, @\libconcept{UnitMagnitude}@ auto) = delete;
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
friend consteval @\libconcept{Unit}@ auto operator/(M mag, U u);
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval @\libconcept{Unit}@ auto operator*(Lhs lhs, Rhs rhs);
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval @\libconcept{Unit}@ auto operator/(Lhs lhs, Rhs rhs);
// \ref{qty.unit.cmp}, comparison
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval bool equivalent(Lhs lhs, Rhs rhs);
};
}
\end{codeblock}
\indexlibrarymember{operator*}{UnitMagnitude}
\indexlibrarymember{operator*}{Unit}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
friend consteval @\libconcept{Unit}@ auto operator*(M, U u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (std::is_same_v<M, decltype(auto(mag<1>))>)
return u;
else if constexpr (@\exposidnc{is-specialization-of}@<U, scaled_unit>()) {
if constexpr (M{} * U::@\exposidnc{mag}@ == mag<1>)
return U::@\exposidnc{reference-unit}@;
else
return scaled_unit<M{} * U::@\exposidnc{mag}@, decltype(auto(U::@\exposidnc{reference-unit}@))>{};
} else
return scaled_unit<M{}, U>{};
\end{codeblock}
\end{itemdescr}
\begin{itemdecl}
friend consteval @\libconcept{Unit}@ auto operator*(@\libconcept{Unit}@ auto, @\libconcept{UnitMagnitude}@ auto) = delete;
\end{itemdecl}
\begin{itemdescr}
\pnum
\recommended
Suggest swapping the operands.
\end{itemdescr}
\indexlibrarymember{operator/}{UnitMagnitude}
\indexlibrarymember{operator/}{Unit}
\begin{itemdecl}
template<@\libconcept{UnitMagnitude}@ M, @\libconcept{Unit}@ U>
friend consteval @\libconcept{Unit}@ auto operator/(M mag, U u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{mag * inverse(u)}.
\end{itemdescr}
\indexlibrarymember{operator*}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval @\libconcept{Unit}@ auto operator*(Lhs lhs, Rhs rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-multiply}<derived_unit, struct one>(lhs, rhs)}.
\end{itemdescr}
\indexlibrarymember{operator/}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval @\libconcept{Unit}@ auto operator/(Lhs lhs, Rhs rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-divide}<derived_unit, struct one>(lhs, rhs)}.
\end{itemdescr}
\indexlibrarymember{inverse}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto inverse(@\libconcept{Unit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{one / u}.
\end{itemdescr}
\indexlibrarymember{pow}{Unit}
\begin{itemdecl}
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Unit}@ U>
requires(Den != 0)
consteval @\libconcept{Unit}@ auto pow(U u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{\exposidnc{expr-pow}<Num, Den, derived_unit, struct one>(u)}.
\end{itemdescr}
\indexlibrarymember{sqrt}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto sqrt(@\libconcept{Unit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 2>(u)}.
\end{itemdescr}
\indexlibrarymember{cbrt}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto cbrt(@\libconcept{Unit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<1, 3>(u)}.
\end{itemdescr}
\indexlibrarymember{square}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto square(@\libconcept{Unit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<2>(u)}.
\end{itemdescr}
\indexlibrarymember{cubic}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto cubic(@\libconcept{Unit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{pow<3>(u)}.
\end{itemdescr}
\rSec3[qty.unit.cmp]{Comparison}
\indexlibrarymember{operator==}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval bool operator==(Lhs, Rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{std::is_same_v<Lhs, Rhs>}.
\end{itemdescr}
\indexlibrarymember{equivalent}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ Lhs, @\libconcept{Unit}@ Rhs>
friend consteval bool equivalent(Lhs lhs, Rhs rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
const auto lhs_canonical = @\exposidnc{get-canonical-unit}@(lhs);
const auto rhs_canonical = @\exposidnc{get-canonical-unit}@(rhs);
return lhs_canonical.mag == rhs_canonical.mag &&
lhs_canonical.reference_unit == rhs_canonical.reference_unit;
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{convertible}{Unit}
\begin{itemdecl}
template<@\libconcept{Unit}@ From, @\libconcept{Unit}@ To>
consteval bool convertible(From from, To to);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (std::is_same_v<From, To>)
return true;
else if constexpr (@\exposconceptnc{PotentiallyConvertibleTo}@<From, To>)
return std::is_same_v<decltype(@\exposidnc{get-canonical-unit}@(from).reference_unit),
decltype(@\exposidnc{get-canonical-unit}@(to).reference_unit)>;
else
return false;
\end{codeblock}
\end{itemdescr}
\rSec3[qty.unit.obs]{Observers}
\indexlibrarymember{get_quantity_spec}{AssociatedUnit}
\begin{itemdecl}
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(@\libconcept{AssociatedUnit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{kind_of<\exposidnc{get-associated-quantity}(u)>}.
\end{itemdescr}
\indexlibrarymember{get_unit}{AssociatedUnit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto get_unit(@\libconcept{AssociatedUnit}@ auto u);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{u}.
\end{itemdescr}
\indexlibrarymember{get_common_unit}{Unit}
\begin{itemdecl}
consteval @\libconcept{Unit}@ auto get_common_unit(@\libconcept{Unit}@ auto... us)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let
\begin{itemize}
\item
\tcode{u1} be \tcode{us...[0]},
\item
\tcode{u2} be \tcode{us...[1]},
\item
\tcode{U1} be \tcode{decltype(u1)},
\item
\tcode{U2} be \tcode{decltype(u2)}, and
\item
\tcode{rest} be a pack denoting the elements of \tcode{us} without \tcode{u1} and \tcode{u2}.
\end{itemize}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (sizeof...(us) == 1)
return u1;
else if constexpr (sizeof...(us) == 2) {
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<U1, common_unit>()) {
return @\textit{TBD.}@;
} else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<U2, common_unit>())
return get_common_unit(u2, u1);
else if constexpr (std::is_same_v<U1, U2>)
return u1;
else if constexpr (equivalent(U1{}, U2{})) {
if constexpr (std::@\stdconcept{derived_from}@<U1, typename U2::@\exposidnc{base-type}@>)
return u1;
else if constexpr (std::@\stdconcept{derived_from}@<U2, typename U1::@\exposidnc{base-type}@>)
return u2;
else
return std::conditional_t<@\exposidnc{type-less-impl}@<U1, U2>(), U1, U2>{};
} else {
constexpr auto canonical_lhs = @\exposidnc{get-canonical-unit}@(U1{});
constexpr auto canonical_rhs = @\exposidnc{get-canonical-unit}@(U2{});
if constexpr (@\exposidnc{is-positive-integral-power}@(canonical_lhs.mag / canonical_rhs.mag))
return u2;
else if constexpr (@\exposidnc{is-positive-integral-power}@(canonical_rhs.mag / canonical_lhs.mag))
return u1;
else {
if constexpr (@\exposidnc{type-less}@<U1, U2>{})
return common_unit<U1, U2>{};
else
return common_unit<U2, U1>{};
}
}
} else
return get_common_unit(get_common_unit(u1, u2), rest...);
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(sizeof...(us) != 0 && (sizeof...(us) == 1 || //
(sizeof...(us) == 2 && convertible(U1{}, U2{})) ||
requires { get_common_unit(get_common_unit(u1, u2), rest...); }))
\end{codeblock}
\end{itemdescr}
\rSec3[assoc.qty]{Associated quantity}
\indexlibrarymemberexpos{Unit}{has-associated-quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ U>
consteval bool @\exposidnc{has-associated-quantity}@(U); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{U::\exposidnc{quantity-spec}} is a valid expression,
returns \tcode{true}.
\item
Otherwise, if \tcode{U::\exposidnc{reference-unit}} is a valid expression,
returns
\begin{codeblock}
@\exposidnc{has-associated-quantity}@(U::@\exposidnc{reference-unit}@)
\end{codeblock}
\item
Otherwise, if
\tcode{\exposidnc{is-derived-from-specialization-of}<U, \exposidnc{expr-fractions}>()}
is \tcode{true},
let \tcode{Nums} and \tcode{Dens}
be packs denoting the template arguments of
\tcode{U::\exposidnc{nums}} and \tcode{U::\exposidnc{dens}}, respectively.
Returns
\begin{codeblock}
(... && @\exposidnc{has-associated-quantity}@(@\exposidnc{expr-type}@<Nums>{})) &&
(... && @\exposidnc{has-associated-quantity}@(@\exposidnc{expr-type}@<Dens>{}))
\end{codeblock}
\item
Otherwise, returns \tcode{false}.
\end{itemize}
\end{itemdescr}
\indexlibrarymemberexpos{AssociatedUnit}{get-associated-quantity}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U>
consteval auto @\exposidnc{get-associated-quantity}@(U u); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{itemize}
\item
If \tcode{U} is of the form \tcode{common_unit<Us...>},
returns
\begin{codeblock}
get_common_quantity_spec(@\exposidnc{get-associated-quantity}@(Us{})...)
\end{codeblock}
\item
Otherwise, if \tcode{U::\exposidnc{quantity-spec}} is a valid expression,
returns
\begin{codeblock}
@\exposidnc{remove-kind}@(U::@\exposidnc{quantity-spec}@)
\end{codeblock}
\item
Otherwise, if \tcode{U::\exposidnc{reference-unit}} is a valid expression,
returns
\begin{codeblock}
@\exposidnc{get-associated-quantity}@(U::@\exposidnc{reference-unit}@)
\end{codeblock}
\item
Otherwise, if
\tcode{\exposidnc{is-derived-from-specialization-of}<U, \exposidnc{expr-fractions}>()}
is \tcode{true},
returns
\begin{codeblock}
@\exposidnc{expr-map}@<@\exposidnc{to-quantity-spec}@, derived_quantity_spec, struct dimensionless>(u)
\end{codeblock}
where \exposid{to-quantity-spec} is defined as follows:
\begin{codeblock}
template<@\libconcept{AssociatedUnit}@ U>
using @\exposidnc{to-quantity-spec}@ = decltype(@\exposidnc{get-associated-quantity}@(U{})); // \expos
\end{codeblock}
\end{itemize}
\end{itemdescr}
\rSec3[qty.unit.sym.fmt]{Symbol formatting}
\indexlibrarymember{unit_symbol_to}{Unit}
\begin{itemdecl}
template<typename CharT = char, std::@\stdconcept{output_iterator}@<CharT> Out, @\libconcept{Unit}@ U>
constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {});
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
TBD.
\pnum
\returns
TBD.
\end{itemdescr}
\indexlibrarymember{unit_symbol}{Unit}
\begin{itemdecl}
template<unit_symbol_formatting fmt = {}, typename CharT = char, @\libconcept{Unit}@ U>
consteval std::string_view unit_symbol(U);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
TBD.
\end{codeblock}
\end{itemdescr}
\rSec2[qty.ref.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Reference}@ = @\libconcept{AssociatedUnit}@<T> || (@\exposidnc{is-specialization-of}@<T, reference>());
\end{itemdecl}
A type \tcode{T} that satisfies \tcode{Reference}
represents the reference of a quantity\irefiev{112-01-01}.
\begin{itemdecl}
template<typename T, auto QS>
concept @\deflibconcept{ReferenceOf}@ = @\libconcept{Reference}@<T> && @\libconcept{QuantitySpecOf}@<decltype(get_quantity_spec(T{})), QS>;
\end{itemdecl}
\rSec2[qty.ref.syn]{Class template \tcode{reference}}
\indexlibrarymember{operator*}{reference}
\indexlibrarymember{operator*}{AssociatedUnit}
\indexlibrarymember{operator/}{reference}
\indexlibrarymember{operator/}{AssociatedUnit}
\indexlibrarymember{inverse}{reference}
\indexlibrarymember{pow}{reference}
\indexlibrarymember{sqrt}{reference}
\indexlibrarymember{cbrt}{reference}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{QuantitySpec}@ auto Q, @\libconcept{Unit}@ auto U>
using @\exposidnc{reference-t}@ = reference<decltype(Q), decltype(U)>; // \expos
template<@\libconcept{QuantitySpec}@ Q, @\libconcept{Unit}@ U>
struct @\libglobal{reference}@ {
// \ref{qty.ref.ops}, operations
template<typename Q2, typename U2>
friend consteval auto operator*(reference, reference<Q2, U2>)
-> @\exposidnc{reference-t}@<Q{} * Q2{}, U{} * U2{}>;
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval auto operator*(reference, U2)
-> @\exposidnc{reference-t}@<Q{} * get_quantity_spec(U2{}), U{} * U2{}>;
template<@\libconcept{AssociatedUnit}@ U1>
friend consteval auto operator*(U1, reference)
-> @\exposidnc{reference-t}@<get_quantity_spec(U1{}) * Q{}, U1{} * U{}>;
template<typename Q2, typename U2>
friend consteval auto operator/(reference, reference<Q2, U2>)
-> @\exposidnc{reference-t}@<Q{} / Q2{}, U{} / U2{}>;
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval auto operator/(reference, U2)
-> @\exposidnc{reference-t}@<Q{} / get_quantity_spec(U2{}), U{} / U2{}>;
template<@\libconcept{AssociatedUnit}@ U1>
friend consteval auto operator/(U1, reference)
-> @\exposidnc{reference-t}@<get_quantity_spec(U1{}) / Q{}, U1{} / U{}>;
friend consteval auto inverse(reference) -> @\exposidnc{reference-t}@<inverse(Q{}), inverse(U{})>;
template<std::intmax_t Num, std::intmax_t Den = 1>
requires(Den != 0)
friend consteval auto pow(reference) -> @\exposidnc{reference-t}@<pow<Num, Den>(Q{}), pow<Num, Den>(U{})>;
friend consteval auto sqrt(reference) -> @\exposidnc{reference-t}@<sqrt(Q{}), sqrt(U{})>;
friend consteval auto cbrt(reference) -> @\exposidnc{reference-t}@<cbrt(Q{}), cbrt(U{})>;
// \ref{qty.ref.cmp}, comparison
template<typename Q2, typename U2>
friend consteval bool operator==(reference, reference<Q2, U2>);
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval bool operator==(reference, U2 u2);
template<typename Q2, typename U2>
friend consteval bool convertible(reference, reference<Q2, U2>);
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval bool convertible(reference, U2 u2);
template<@\libconcept{AssociatedUnit}@ U1>
friend consteval bool convertible(U1 u1, reference);
};
}
\end{codeblock}
\pnum
\tcode{reference<Q, U>} represents the reference of a quantity\irefiev{112-01-01}.
The unit of measurement \tcode{U}\irefiev{112-01-14}
is used to measure a value of the quantity \tcode{Q}\irefiev{112-01-28}.
\begin{note}
\tcode{reference} is typically implicitly instantiated
when specifying that a unit measures a more specific quantity.
\begin{example}
\begin{codeblock}
using namespace si::unit_symbols;
auto x = 1 * m; // measures a length
auto y = 1 * isq::width[m]; // measures a width
auto z = 1 * isq::diameter[m]; // measures a diameter
\end{codeblock}
\end{example}
\end{note}
\rSec2[qty.ref.ops]{Operations}
\pnum
Each member function with a \fakegrammarterm{trailing-return-type}
of \tcode{-> \exposidnc{reference-t}<T...>}
returns \tcode{\{\}}.
\indexlibrarymember{operator*}{Representation}
\indexlibrarymember{operator*}{Reference}
\begin{itemdecl}
template<typename FwdRep, @\libconcept{Reference}@ R,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr quantity<R{}, Rep> operator*(FwdRep&& lhs, R r);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity\{std::forward<FwdRep>(lhs), r\};}
\end{itemdescr}
\indexlibrarymember{operator*}{Representation}
\indexlibrarymember{operator*}{Reference}
\begin{itemdecl}
template<typename FwdRep, @\libconcept{Reference}@ R,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
requires(!@\exposconceptnc{OffsetUnit}@<decltype(get_unit(R{}))>)
constexpr @\libconcept{Quantity}@ auto operator/(FwdRep&& lhs, R);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity\{std::forward<FwdRep>(lhs), inverse(R\{\})\};}
\end{itemdescr}
\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator*}{Reference}
\indexlibrarymember{operator/}{quantity}
\indexlibrarymember{operator/}{Reference}
\begin{itemdecl}
template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator*(FwdQ&& q, R);
template<typename FwdQ, @\libconcept{Reference}@ R, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
constexpr @\libconcept{Quantity}@ auto operator/(FwdQ&& q, R);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity{std::forward<FwdQ>(q).@\exposidnc{numerical-value}@, Q::reference @\atsign@ R{}};
\end{codeblock}
\end{itemdescr}
\begin{itemdecl}
template<@\libconcept{Reference}@ R, typename Rep>
requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator*(R, Rep&&) = delete;
template<@\libconcept{Reference}@ R, typename Rep>
requires @\libconcept{RepresentationOf}@<std::remove_cvref_t<Rep>, get_quantity_spec(R{})>
constexpr auto operator/(R, Rep&&) = delete;
template<@\libconcept{Reference}@ R, typename Q>
requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator*(R, Q&&) = delete;
template<@\libconcept{Reference}@ R, typename Q>
requires @\libconcept{Quantity}@<std::remove_cvref_t<Q>>
constexpr auto operator/(R, Q&&) = delete;
\end{itemdecl}
\begin{itemdescr}
\pnum
\recommended
Suggest swapping the operands.
\end{itemdescr}
\rSec2[qty.ref.cmp]{Comparison}
\indexlibrarymember{operator==}{reference}
\begin{itemdecl}
template<typename Q2, typename U2>
friend consteval bool operator==(reference, reference<Q2, U2>);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{Q\{\} == Q2\{\} \&\& U\{\} == U2\{\}}.
\end{itemdescr}
\indexlibrarymember{operator==}{reference}
\indexlibrarymember{operator==}{AssociatedUnit}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval bool operator==(reference, U2 u2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{Q\{\} == get_quantity_spec(u2) \&\& U\{\} == u2}.
\end{itemdescr}
\indexlibrarymember{convertible}{reference}
\begin{itemdecl}
template<typename Q2, typename U2>
friend consteval bool convertible(reference, reference<Q2, U2>);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(Q\{\}, Q2\{\}) \&\& convertible(U\{\}, U2\{\})}.
\end{itemdescr}
\indexlibrarymember{convertible}{reference}
\indexlibrarymember{convertible}{AssociatedUnit}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U2>
friend consteval bool convertible(reference, U2 u2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(Q\{\}, get_quantity_spec(u2)) \&\& convertible(U\{\}, u2)}.
\end{itemdescr}
\indexlibrarymember{convertible}{reference}
\indexlibrarymember{convertible}{AssociatedUnit}
\begin{itemdecl}
template<@\libconcept{AssociatedUnit}@ U1>
friend consteval bool convertible(U1 u1, reference);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{implicitly_convertible(get_quantity_spec(u1), Q\{\}) \&\& convertible(u1, U\{\})}.
\end{itemdescr}
\rSec2[qty.ref.obs]{Observers}
\indexlibrarymember{get_quantity_spec}{reference}
\begin{itemdecl}
template<typename Q, typename U>
consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(reference<Q, U>);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{Q\{\}}.
\end{itemdescr}
\indexlibrarymember{get_unit}{reference}
\begin{itemdecl}
template<typename Q, typename U>
consteval @\libconcept{Unit}@ auto get_unit(reference<Q, U>);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{U\{\}}.
\end{itemdescr}
\indexlibrarymember{get_common_reference}{AssociatedUnit}
\begin{itemdecl}
consteval @\libconcept{AssociatedUnit}@ auto @\libglobal{get_common_reference}@(@\libconcept{AssociatedUnit}@ auto u1,
@\libconcept{AssociatedUnit}@ auto u2,
@\libconcept{AssociatedUnit}@ auto... rest)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{get_common_unit(u1, u2, rest...)}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
get_common_quantity_spec(get_quantity_spec(u1), get_quantity_spec(u2),
get_quantity_spec(rest)...);
{ get_common_unit(u1, u2, rest...) } -> AssociatedUnit;
}
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{get_common_reference}{reference}
\begin{itemdecl}
template<@\libconcept{Reference}@ R1, @\libconcept{Reference}@ R2, @\libconcept{Reference}@... Rest>
consteval @\libconcept{Reference}@ auto @\libglobal{get_common_reference}@(R1 r1, R2 r2, Rest... rest)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\begin{codeblock}
@\exposidnc{reference-t}@<get_common_quantity_spec(get_quantity_spec(R1{}), get_quantity_spec(R2{}),
get_quantity_spec(rest)...),
get_common_unit(get_unit(R1{}), get_unit(R2{}), get_unit(rest)...)>{};
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
get_common_quantity_spec(get_quantity_spec(r1), get_quantity_spec(r2),
get_quantity_spec(rest)...);
get_common_unit(get_unit(r1), get_unit(r2), get_unit(rest)...);
}
\end{codeblock}
\end{itemdescr}
\rSec1[qty.rep]{Representation}
\rSec2[qty.rep.general]{General}
\pnum
Subclause \ref{qty.rep} specifies the components
used to constrain the numerical value of a quantity\irefiev{112-01-29}.
\rSec2[qty.rep.traits]{Traits}
\rSec3[qty.fp.traits]{Floating-point}
\begin{itemdecl}
template<typename T>
struct @\exposidnc{actual-value-type}@ : @\exposidnc{cond-value-type}@<T> {}; // see \refcpp{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 @\exposidnc{actual-value-type}@<T> : std::indirectly_readable_traits<T> {};
template<typename T>
using @\exposidnc{actual-value-type-t}@ = @\exposidnc{actual-value-type}@<T>::value_type;
template<typename Rep>
constexpr bool @\libglobal{treat_as_floating_point}@ =
std::chrono::treat_as_floating_point_v<@\exposidnc{actual-value-type-t}@<Rep>>;
\end{itemdecl}
\begin{itemdescr}
\pnum
\tcode{quantity} and \tcode{quantity_point} use \tcode{treat_as_floating_point}
to help determine whether implicit conversions are allowed among them.
\pnum
\remarks
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
users may specialize \tcode{treat_as_floating_point}
for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions\irefcpp{expr.const}
and have type \tcode{const bool}.
\end{itemdescr}
\rSec3[qty.char.traits]{Quantity character}
\indexlibraryglobal{disable_scalar}
\indexlibraryglobal{disable_complex}
\indexlibraryglobal{disable_vector}
\begin{itemdecl}
template<typename T>
constexpr bool disable_scalar = false;
template<typename T>
constexpr bool disable_complex = false;
template<typename T>
constexpr bool disable_vector = false;
\end{itemdecl}
\begin{itemdescr}
\pnum
Some quantities are defined as having a numerical value\irefiev{112-01-29} of a specific set\irefiev{102-01-02}.
The representation concepts use these traits
to help determine the sets \tcode{T} represents.
\pnum
\remarks
Pursuant to \refcpp{namespace.std}\iref{spec.ext},
users may specialize these templates
for cv-unqualified program-defined types.
Such specializations shall be usable in constant expressions\irefcpp{expr.const}
and have type \tcode{const bool}.
\pnum
\begin{note}
These templates prevent use of representation types with the library
that satisfy but do not in fact model their corresponding concept.
\end{note}
\end{itemdescr}
\rSec3[qty.val.traits]{Values}
\pnum
\tcode{quantity} and \tcode{quantity_point} use \tcode{representation_values}
to construct special values of its representation type.
\begin{codeblock}
namespace mp_units {
template<typename Rep>
struct @\libglobal{representation_values}@ : std::chrono::duration_values<Rep> {
static constexpr Rep one() noexcept;
};
}
\end{codeblock}
\pnum
The requirements on \tcode{std::chrono::duration_values<Rep>}\irefcpp{time.traits.duration.values}
also apply to \tcode{representation_values<Rep>}.
\begin{itemdecl}
static constexpr Rep one() noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\tcode{Rep(1)}.
\pnum
\remarks
The value returned shall be the neutral element for multiplication\irefiev{102-01-19}.
\end{itemdescr}
\rSec2[qty.rep.cpos]{Customization point objects}
\rSec3[qty.rep.cpos.general]{General}
\pnum
Within subclause \ref{qty.rep.cpos},
\term{reified object} is as defined in \refcpp{range.access.general}.
\rSec3[qty.real.cpo]{\tcode{mp_units::real}}
\pnum
The name \tcode{mp_units::real} denotes a customization point object\irefcpp{customization.point.object}.
\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::real(E)} is ill-formed.
\item
If \tcode{auto(t.real())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::real(E)} is expression-equivalent to \tcode{auto(t.real())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(real(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{real} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::real(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::real(E)} is ill-formed.
\end{itemize}
\rSec3[qty.imag.cpo]{\tcode{mp_units::imag}}
\pnum
The name \tcode{mp_units::imag} denotes a customization point object\irefcpp{customization.point.object}.
\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::imag(E)} is ill-formed.
\item
If \tcode{auto(t.imag())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::imag(E)} is expression-equivalent to \tcode{auto(t.imag())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(imag(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{imag} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::imag(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::imag(E)} is ill-formed.
\end{itemize}
\rSec3[qty.modulus.cpo]{\tcode{mp_units::modulus}}
\pnum
The name \tcode{mp_units::modulus} denotes a customization point object\irefcpp{customization.point.object}.
\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::modulus(E)} is ill-formed.
\item
If \tcode{auto(t.modulus())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::modulus(E)} is expression-equivalent to \tcode{auto(t.modulus())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(modulus(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{modulus} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::modulus(E)} is expression-equivalent to that expression.
\item
If \tcode{auto(t.abs())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::modulus(E)} is expres\-sion-equivalent to \tcode{auto(t.abs())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(abs(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{abs} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::modulus(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::modulus(E)} is ill-formed.
\end{itemize}
\rSec3[qty.mag.cpo]{\tcode{mp_units::magnitude}}
\pnum
The name \tcode{mp_units::magnitude} denotes a customization point object\irefcpp{customization.point.object}.
\pnum
Given a subexpression \tcode{E} with type \tcode{T},
let \tcode{t} be an lvalue that denotes the reified object for \tcode{E}.
Then:
\begin{itemize}
\item
If \tcode{T} does not model \exposconcept{WeaklyRegular},
\tcode{mp_units::magnitude(E)} is ill-formed.
\item
If \tcode{auto(t.magnitude())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::magnitude(E)} is expression-equivalent to \tcode{auto(t.magnitude())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(magnitude(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{magnitude} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::magnitude(E)} is expression-equivalent to that expression.
\item
Otherwise, if \tcode{auto(t.abs())} is a valid expression whose type models \exposconcept{Scalar},
\tcode{mp_units::magnitude(\brk{}E)} is expression-equivalent to \tcode{auto(t.abs())}.
\item
Otherwise, if \tcode{T} is a class or enumeration type and
\tcode{auto(abs(t))} is a valid expression whose type models \exposconcept{Scalar}
where the meaning of \tcode{magnitude} is established as-if by performing argument-dependent lookup only\irefcpp{basic.lookup.argdep},
then \tcode{mp_units::magnitude(E)} is expression-equivalent to that expression.
\item
Otherwise, \tcode{mp_units::magnitude(E)} is ill-formed.
\end{itemize}
\rSec2[qty.rep.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{WeaklyRegular}@ = std::@\stdconcept{copyable}@<T> && std::@\stdconcept{equality_comparable}@<T>; // \expos
template<typename T>
concept @\defexposconceptnc{Scalar}@ = (!disable_scalar<T>) && @\exposconceptnc{WeaklyRegular}@<T> && requires(T a, T b) { // \expos
// 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>;
};
\end{itemdecl}
\pnum
TBD.
\begin{itemdecl}
template<typename T>
using @\exposidnc{value-type-t}@ = @\exposidnc{actual-value-type-t}@<T>; // \expos, see \ref{qty.fp.traits}
template<typename T>
concept @\defexposconceptnc{Complex}@ = // \expos
(!disable_complex<T>) && @\exposconceptnc{WeaklyRegular}@<T> && @\exposconceptnc{Scalar}@<@\exposidnc{value-type-t}@<T>> &&
std::constructible_from<T, @\exposidnc{value-type-t}@<T>, @\exposidnc{value-type-t}@<T>> &&
requires(T a, T b, @\exposidnc{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);
};
\end{itemdecl}
\pnum
TBD.
\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{Vector}@ = // \expos
(!disable_vector<T>) && @\exposconceptnc{WeaklyRegular}@<T> && @\exposconceptnc{Scalar}@<@\exposidnc{value-type-t}@<T>> &&
requires(T a, T b, @\exposidnc{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);
};
\end{itemdecl}
\pnum
TBD.
\begin{itemdecl}
template<typename T>
using @\exposidnc{scaling-factor-type-t}@ = // \expos
std::conditional_t<treat_as_floating_point<T>, long double, std::intmax_t>;
template<typename T>
concept @\defexposconceptnc{ScalarRepresentation}@ = // \expos
(!@\exposidnc{is-specialization-of}@<T, quantity>()) && @\exposconceptnc{Scalar}@<T> &&
requires(T a, T b, @\exposidnc{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>;
};
\end{itemdecl}
\pnum
TBD.
\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{ComplexRepresentation}@ = // \expos
(!@\exposidnc{is-specialization-of}@<T, quantity>()) && @\exposconceptnc{Complex}@<T> &&
requires(T a, T b, @\exposidnc{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>;
};
\end{itemdecl}
\pnum
TBD.
\begin{itemdecl}
template<typename T>
concept @\defexposconceptnc{VectorRepresentation}@ = // \expos
(!@\exposidnc{is-specialization-of}@<T, quantity>()) && @\exposconceptnc{Vector}@<T>;
\end{itemdecl}
\pnum
TBD.
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{Representation}@ = @\exposconceptnc{ScalarRepresentation}@<T> || @\exposconceptnc{ComplexRepresentation}@<T> ||
@\exposconceptnc{VectorRepresentation}@<T>;
\end{itemdecl}
\pnum
A type \tcode{T} models \libconcept{Representation} if
it represents the numerical value of a quantity\irefiev{112-01-29}.
\begin{itemdecl}
template<typename T, quantity_character Ch>
concept @\defexposconceptnc{IsOfCharacter}@ = (Ch == quantity_character::scalar && @\exposconceptnc{Scalar}@<T>) || // \expos
(Ch == quantity_character::complex && @\exposconceptnc{Complex}@<T>) ||
(Ch == quantity_character::vector && @\exposconceptnc{Vector}@<T>);
template<typename T, auto V>
concept @\deflibconcept{RepresentationOf}@ =
@\libconcept{Representation}@<T> && ((@\libconcept{QuantitySpec}@<decltype(V)> &&
(@\exposconceptnc{QuantityKindSpec}@<decltype(V)> || @\exposconceptnc{IsOfCharacter}@<T, V.character>)) ||
(std::@\stdconcept{same_as}@<quantity_character, decltype(V)> && @\exposconceptnc{IsOfCharacter}@<T, V>));
\end{itemdecl}
\pnum
A type \tcode{T} models \tcode{\libconcept{RepresentationOf}<V>} if
\tcode{T} models \libconcept{Representation} and
\begin{itemize}
\item
\tcode{V} is a kind of quantity, or
\item
if \tcode{V} is a quantity, then \tcode{T} represents a value of its character, or
\item
if \tcode{V} is a quantity character, then \tcode{T} represents a value of \tcode{V}.
\end{itemize}
\rSec1[qty]{Quantity}
\rSec2[qty.general]{General}
\pnum
Subclause \ref{qty} describes the class template \tcode{quantity}
that represents the value of a quantity\irefiev{112-01-28}
that is an element of a vector space\irefiev{102-03-01,102-03-04}.
\rSec2[qty.like]{Interoperability}
\pnum
The interfaces specified in this subclause and subclause \ref{qty.pt.like}
are used by \tcode{quantity} and \tcode{quantity_point}
to specify conversions with other types representing quantities.
\begin{note}
\ref{qty.chrono} implements them for \tcode{std::chrono::duration} and \tcode{std::chrono::time_point}.
\end{note}
\begin{itemdecl}
template<typename T, template<typename> typename Traits>
concept @\defexposconceptnc{qty-like-impl}@ = requires(const T& qty, const Traits<T>::rep& num) { // \expos
{ Traits<T>::to_numerical_value(qty) } -> std::@\stdconcept{same_as}@<typename Traits<T>::rep>;
{ Traits<T>::from_numerical_value(num) } -> std::@\stdconcept{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 @\deflibconcept{QuantityLike}@ = !@\libconcept{Quantity}@<T> && @\exposconceptnc{qty-like-impl}@<T, quantity_like_traits> && requires {
typename quantity<quantity_like_traits<T>::reference, typename quantity_like_traits<T>::rep>;
};
\end{itemdecl}
\pnum
In the following descriptions, let
\begin{itemize}
\item
\tcode{Traits} be \tcode{quantity_like_traits} or \tcode{quantity_point_like_traits},
\item
\tcode{Q} be a type for which \tcode{Traits<Q>} is specialized,
\item
\tcode{qty} be an lvalue of type \tcode{const Q}, and
\item
\tcode{num} be an lvalue of type \tcode{const Traits<Q>::rep}.
\end{itemize}
\pnum
\tcode{Q} models \tcode{\exposconceptnc{qty-like-impl}<Traits>} if and only if:
\begin{itemize}
\item
\tcode{Traits<Q>::to_numerical_value(qty)} returns the numerical value\irefiev{112-01-29} of \tcode{qty}.
\item
\tcode{Traits<Q>::from_numerical_value(num)} returns a \tcode{Q} with numerical value \tcode{num}.
\item
If \tcode{Traits} is \tcode{quantity_point_like_traits},
both numerical values are offset from \tcode{Traits<Q>::point_origin}.
\end{itemize}
\pnum
If the following expression is \tcode{true}, the specified conversion will be explicit.
\begin{itemize}
\item
\tcode{Traits<Q>::explicit_import} for the conversion from \tcode{Q} to this library's type.
\item
\tcode{Traits<Q>::explicit_export} for the conversion from this library's type to \tcode{Q}.
\end{itemize}
\rSec2[qty.syn]{Class template \tcode{quantity}}
\begin{codeblock}
namespace mp_units {
template<typename T>
concept @\deflibconcept{Quantity}@ = (@\exposidnc{is-derived-from-specialization-of}@<T, quantity>()); // \expos
template<typename Q, auto QS>
concept @\deflibconcept{QuantityOf}@ = // \expos
@\libconcept{Quantity}@<Q> && @\libconcept{QuantitySpecOf}@<decltype(auto(Q::quantity_spec)), QS>;
template<@\libconcept{Unit}@ UFrom, @\libconcept{Unit}@ UTo>
consteval bool @\exposidnc{integral-conversion-factor}@(UFrom from, UTo to) // \expos
{
return @\exposidnc{is-integral}@(@\exposidnc{get-canonical-unit}@(from).mag / @\exposidnc{get-canonical-unit}@(to).mag);
}
template<typename T>
concept @\defexposconceptnc{IsFloatingPoint}@ = treat_as_floating_point<T>; // \expos
template<typename FromRep, typename ToRep, auto FromUnit = one, auto ToUnit = one>
concept @\defexposconceptnc{ValuePreservingTo}@ = // \expos
@\libconcept{Representation}@<std::remove_cvref_t<FromRep>> && @\libconcept{Representation}@<ToRep> &&
@\libconcept{Unit}@<decltype(FromUnit)> && @\libconcept{Unit}@<decltype(ToUnit)> && std::@\stdconcept{assignable_from}@<ToRep&, FromRep> &&
(@\exposidnc{IsFloatingPoint}@<ToRep> || (!@\exposconceptnc{IsFloatingPoint}@<std::remove_cvref_t<FromRep>> &&
(@\exposidnc{integral-conversion-factor}@(FromUnit, ToUnit))));
template<typename QFrom, typename QTo>
concept @\defexposconceptnc{QuantityConvertibleTo}@ = // \expos
@\libconcept{Quantity}@<QFrom> && @\libconcept{Quantity}@<QTo> &&
@\exposconceptnc{QuantitySpecConvertibleTo}@<QFrom::quantity_spec, QTo::quantity_spec> &&
@\exposconceptnc{UnitConvertibleTo}@<QFrom::unit, QTo::unit> &&
@\exposidnc{ValuePreservingTo}@<typename QFrom::rep, typename QTo::rep, QFrom::unit, QTo::unit> &&
requires(QFrom q) { @\exposidnc{sudo-cast}@<QTo>(q); }; // see \ref{qty.non.mem.conv}
template<auto QS, typename Func, typename T, typename U>
concept @\defexposconceptnc{InvokeResultOf}@ = // \expos
@\libconcept{QuantitySpec}@<decltype(QS)> && std::@\stdconcept{regular_invocable}@<Func, T, U> &&
@\libconcept{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 @\defexposconceptnc{InvocableQuantities}@ = // \expos
@\libconcept{QuantitySpec}@<decltype(QS)> && @\libconcept{Quantity}@<Q1> && @\libconcept{Quantity}@<Q2> &&
@\exposconceptnc{InvokeResultOf}@<QS, Func, typename Q1::rep, typename Q2::rep>;
template<auto R1, auto R2>
concept @\defexposconceptnc{HaveCommonReference}@ = requires { get_common_reference(R1, R2); }; // \expos
template<typename Func, Quantity Q1, Quantity Q2>
using @\exposidnc{common-quantity-for}@ = // \expos
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 @\defexposconceptnc{CommonlyInvocableQuantities}@ = // \expos
@\libconcept{Quantity}@<Q1> && @\libconcept{Quantity}@<Q2> && @\exposconceptnc{HaveCommonReference}@<Q1::reference, Q2::reference> &&
std::@\stdconcept{convertible_to}@<Q1, @\exposidnc{common-quantity-for}@<Func, Q1, Q2>> &&
std::@\stdconcept{convertible_to}@<Q2, @\exposidnc{common-quantity-for}@<Func, Q1, Q2>> &&
@\exposconceptnc{InvocableQuantities}@<Func, Q1, Q2,
get_common_quantity_spec(Q1::quantity_spec, Q2::quantity_spec)>;
template<auto R1, auto R2, typename Rep1, typename Rep2>
concept @\defexposconceptnc{SameValueAs}@ = // \expos
(equivalent(get_unit(R1), get_unit(R2))) && std::@\stdconcept{convertible_to}@<Rep1, Rep2>;
template<typename T>
using @\exposidnc{quantity-like-type}@ = // \expos
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 @\defexposconceptnc{Mutable}@ = (!std::is_const_v<TT>) && std::@\stdconcept{derived_from}@<TT, U>; // \expos
template<@\libconcept{Reference}@ auto R, @\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
class @\libglobal{quantity}@ {
public:
Rep @\exposidnc{numerical-value}@; // \expos
// member types and values
static constexpr @\libconcept{Reference}@ auto reference = R;
static constexpr @\libconcept{QuantitySpec}@ auto quantity_spec = get_quantity_spec(reference);
static constexpr @\libconcept{Dimension}@ auto dimension = quantity_spec.dimension;
static constexpr @\libconcept{Unit}@ auto unit = get_unit(reference);
using rep = Rep;
// \ref{qty.static}, static member functions
static constexpr quantity zero() noexcept
requires @\seebelownc@;
static constexpr quantity one() noexcept
requires @\seebelownc@;
static constexpr quantity min() noexcept
requires @\seebelownc@;
static constexpr quantity max() noexcept
requires @\seebelownc@;
// \ref{qty.cons}, constructors and assignment
quantity() = default;
quantity(const quantity&) = default;
quantity(quantity&&) = default;
~quantity() = default;
template<typename FwdValue, @\libconcept{Reference}@ R2>
requires @\exposconceptnc{SameValueAs}@<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(FwdValue&& v, R2);
template<typename FwdValue, @\libconcept{Reference}@ R2, typename Value = std::remove_cvref_t<FwdValue>>
requires(!@\exposconceptnc{SameValueAs}@<R2{}, R, Value, Rep>) &&
@\exposconceptnc{QuantityConvertibleTo}@<quantity<R2{}, Value>, quantity>
constexpr quantity(FwdValue&& v, R2);
template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr quantity(FwdValue&& v);
template<@\exposconceptnc{QuantityConvertibleTo}@<quantity> Q>
constexpr explicit(@\seebelownc@) quantity(const Q& q);
template<@\libconcept{QuantityLike}@ Q>
requires @\exposconceptnc{QuantityConvertibleTo}@<@\exposidnc{quantity-like-type}@<Q>, quantity>
constexpr explicit(@\seebelownc@) quantity(const Q& q);
quantity& operator=(const quantity&) = default;
quantity& operator=(quantity&&) = default;
template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr quantity& operator=(FwdValue&& v);
// \ref{qty.conv}, conversions
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), Rep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<reference, ToRep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in() const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity,
quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), ToRep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires requires(const quantity q) { value_cast<ToU{}>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires requires(const quantity q) { value_cast<ToRep>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in() const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;
// \ref{qty.obs}, numerical value observers
template<@\libconcept{Unit}@ U>
requires(equivalent(U{}, unit))
constexpr rep& numerical_value_ref_in(U) & noexcept;
template<@\libconcept{Unit}@ U>
requires(equivalent(U{}, unit))
constexpr const rep& numerical_value_ref_in(U) const & noexcept;
template<@\libconcept{Unit}@ U>
requires(equivalent(U{}, unit))
void numerical_value_ref_in(U) const && = delete;
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, U{}), Rep>>
constexpr rep numerical_value_in(U) const noexcept;
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
requires requires(const quantity q) { value_cast<U{}>(q); }
constexpr rep force_numerical_value_in(U) const noexcept;
// \ref{qty.conv.ops}, conversion operations
template<typename V_, std::@\stdconcept{constructible_from}@<Rep> Value = std::remove_cvref_t<V_>>
requires(unit == ::mp_units::one)
explicit operator V_() const & noexcept;
template<typename Q_, @\libconcept{QuantityLike}@ Q = std::remove_cvref_t<Q_>>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, @\exposidnc{quantity-like-type}@<Q>>
constexpr explicit(@\seebelownc@) operator Q_() const noexcept(@\seebelownc@);
// \ref{qty.unary.ops}, unary operations
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator+() const
requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator-() const
requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity> Q>
friend constexpr decltype(auto) operator++(Q&& q)
requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity> Q>
friend constexpr decltype(auto) operator--(Q&& q)
requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator++(int)
requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator--(int)
requires @\seebelownc@;
// \ref{qty.assign.ops}, compound assignment operations
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
requires @\seebelownc@
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
requires @\seebelownc@
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
requires @\seebelownc@
friend constexpr decltype(auto) operator*=(Q&& lhs, const Q2& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
requires @\seebelownc@
friend constexpr decltype(auto) operator/=(Q&& lhs, const Q2& rhs);
// \ref{qty.arith.ops}, arithmetic operations
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::plus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::minus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) &&
@\exposconceptnc{CommonlyInvocableQuantities}@<std::modulus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{InvocableQuantities}@<std::multiplies<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator*(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{InvocableQuantities}@<std::divides<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator/(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, Rep, const Value&>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, Rep, const Value&>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator/(const Q& lhs, const Value& rhs);
template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, const Value&, Rep>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Value& lhs, const Q& rhs);
template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, const Value&, Rep>
friend constexpr @\libconcept{Quantity}@ auto operator/(const Value&, const Q&);
// \ref{qty.cmp}, comparison
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr bool operator==(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr auto operator<=>(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires @\seebelownc@
friend constexpr bool operator==(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires @\seebelownc@
friend constexpr auto operator<=>(const Q& lhs, const Value& rhs);
// \ref{qty.val.cmp}, value comparison
friend constexpr bool is_eq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_neq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_lt_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_gt_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_lteq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_gteq_zero(const quantity& q) requires @\seebelownc@;
};
template<@\libconcept{Representation}@ Value, @\libconcept{Reference}@ R>
quantity(Value, R) -> quantity<R{}, Value>;
template<@\libconcept{Representation}@ Value>
quantity(Value) -> quantity<one, Value>;
template<@\libconcept{QuantityLike}@ Q>
explicit(quantity_like_traits<Q>::explicit_import) quantity(Q)
-> quantity<quantity_like_traits<Q>::reference, typename quantity_like_traits<Q>::rep>;
}
\end{codeblock}
\pnum
\tcode{quantity<R, Rep>} is a structural type\irefcppx{temp.param}{term.structural.type}
if \tcode{Rep} is a structural type.
\rSec2[qty.static]{Static member functions}
\indexlibrarymember{zero}{quantity}
\indexlibrarymember{one}{quantity}
\indexlibrarymember{min}{quantity}
\indexlibrarymember{max}{quantity}
\begin{itemdecl}
static constexpr quantity zero() noexcept
requires @\seebelownc@;
static constexpr quantity one() noexcept
requires @\seebelownc@;
static constexpr quantity min() noexcept
requires @\seebelownc@;
static constexpr quantity max() noexcept
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \placeholder{F} be one of \tcode{zero}, \tcode{one}, \tcode{min}, and \tcode{max}.
\pnum
\returns
\tcode{\{representation_values<rep>::\placeholdernc{F}(), R\}}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { representation_values<rep>::@\placeholdernc{F}@(); }
\end{codeblock}
\end{itemdescr}
\rSec2[qty.cons]{Constructors and assignment}
\indexlibraryctor{quantity}
\begin{itemdecl}
template<typename FwdValue, @\libconcept{Reference}@ R2>
requires @\exposconceptnc{SameValueAs}@<R2{}, R, std::remove_cvref_t<FwdValue>, Rep>
constexpr quantity(FwdValue&& v, R2);
template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr quantity(FwdValue&& v);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Initializes \exposidnc{numerical-value} with \tcode{std::forward<FwdValue>(v)}.
\end{itemdescr}
\indexlibraryctor{quantity}
\begin{itemdecl}
template<typename FwdValue, @\libconcept{Reference}@ R2, typename Value = std::remove_cvref_t<FwdValue>>
requires(!@\exposconceptnc{SameValueAs}@<R2{}, R, Value, Rep>) &&
@\exposconceptnc{QuantityConvertibleTo}@<quantity<R2{}, Value>, quantity>
constexpr quantity(FwdValue&& v, R2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to
\tcode{quantity(quantity<R2\{\}, Value>\{std::forward<FwdValue>(v), R2\{\}\})}.
\end{itemdescr}
\indexlibraryctor{quantity}
\begin{itemdecl}
template<@\exposconceptnc{QuantityConvertibleTo}@<quantity> Q>
constexpr explicit(!std::@\stdconcept{convertible_to}@<typename Q::rep, Rep>) quantity(const Q& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposidnc{sudo-cast}<quantity>(q)}\iref{qty.non.mem.conv}.
\end{itemdescr}
\indexlibraryctor{quantity}
\begin{itemdecl}
template<@\libconcept{QuantityLike}@ Q>
requires @\exposconceptnc{QuantityConvertibleTo}@<@\exposidnc{quantity-like-type}@<Q>, quantity>
constexpr explicit(@\seebelownc@) quantity(const Q& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
quantity(::mp_units::quantity{quantity_like_traits<Q>::to_numerical_value(q),
quantity_like_traits<Q>::reference})
\end{codeblock}
\pnum
\remarks
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
quantity_like_traits<Q>::explicit_import ||
!std::@\stdconcept{convertible_to}@<typename quantity_like_traits<Q>::rep, Rep>
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{ValuePreservingTo}@<Rep> FwdValue>
requires(unit == ::mp_units::one)
constexpr quantity& operator=(FwdValue&& v);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to \tcode{\exposidnc{numerical-value} = std::forward<FwdValue>(v)}.
\pnum
\returns
\tcode{*this}.
\end{itemdescr}
\rSec2[qty.conv]{Conversions}
\indexlibrarymember{in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), Rep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity<\exposidnc{make-reference}(quantity_spec, ToU\{\}), Rep>\{*this\};}
\end{itemdescr}
\indexlibrarymember{in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<reference, ToRep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in() const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity<reference, ToRep>\{*this\};}
\end{itemdescr}
\indexlibrarymember{in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity,
quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), ToRep>>
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto in(ToU) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity<@\exposidnc{make-reference}@(quantity_spec, ToU{}), ToRep>{*this};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{force_in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires requires(const quantity q) { value_cast<ToU{}>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return value_cast<ToU\{\}>(*this);}
\end{itemdescr}
\indexlibrarymember{force_in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires requires(const quantity q) { value_cast<ToRep>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in() const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return value_cast<ToRep>(*this);}
\end{itemdescr}
\indexlibrarymember{force_in}{quantity}
\begin{itemdecl}
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires requires(const quantity q) { value_cast<ToU{}, ToRep>(q); }
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto force_in(ToU) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return value_cast<ToU\{\}, ToRep>(*this);}
\end{itemdescr}
\rSec2[qty.obs]{Numerical value observers}
\indexlibrarymember{numerical_value_ref_in}{quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ U>
requires(equivalent(U{}, unit))
constexpr rep& numerical_value_ref_in(U) & noexcept;
template<@\libconcept{Unit}@ U>
requires(equivalent(U{}, unit))
constexpr const rep& numerical_value_ref_in(U) const & noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\exposidnc{numerical-value}.
\end{itemdescr}
\indexlibrarymember{numerical_value_in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, quantity<@\exposidnc{make-reference}@(quantity_spec, U{}), Rep>>
constexpr rep numerical_value_in(U) const noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return (*this).in(U\{\}).\exposidnc{numerical-value};}
\end{itemdescr}
\indexlibrarymember{force_numerical_value_in}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> U>
requires requires(const quantity q) { value_cast<U{}>(q); }
constexpr rep force_numerical_value_in(U) const noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return (*this).force_in(U\{\}).\exposidnc{numerical-value};}
\end{itemdescr}
\rSec2[qty.conv.ops]{Conversion operations}
\indexlibrarymisc{\idxcode{quantity}}{\idxcode{operator constructible_from<Rep>}}
\begin{itemdecl}
template<typename V_, std::@\stdconcept{constructible_from}@<Rep> Value = std::remove_cvref_t<V_>>
requires(unit == ::mp_units::one)
explicit operator V_() const & noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\exposidnc{numerical-value}.
\end{itemdescr}
\indexlibrarymisc{\idxcode{quantity}}{\idxcode{operator QuantityLike}}
\begin{itemdecl}
template<typename Q_, @\libconcept{QuantityLike}@ Q = std::remove_cvref_t<Q_>>
requires @\exposconceptnc{QuantityConvertibleTo}@<quantity, @\exposidnc{quantity-like-type}@<Q>>
constexpr explicit(@\seebelownc@) operator Q_() const noexcept(@\seebelownc@);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_like_traits<Q>::from_numerical_value(
numerical_value_in(get_unit(quantity_like_traits<Q>::reference)));
\end{codeblock}
\pnum
\remarks
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
quantity_like_traits<Q>::explicit_export ||
!std::@\stdconcept{convertible_to}@<Rep, typename quantity_like_traits<Q>::rep>
\end{codeblock}
The exception specification is equivalent to:
\begin{codeblock}
noexcept(quantity_like_traits<Q>::from_numerical_value(@\exposidnc{numerical-value}@)) &&
std::is_nothrow_copy_constructible_v<rep>
\end{codeblock}
\end{itemdescr}
\rSec2[qty.unary.ops]{Unary operations}
\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.
\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\begin{itemdecl}
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator+() const
requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator-() const
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return ::mp_units::quantity\{@\exposidnc{numerical-value}, reference\};}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires(const rep v) {
{ @\atsign@v } -> std::@\stdconcept{common_with}@<rep>;
}
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator++}{quantity}
\indexlibrarymember{operator--}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity> Q>
friend constexpr decltype(auto) operator++(Q&& q)
requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity> Q>
friend constexpr decltype(auto) operator--(Q&& q)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to
\tcode{@q.\exposidnc{numerical-value}}.
\pnum
\returns
\tcode{std::forward<Q>(q)}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires(rep& v) {
{ @\atsign@v } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator++}{quantity}
\indexlibrarymember{operator--}{quantity}
\begin{itemdecl}
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator++(int)
requires @\seebelownc@;
constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator--(int)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return ::mp_units::quantity\{\exposid{numerical-value}@, reference\};}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires(rep& v) {
{ v@\atsign@ } -> std::@\stdconcept{common_with}@<rep>;
}
\end{codeblock}
\end{itemdescr}
\rSec2[qty.assign.ops]{Compound assignment operations}
\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.
\indexlibrarymember{operator+=}{quantity}
\indexlibrarymember{operator-=}{quantity}
\indexlibrarymember{operator\%=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator+=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator-=(Q&& lhs, const quantity<R2, Rep2>& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs);
2024-09-08 08:20:26 +02:00
\end{itemdecl}
\begin{itemdescr}
\pnum
\expects
2024-10-12 22:25:53 -04:00
If \tcode{@} is \tcode{\%=}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.
\pnum
\effects
Equivalent to
\tcode{lhs.\exposid{numerical-value} @ rhs.in(lhs.unit).\exposid{numerical-value}}.
2024-09-08 08:20:26 +02:00
\pnum
\returns
2024-10-12 22:25:53 -04:00
\tcode{std::forward<Q>(lhs)}.
\pnum
\remarks
Let \placeholder{C} be
\begin{itemize}
\item
\tcode{(!treat_as_floating_point<rep>)} if \tcode{@} is \tcode{\%=}, and
\item
\tcode{true} otherwise.
\end{itemize}
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\exposconceptnc{QuantityConvertibleTo}@<quantity<R2, Rep2>, quantity> && @\placeholder{C}@ &&
requires(rep& a, const Rep2 b) {
{ a @\atsign@ b } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
\pnum
\recommended
If \tcode{equivalent(unit, get_unit(rhs.reference))} is \tcode{true},
then the expression \tcode{rhs.in(lhs.unit)} is replaced with \tcode{rhs}.
2024-09-08 08:20:26 +02:00
\end{itemdescr}
2024-10-12 22:25:53 -04:00
\indexlibrarymember{operator*=}{quantity}
\indexlibrarymember{operator/=}{quantity}
2024-09-08 08:20:26 +02:00
\begin{itemdecl}
2024-10-12 22:25:53 -04:00
template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
requires @\seebelownc@
friend constexpr decltype(auto) operator*=(Q&& lhs, const Value& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\exposconceptnc{ValuePreservingTo}@<Rep> Value>
requires @\seebelownc@
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& rhs);
2024-09-08 08:20:26 +02:00
\end{itemdecl}
\begin{itemdescr}
2024-10-12 22:25:53 -04:00
\pnum
\expects
If \tcode{@} is \tcode{/=}, then \tcode{rhs != representation_values<Value>::zero()} is \tcode{true}.
\pnum
\effects
Equivalent to
\tcode{lhs.\exposid{numerical-value} @ rhs}.
\pnum
\returns
\tcode{std::forward<Q>(lhs)}.
2024-09-08 08:20:26 +02:00
\pnum
\remarks
2024-10-12 22:25:53 -04:00
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(!@\libconcept{Quantity}@<Value>) && requires(rep& a, const Value b) {
{ a @\atsign@ b } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
2024-09-08 08:20:26 +02:00
\end{itemdescr}
2024-10-12 22:25:53 -04:00
\indexlibrarymember{operator*=}{quantity}
\indexlibrarymember{operator/=}{quantity}
2024-09-08 08:20:26 +02:00
\begin{itemdecl}
2024-10-12 22:25:53 -04:00
template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
requires @\seebelownc@
friend constexpr decltype(auto) operator*=(Q&& lhs, const Q2& rhs);
template<@\exposconceptnc{Mutable}@<quantity> Q, @\libconcept{QuantityOf}@<dimensionless> Q2>
requires @\seebelownc@
friend constexpr decltype(auto) operator/=(Q&& lhs, const Q2& rhs);
2024-09-08 08:20:26 +02:00
\end{itemdecl}
2024-10-12 22:25:53 -04:00
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return std::forward<Q>(lhs) @ rhs.\exposid{numerical-value};}
2024-09-08 08:20:26 +02:00
\pnum
2024-10-12 22:25:53 -04:00
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(Q2::unit == ::mp_units::one) && @\exposconceptnc{ValuePreservingTo}@<typename Q2::rep, Rep> &&
requires(rep& a, const Q2::rep b) {
{ a @\atsign@ b } -> std::@\stdconcept{same_as}@<rep&>;
}
\end{codeblock}
\end{itemdescr}
\rSec2[qty.arith.ops]{Arithmetic operations}
2024-09-08 08:20:26 +02:00
\pnum
2024-10-12 22:25:53 -04:00
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\indexlibrarymember{operator\%}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::plus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{CommonlyInvocableQuantities}@<std::minus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires(!treat_as_floating_point<Rep>) && (!treat_as_floating_point<Rep2>) &&
@\exposconceptnc{CommonlyInvocableQuantities}@<std::modulus<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\begin{itemdescr}
\pnum
Let \placeholder{F} be the first argument to \exposconceptnc{CommonlyInvocableQuantities}.
\pnum
\expects
If \tcode{@} is \tcode{\%}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
using ret = @\exposidnc{common-quantity-for}@<@\placeholdernc{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) @\atsign@ ret_rhs.numerical_value_ref_in(ret::unit),
ret::reference};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\indexlibrarymember{operator\%}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Q& lhs, const Value& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return lhs @ ::mp_units::quantity\{rhs\};}
\end{itemdescr}
\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity}
\indexlibrarymember{operator\%}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::plus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator+(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::minus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator-(const Value& lhs, const Q& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires(Q::unit == ::mp_units::one) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::modulus<>, Rep, const Value&>
friend constexpr @\libconcept{Quantity}@ auto operator%(const Value& lhs, const Q& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return ::mp_units::quantity\{lhs\} @ rhs;}
\end{itemdescr}
\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator/}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{InvocableQuantities}@<std::multiplies<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator*(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\exposconceptnc{InvocableQuantities}@<std::divides<>, quantity, quantity<R2, Rep2>>
friend constexpr @\libconcept{Quantity}@ auto operator/(const Q& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity{
lhs.numerical_value_ref_in(unit) @\atsign@ rhs.numerical_value_ref_in(rhs.unit), R @\atsign@ R2};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator/}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, Rep, const Value&>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, typename Value>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, Rep, const Value&>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator/(const Q& lhs, const Value& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/}, then \tcode{rhs != representation_values<Value>::zero()} is \tcode{true}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity{lhs.numerical_value_ref_in(unit) @\atsign@ rhs, R};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator*}{quantity}
\indexlibrarymember{operator/}{quantity}
\begin{itemdecl}
template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::multiplies<>, const Value&, Rep>
friend constexpr @\libconcept{QuantityOf}@<quantity_spec> auto operator*(const Value& lhs, const Q& rhs);
template<typename Value, std::@\stdconcept{derived_from}@<quantity> Q>
requires(!@\libconcept{Quantity}@<Value>) && (!@\libconcept{Reference}@<Value>) &&
@\exposconceptnc{InvokeResultOf}@<quantity_spec, std::divides<>, const Value&, Rep>
friend constexpr @\libconcept{Quantity}@ auto operator/(const Value& lhs, const Q& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
\expects
If \tcode{@} is \tcode{/}, then \tcode{is_neq_zero(rhs)} is \tcode{true}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity{lhs @\atsign@ rhs.numerical_value_ref_in(unit), ::mp_units::one @\atsign@ R};
\end{codeblock}
\end{itemdescr}
\rSec2[qty.cmp]{Comparison}
\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.
\indexlibrarymember{operator==}{quantity}
\indexlibrarymember{operator<=>}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr bool operator==(const Q& lhs, const quantity<R2, Rep2>& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr auto operator<=>(const Q& lhs, const quantity<R2, Rep2>& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable}} if \tcode{@} is \tcode{==}, and
\tcode{std::\stdconcept{three_way_comparable}} if \tcode{@} is \tcode{<=>}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
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) @\atsign@ ct_rhs.numerical_value_ref_in(ct::unit);
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
typename std::common_type_t<quantity, quantity<R2, Rep2>>;
} && @\placeholder{C}@<typename std::common_type_t<quantity, quantity<R2, Rep2>>::rep>
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator==}{quantity}
\indexlibrarymember{operator<=>}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires @\seebelownc@
friend constexpr bool operator==(const Q& lhs, const Value& rhs);
template<std::@\stdconcept{derived_from}@<quantity> Q, @\libconcept{Representation}@ Value>
requires @\seebelownc@
friend constexpr auto operator<=>(const Q& lhs, const Value& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable_with}} if \tcode{@} is \tcode{==}, and
\tcode{std::\stdconcept{three_way_comparable_with}} if \tcode{@} is \tcode{<=>}.
\pnum
\returns
\tcode{lhs.numerical_value_ref_in(unit) @ rhs}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(Q::unit == ::mp_units::one) && @\placeholder{C}@<Rep, Value>
\end{codeblock}
\end{itemdescr}
\rSec2[qty.val.cmp]{Value comparison}
\indexlibrarymember{is_eq_zero}{quantity}
\indexlibrarymember{is_neq_zero}{quantity}
\indexlibrarymember{is_lt_zero}{quantity}
\indexlibrarymember{is_gt_zero}{quantity}
\indexlibrarymember{is_lteq_zero}{quantity}
\indexlibrarymember{is_gteq_zero}{quantity}
\begin{itemdecl}
friend constexpr bool is_eq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_neq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_lt_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_gt_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_lteq_zero(const quantity& q) requires @\seebelownc@;
friend constexpr bool is_gteq_zero(const quantity& q) requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{is_\placeholdernc{F}_zero} be the function name.
\pnum
\returns
\begin{itemize}
\item
If \tcode{\placeholdernc{F}} is \tcode{eq}, returns \tcode{q == zero()}.
\item
Otherwise, if \tcode{\placeholdernc{F}} is \tcode{neq}, returns \tcode{q != zero()}.
\item
Otherwise, returns \tcode{is_\placeholdernc{F}(q <=> zero())}\irefcpp{compare.syn}.
\end{itemize}
\pnum
\remarks
Let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable_with}} if \placeholder{F} is \tcode{eq} or \tcode{neq}, and
\tcode{std::\stdconcept{three_way_comparable_with}} otherwise.
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires {
{ T::zero() } -> @\placeholder{C}@<quantity>;
}
\end{codeblock}
\end{itemdescr}
\rSec2[qty.delta]{Construction helper \tcode{delta}}
\indexlibraryglobal{delta_}
2024-09-08 08:20:26 +02:00
\begin{codeblock}
namespace mp_units {
2024-10-12 22:25:53 -04:00
template<@\libconcept{Reference}@ R>
struct delta_ {
template<typename FwdRep,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const;
};
2024-09-08 08:20:26 +02:00
}
\end{codeblock}
2024-10-12 22:25:53 -04:00
\indexlibrarymember{operator()}{delta_}
\begin{itemdecl}
template<typename FwdRep,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
constexpr quantity<R{}, Rep> operator()(FwdRep&& lhs) const;
\end{itemdecl}
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity\{std::forward<FwdRep>(lhs), R\{\}\};}
\end{itemdescr}
\rSec2[qty.non.mem.conv]{Non-member conversions}
\indexlibrarymemberexpos{quantity}{sudo-cast}
\begin{itemdecl}
template<@\libconcept{Quantity}@ To, typename FwdFrom, @\libconcept{Quantity}@ From = std::remove_cvref_t<FwdFrom>>
requires @\seebelownc@
constexpr To @\exposidnc{sudo-cast}@(FwdFrom&& q); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}
\pnum
\tcode{value_cast} is an explicit cast that allows truncation.
\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires(convertible(Q::reference, ToU))
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposidnc{sudo-cast}@<quantity<@\exposidnc{make-reference}@(Q::quantity_spec, ToU), typename Q::rep>>(
std::forward<FwdQ>(q));
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Representation}@ ToRep, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires @\libconcept{RepresentationOf}@<ToRep, Q::quantity_spec> &&
std::@\stdconcept{constructible_from}@<ToRep, typename Q::rep>
constexpr quantity<Q::reference, ToRep> value_cast(FwdQ&& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposidnc{sudo-cast}@<quantity<Q::reference, ToRep>>(std::forward<FwdQ>(q));
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, typename FwdQ,
@\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, typename FwdQ,
@\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires @\seebelownc@
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return @\exposidnc{sudo-cast}@<quantity<@\exposidnc{make-reference}@(Q::quantity_spec, ToU), ToRep>>(
std::forward<FwdQ>(q));
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(convertible(Q::reference, ToU)) && @\libconcept{RepresentationOf}@<ToRep, Q::quantity_spec> &&
std::@\stdconcept{constructible_from}@<ToRep, typename Q::rep>
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{Quantity}@ ToQ, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires(convertible(Q::reference, ToQ::unit)) && (ToQ::quantity_spec == Q::quantity_spec) &&
std::@\stdconcept{constructible_from}@<typename ToQ::rep, typename Q::rep>
constexpr @\libconcept{Quantity}@ auto value_cast(FwdQ&& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to: \tcode{return \exposidnc{sudo-cast}<ToQ>(std::forward<FwdQ>(q));}
\end{itemdescr}
\pnum
\tcode{quantity_cast} is an explicit cast that allows converting to more specific quantities.
\begin{example}
\begin{codeblock}
auto length = isq::length(42 * m);
auto distance = quantity_cast<isq::distance>(length);
\end{codeblock}
\end{example}
\indexlibrarymember{quantity_cast}{quantity}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto ToQS, typename FwdQ, @\libconcept{Quantity}@ Q = std::remove_cvref_t<FwdQ>>
requires @\exposconceptnc{QuantitySpecCastableTo}@<Q::quantity_spec, ToQS>
constexpr @\libconcept{Quantity}@ auto quantity_cast(FwdQ&& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity{std::forward<FwdQ>(q).@\exposidnc{numerical-value}@, @\exposidnc{make-reference}@(ToQS, Q::unit)};
\end{codeblock}
\end{itemdescr}
\rSec2[qty.common.type]{\tcode{std::common_type} specializations}
\begin{codeblock}
template<mp_units::@\libconcept{Quantity}@ Q1, mp_units::@\libconcept{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::@\libconcept{RepresentationOf}@<std::common_type_t<typename Q1::rep, typename Q2::rep>,
mp_units::get_common_quantity_spec(Q1::quantity_spec,
Q2::quantity_spec)>;
}
struct @\libspec{std::common_type}{quantity}@<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::@\libconcept{Quantity}@ Q, mp_units::@\libconcept{Representation}@ Value>
requires(Q::unit == mp_units::one) && requires {
typename mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>;
}
struct @\libspec{std::common_type}{quantity}@<Q, Value> {
using type = mp_units::quantity<Q::reference, std::common_type_t<typename Q::rep, Value>>;
};
\end{codeblock}
\rSec1[qty.pt]{Quantity point}
\rSec2[qty.pt.general]{General}
\pnum
Subclause \ref{qty.pt} describes the class template \tcode{quantity_point}
that represents the value of a quantity\irefiev{112-01-28}
that is an element of an affine space\irefiev{102-03-02,102-04-01}.
\rSec2[qty.pt.orig]{Point origin}
\rSec3[qty.pt.orig.general]{General}
\pnum
This subclause specifies the components
for defining the origin of an affine space.
An \defn{origin} is a point from which measurements\irefiev{112-04-01} take place.
\rSec3[qty.pt.orig.concepts]{Concepts}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{PointOrigin}@ = @\exposconceptnc{SymbolicConstant}@<T> && std::@\stdconcept{derived_from}@<T, @\exposidnc{point-origin-interface}@>;
template<typename T, auto QS>
concept @\deflibconcept{PointOriginFor}@ = @\libconcept{PointOrigin}@<T> && @\libconcept{QuantitySpecOf}@<decltype(QS), T::@\exposidnc{quantity-spec}@>;
template<typename T, auto V>
concept @\defexposconceptnc{SameAbsolutePointOriginAs}@ = // \expos
@\libconcept{PointOrigin}@<T> && @\libconcept{PointOrigin}@<decltype(V)> && @\exposidnc{same-absolute-point-origins}@(T{}, V);
\end{itemdecl}
\rSec3[qty.pt.orig.types]{Types}
\rSec4[qty.abs.pt.orig]{Absolute}
2024-09-08 08:20:26 +02:00
\begin{codeblock}
namespace mp_units {
2024-10-12 22:25:53 -04:00
template<@\libconcept{QuantitySpec}@ auto QS>
struct @\libglobal{absolute_point_origin}@ : @\exposidnc{point-origin-interface}@ {
static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = QS; // \expos
};
2024-09-08 08:20:26 +02:00
}
\end{codeblock}
2024-10-12 22:25:53 -04:00
\pnum
An \defnadj{absolute}{origin} is an origin
chosen by convention and not defined in terms of another origin.
A specialization of \tcode{absolute_point_origin} is used as a base type when defining an absolute origin.
\tcode{QS} is the quantity the origin represents.
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\rSec4[qty.rel.pt.orig]{Relative}
2024-09-08 08:20:26 +02:00
2024-10-12 22:25:53 -04:00
\begin{codeblock}
namespace mp_units {
template<@\libconcept{QuantityPoint}@ auto QP>
struct @\libglobal{relative_point_origin}@ : @\exposidnc{point-origin-interface}@ {
static constexpr @\libconcept{QuantityPoint}@ auto @\exposidnc{quantity-point}@ = QP; // \expos
static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = @\seebelownc@; // \expos
static constexpr @\libconcept{PointOrigin}@ auto @\exposidnc{absolute-point-origin}@ = // \expos
QP.absolute_point_origin;
};
}
\end{codeblock}
\pnum
A \defnadj{relative}{origin} is an origin
of a subspace\irefiev{102-03-03}.
A specialization of \tcode{relative_point_origin} is used as a base type when defining a relative origin \placeholder{O}.
\placeholder{O} is offset from \tcode{QP.absolute_point_origin} by \tcode{QP.quantity_from_zero()}.
\pnum
The member \exposid{quantity-spec} is equal to
\tcode{QP.point_origin.\exposidnc{quantity-spec}} if
\begin{codeblock}
@\exposconceptnc{QuantityKindSpec}@<decltype(auto(QP.@\exposidnc{quantity-spec}@))>
\end{codeblock}
is satisfied, and
to \tcode{QP.\exposidnc{quantity-spec}} otherwise.
\rSec4[qty.zeroth.pt.orig]{Zeroth}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{QuantitySpec}@ auto QS>
struct @\libglobal{zeroth_point_origin_}@ final : absolute_point_origin<QS> {};
}
\end{codeblock}
\pnum
\tcode{zeroth_point_origin_<QS>} represents an origin
chosen by convention as the value $0$ of the quantity \tcode{QS}.
\rSec3[qty.pt.orig.ops]{Operations}
\begin{codeblock}
namespace mp_units {
struct @\exposidnc{point-origin-interface}@ {
template<@\libconcept{PointOrigin}@ PO, typename FwdQ,
@\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, FwdQ&& q);
template<@\libconcept{Quantity}@ FwdQ, @\libconcept{PointOrigin}@ PO,
@\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(FwdQ&& q, PO);
template<@\libconcept{PointOrigin}@ PO, @\libconcept{Quantity}@ Q>
requires @\libconcept{ReferenceOf}@<decltype(auto(Q::reference)), PO::@\exposidnc{quantity-spec}@>
friend constexpr @\libconcept{QuantityPoint}@ auto operator-(PO po, const Q& q)
requires requires { -q; };
template<@\libconcept{PointOrigin}@ PO1, @\exposconceptnc{SameAbsolutePointOriginAs}@<PO1{}> PO2>
requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(PO1 po1, PO2 po2);
template<@\libconcept{PointOrigin}@ PO1, @\libconcept{PointOrigin}@ PO2>
friend consteval bool operator==(PO1 po1, PO2 po2);
};
}
\end{codeblock}
\indexlibrarymemberexpos{operator+}{point-origin-interface}
\indexlibrarymemberexpos{operator+}{quantity}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO, typename FwdQ,
@\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(PO, FwdQ&& q);
template<@\libconcept{Quantity}@ FwdQ, @\libconcept{PointOrigin}@ PO,
@\libconcept{QuantityOf}@<PO::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
friend constexpr quantity_point<Q::reference, PO{}, typename Q::rep> operator+(FwdQ&& q, PO);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity_point\{std::forward<FwdQ>(q), PO\{\}\};}
\end{itemdescr}
\indexlibrarymemberexpos{operator-}{point-origin-interface}
\indexlibrarymemberexpos{operator-}{quantity}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO, @\libconcept{Quantity}@ Q>
requires @\libconcept{ReferenceOf}@<decltype(auto(Q::reference)), PO::@\exposidnc{quantity-spec}@>
friend constexpr @\libconcept{QuantityPoint}@ auto operator-(PO po, const Q& q)
requires requires { -q; };
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return po + -q;}
\end{itemdescr}
\indexlibrarymemberexpos{operator-}{point-origin-interface}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO1, @\exposconceptnc{SameAbsolutePointOriginAs}@<PO1{}> PO2>
requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(PO1 po1, PO2 po2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, absolute_point_origin>()) {
return po1 - po2.@\exposidnc{quantity-point}@;
} else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2, absolute_point_origin>()) {
return po1.@\exposidnc{quantity-point}@ - po2;
} else {
return po1.@\exposidnc{quantity-point}@ - po2.@\exposidnc{quantity-point}@;
}
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\libconcept{QuantitySpecOf}@<decltype(auto(PO1::@\exposidnc{quantity-spec}@)), PO2::@\exposidnc{quantity-spec}@> &&
(@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>() ||
@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
\end{codeblock}
\end{itemdescr}
\indexlibrarymemberexpos{operator==}{point-origin-interface}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO1, @\libconcept{PointOrigin}@ PO2>
friend consteval bool operator==(PO1 po1, PO2 po2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, absolute_point_origin>() &&
@\exposidnc{is-derived-from-specialization-of}@<PO2, absolute_point_origin>())
return std::is_same_v<PO1, PO2> ||
(@\exposidnc{is-specialization-of}@<PO1, zeroth_point_origin>() &&
@\exposidnc{is-specialization-of}@<PO2, zeroth_point_origin>() &&
interconvertible(po1.@\exposidnc{quantity-spec}@, po2.@\exposidnc{quantity-spec}@));
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>() &&
@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
return PO1::@\exposidnc{quantity-point}@ == PO2::@\exposidnc{quantity-point}@;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>())
return @\exposidnc{same-absolute-point-origins}@(po1, po2) &&
is_eq_zero(PO1::@\exposidnc{quantity-point}@.quantity_from_zero());
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
return @\exposidnc{same-absolute-point-origins}@(po1, po2) &&
is_eq_zero(PO2::@\exposidnc{quantity-point}@.quantity_from_zero());
\end{codeblock}
\end{itemdescr}
\rSec3[qty.pt.orig.utils]{Utilities}
\rSec4[qty.same.abs.pt.origs]{Same absolute}
\indexlibrarymemberexpos{PointOrigin}{same-absolute-point-origins}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO1, @\libconcept{PointOrigin}@ PO2>
consteval bool @\exposidnc{same-absolute-point-origins}@(PO1 po1, PO2 po2); // \expos
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, absolute_point_origin>() &&
@\exposidnc{is-derived-from-specialization-of}@<PO2, absolute_point_origin>())
return po1 == po2;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>() &&
@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
return po1.@\exposidnc{absolute-point-origin}@ == po2.@\exposidnc{absolute-point-origin}@;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO1, relative_point_origin>())
return po1.@\exposidnc{absolute-point-origin}@ == po2;
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2, relative_point_origin>())
return po1 == po2.@\exposidnc{absolute-point-origin}@;
else
return false;
\end{codeblock}
\end{itemdescr}
\rSec4[qty.def.pt.orig]{Default}
\indexlibrarymember{Reference}{default_point_origin}
\begin{itemdecl}
template<@\libconcept{Reference}@ R>
consteval @\libconcept{PointOriginFor}@<get_quantity_spec(R{})> auto default_point_origin(R);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (requires { get_unit(R{}).@\exposidnc{point-origin}@; })
return get_unit(R{}).@\exposidnc{point-origin}@;
else
return zeroth_point_origin<get_quantity_spec(R{})>;
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.like]{Interoperability}
\begin{itemdecl}
template<typename T>
concept @\deflibconcept{QuantityPointLike}@ =
!@\libconcept{QuantityPoint}@<T> &&
@\exposconceptnc{qty-like-impl}@<T, quantity_point_like_traits> && // see \ref{qty.like}
requires {
typename quantity_point<quantity_point_like_traits<T>::reference,
quantity_point_like_traits<T>::point_origin,
typename quantity_point_like_traits<T>::rep>;
};
\end{itemdecl}
\rSec2[qty.pt.syn]{Class template \tcode{quantity_point}}
\begin{codeblock}
namespace mp_units {
template<typename T>
concept @\deflibconcept{QuantityPoint}@ = (@\exposidnc{is-derived-from-specialization-of}@<T, quantity_point>());
template<typename QP, auto V>
concept @\deflibconcept{QuantityPointOf}@ =
@\libconcept{QuantityPoint}@<QP> && (@\libconcept{QuantitySpecOf}@<decltype(auto(QP::quantity_spec)), V> ||
@\exposconceptnc{SameAbsolutePointOriginAs}@<decltype(auto(QP::absolute_point_origin)), V>);
template<@\libconcept{Reference}@ auto R,
@\libconcept{PointOriginFor}@<get_quantity_spec(R)> auto PO = default_point_origin(R),
@\libconcept{RepresentationOf}@<get_quantity_spec(R)> Rep = double>
class @\libglobal{quantity_point}@ {
public:
// member types and values
static constexpr @\libconcept{Reference}@ auto reference = R;
static constexpr @\libconcept{QuantitySpec}@ auto quantity_spec = get_quantity_spec(reference);
static constexpr @\libconcept{Dimension}@ auto dimension = quantity_spec.dimension;
static constexpr @\libconcept{Unit}@ auto unit = get_unit(reference);
static constexpr @\libconcept{PointOrigin}@ auto absolute_point_origin = @\seebelownc@;
static constexpr @\libconcept{PointOrigin}@ auto point_origin = PO;
using rep = Rep;
using quantity_type = quantity<reference, Rep>;
quantity_type @\exposidnc{quantity-from-origin}@; // \expos
// \ref{qty.pt.static}, static member functions
static constexpr quantity_point min() noexcept
requires @\seebelownc@;
static constexpr quantity_point max() noexcept
requires @\seebelownc@;
// \ref{qty.pt.cons}, constructors and assignment
quantity_point() = default;
quantity_point(const quantity_point&) = default;
quantity_point(quantity_point&&) = default;
~quantity_point() = default;
template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> &&
(point_origin == default_point_origin(R)) &&
(implicitly_convertible(Q::quantity_spec, quantity_spec))
constexpr explicit quantity_point(FwdQ&& q);
template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ>
constexpr quantity_point(FwdQ&& q, decltype(PO));
template<typename FwdQ, @\libconcept{PointOrigin}@ PO2,
@\libconcept{QuantityOf}@<PO2::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> && @\exposconceptnc{SameAbsolutePointOriginAs}@<PO2, PO>
constexpr quantity_point(FwdQ&& q, PO2);
template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
requires std::@\stdconcept{constructible_from}@<quantity_type, typename QP::quantity_type>
constexpr explicit(!std::@\stdconcept{convertible_to}@<typename QP::quantity_type, quantity_type>)
quantity_point(const QP& qp);
template<@\libconcept{QuantityPointLike}@ QP>
requires @\seebelownc@
constexpr explicit(@\seebelownc@) quantity_point(const QP& qp);
quantity_point& operator=(const quantity_point&) = default;
quantity_point& operator=(quantity_point&&) = default;
// \ref{qty.pt.conv}, conversions
template<@\exposconceptnc{SameAbsolutePointOriginAs}@<absolute_point_origin> NewPO>
constexpr @\libconcept{QuantityPointOf}@<(NewPO{})> auto point_for(NewPO new_origin) const;
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in() const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in() const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;
// \ref{qty.pt.obs}, quantity value observers
template<@\libconcept{PointOrigin}@ PO2>
requires(PO2{} == point_origin)
constexpr quantity_type& quantity_ref_from(PO2) & noexcept;
template<@\libconcept{PointOrigin}@ PO2>
requires(PO2{} == point_origin)
constexpr const quantity_type& quantity_ref_from(PO2) const & noexcept;
template<@\libconcept{PointOrigin}@ PO2>
requires(PO2{} == point_origin)
void quantity_ref_from(PO2) const && = delete;
template<@\libconcept{PointOrigin}@ PO2>
requires requires(const quantity_point qp) { qp - PO2{}; }
constexpr @\libconcept{Quantity}@ auto quantity_from(PO2) const;
template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
constexpr @\libconcept{Quantity}@ auto quantity_from(const QP&) const;
constexpr @\libconcept{Quantity}@ auto quantity_from_zero() const;
// \ref{qty.pt.conv.ops}, conversion operations
template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
requires @\seebelownc@
constexpr explicit(@\seebelownc@) operator QP_() const & noexcept(@\seebelownc@);
template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
requires @\seebelownc@
constexpr explicit(@\seebelownc@) operator QP_() && noexcept(@\seebelownc@);
// \ref{qty.pt.unary.ops}, unary operations
template<@\exposconceptnc{Mutable}@<quantity_point> QP>
friend constexpr decltype(auto) operator++(QP&& qp)
requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity_point> QP>
friend constexpr decltype(auto) operator--(QP&& qp)
requires @\seebelownc@;
constexpr quantity_point operator++(int)
requires @\seebelownc@;
constexpr quantity_point operator--(int)
requires @\seebelownc@;
// \ref{qty.pt.assign.ops}, compound assignment operations
template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q);
template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity<R2, Rep2>& q);
// \ref{qty.pt.arith.ops}, arithmetic operations
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const QP& qp, const quantity<R2, Rep2>& q)
requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const quantity<R2, Rep2>& q, const QP& qp)
requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator-(const QP& qp, const quantity<R2, Rep2>& q)
requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& lhs, const QP2& rhs)
requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& qp, PO2 po);
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(PO2 po, const QP& qp);
// \ref{qty.pt.cmp}, comparison
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
requires @\seebelownc@
friend constexpr bool operator==(const QP& lhs, const QP2& rhs);
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
requires @\seebelownc@
friend constexpr auto operator<=>(const QP& lhs, const QP2& rhs);
};
template<@\libconcept{Quantity}@ Q>
explicit quantity_point(Q q)
-> quantity_point<Q::reference, default_point_origin(Q::reference), typename Q::rep>;
template<@\libconcept{Quantity}@ Q, @\libconcept{PointOriginFor}@<Q::quantity_spec> PO>
quantity_point(Q, PO) -> quantity_point<Q::reference, PO{}, typename Q::rep>;
template<@\libconcept{QuantityPointLike}@ QP, typename Traits = quantity_point_like_traits<QP>>
explicit(quantity_point_like_traits<QP>::explicit_import) quantity_point(QP)
-> quantity_point<Traits::reference, Traits::point_origin, typename Traits::rep>;
}
\end{codeblock}
\pnum
\tcode{quantity_point<R, PO, Rep>} is a structural type\irefcppx{temp.param}{term.structural.type}
if \tcode{Rep} is a structural type.
\pnum
The member \tcode{absolute_point_origin} is equal to \tcode{PO} if
\begin{codeblock}
@\exposidnc{is-derived-from-specialization-of}@<decltype(PO), absolute_point_origin>()
\end{codeblock}
is \tcode{true}, and
to \tcode{PO.\exposidnc{quantity-point}.absolute_point_origin} otherwise.
\rSec2[qty.pt.static]{Static member functions}
\indexlibrarymember{min}{quantity_point}
\indexlibrarymember{max}{quantity_point}
\begin{itemdecl}
static constexpr quantity_point min() noexcept
requires @\seebelownc@;
static constexpr quantity_point max() noexcept
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \placeholder{F} be one of \tcode{min} and \tcode{max}.
\pnum
\returns
\tcode{\{quantity_type::\placeholdernc{F}(), PO\}}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { quantity_type::@\placeholdernc{F}@(); }
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.cons]{Constructors}
\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> &&
(point_origin == default_point_origin(R)) &&
(implicitly_convertible(Q::quantity_spec, quantity_spec))
constexpr explicit quantity_point(FwdQ&& q);
template<typename FwdQ, @\libconcept{QuantityOf}@<quantity_spec> Q = std::remove_cvref_t<FwdQ>>
requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ>
constexpr quantity_point(FwdQ&& q, decltype(PO));
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Initializes \exposidnc{quantity-from-origin} with \tcode{std::forward<FwdQ>(q)}.
\end{itemdescr}
\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<typename FwdQ, @\libconcept{PointOrigin}@ PO2,
@\libconcept{QuantityOf}@<PO2::@\exposidnc{quantity-spec}@> Q = std::remove_cvref_t<FwdQ>>
requires std::@\stdconcept{constructible_from}@<quantity_type, FwdQ> && @\exposconceptnc{SameAbsolutePointOriginAs}@<PO2, PO>
constexpr quantity_point(FwdQ&& q, PO2);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
quantity_point(quantity_point<Q::reference, PO2{}, typename Q::rep>{std::forward<FwdQ>(q),
PO2{}})
\end{codeblock}
\end{itemdescr}
\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
requires std::@\stdconcept{constructible_from}@<quantity_type, typename QP::quantity_type>
constexpr explicit(!std::@\stdconcept{convertible_to}@<typename QP::quantity_type, quantity_type>)
quantity_point(const QP& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
If \tcode{point_origin == QP::point_origin} is \tcode{true},
initializes \exposidnc{quantity-from-origin} with \tcode{qp.quantity_ref_from(point_origin)}.
Otherwise, initializes \exposidnc{quantity-from-origin} with \tcode{qp - point_origin}.
\end{itemdescr}
\indexlibraryctor{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantityPointLike}@ QP>
requires @\seebelownc@
constexpr explicit(@\seebelownc@) quantity_point(const QP& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{Traits} be \tcode{quantity_point_like_traits<QP>}.
\pnum
\effects
Initializes \exposidnc{quantity-from-origin} with
\begin{codeblock}
Traits::to_numerical_value(qp), get_unit(Traits::reference)
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(Traits::point_origin == point_origin) &&
std::@\stdconcept{convertible_to}@<quantity<Traits::reference, typename Traits::rep>, quantity_type>
\end{codeblock}
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
Traits::explicit_import ||
!std::@\stdconcept{convertible_to}@<quantity<Traits::reference, typename Traits::rep>, quantity_type>
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.conv]{Conversions}
\indexlibrarymember{point_for}{quantity_point}
\begin{itemdecl}
template<@\exposconceptnc{SameAbsolutePointOriginAs}@<absolute_point_origin> NewPO>
constexpr @\libconcept{QuantityPointOf}@<(NewPO{})> auto point_for(NewPO new_origin) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (std::is_same_v<NewPO, decltype(point_origin)>)
return *this;
else
return ::mp_units::quantity_point{*this - new_origin, new_origin};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{in}{quantity_point}
\indexlibrarymember{force_in}{quantity_point}
\begin{itemdecl}
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in() const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto in(ToU) const;
template<@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in() const;
template<@\libconcept{RepresentationOf}@<quantity_spec> ToRep,
@\exposconceptnc{UnitCompatibleWith}@<unit, quantity_spec> ToU>
requires @\seebelownc@
constexpr @\libconcept{QuantityPointOf}@<quantity_spec> auto force_in(ToU) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{\placeholder{converted-quantity-expr}} be an expression denoting
the function call to the corresponding member of \tcode{quantity_ref_from(point_origin)}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return ::mp_units::quantity_point{@\placeholdernc{converted-quantity-expr}@, point_origin};
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { @\placeholdernc{converted-quantity-expr}@; }
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.obs]{Quantity value observers}
\indexlibrarymember{quantity_ref_from}{quantity_point}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO2>
requires(PO2{} == point_origin)
constexpr quantity_type& quantity_ref_from(PO2) & noexcept;
template<@\libconcept{PointOrigin}@ PO2>
requires(PO2{} == point_origin)
constexpr const quantity_type& quantity_ref_from(PO2) const & noexcept;
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
\exposidnc{quantity-from-origin}.
\end{itemdescr}
\indexlibrarymember{quantity_from}{quantity_point}
\begin{itemdecl}
template<@\libconcept{PointOrigin}@ PO2>
requires requires(const quantity_point qp) { qp - PO2{}; }
constexpr @\libconcept{Quantity}@ auto quantity_from(PO2 rhs) const;
template<@\libconcept{QuantityPointOf}@<absolute_point_origin> QP>
constexpr @\libconcept{Quantity}@ auto quantity_from(const QP& rhs) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return *this - rhs;}
\end{itemdescr}
\indexlibrarymember{quantity_from_zero}{quantity_point}
\begin{itemdecl}
constexpr @\libconcept{Quantity}@ auto quantity_from_zero() const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (requires { unit.@\exposidnc{point-origin}@; }) {
// can lose the input unit
const auto q = quantity_from(unit.@\exposidnc{point-origin}@);
if constexpr (requires { q.in(unit); })
// restore the unit
return q.in(unit);
else
return q;
} else
return quantity_from(absolute_point_origin);
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.conv.ops]{Conversion operations}
\indexlibrarymisc{\idxcode{quantity_point}}{\idxcode{operator QuantityPointLike}}
\begin{itemdecl}
template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
requires @\seebelownc@
constexpr explicit(@\seebelownc@) operator QP_() const & noexcept(@\seebelownc@);
template<typename QP_, @\libconcept{QuantityPointLike}@ QP = std::remove_cvref_t<QP_>>
requires @\seebelownc@
constexpr explicit(@\seebelownc@) operator QP_() && noexcept(@\seebelownc@);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{Traits} be \tcode{quantity_point_like_traits<QP>}.
Let \tcode{\placeholder{result-expr}} be
\begin{codeblock}
Traits::from_numerical_value(std::move(@\exposidnc{quantity-from-origin}@).@\exposidnc{numerical-value}@)
\end{codeblock}
\pnum
\returns
\tcode{\placeholdernc{result-expr}}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(point_origin == Traits::point_origin) &&
std::@\stdconcept{convertible_to}@<quantity_type, quantity<Traits::reference, typename Traits::rep>>
\end{codeblock}
The expression inside \tcode{explicit} is equivalent to:
\begin{codeblock}
Traits::explicit_export ||
!std::@\stdconcept{convertible_to}@<quantity_type, quantity<Traits::reference, typename Traits::rep>>
\end{codeblock}
Let \placeholder{T} be
\tcode{std::is_nothrow_copy_constructible_v} for the first signature, and
\tcode{std::is_nothrow_move_constructible_v} for the second signature.
The exception specification is equivalent to:
\begin{codeblock}
noexcept(@\placeholdernc{result-expr}@) && @\placeholder{T}@<rep>
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.unary.ops]{Unary operations}
\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.
\indexlibrarymember{operator++}{quantity_point}
\indexlibrarymember{operator--}{quantity_point}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity_point> QP>
friend constexpr decltype(auto) operator++(QP&& qp)
requires @\seebelownc@;
template<@\exposconceptnc{Mutable}@<quantity_point> QP>
friend constexpr decltype(auto) operator--(QP&& qp)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to
\tcode{@qp.\exposid{quantity-from-origin}}.
\pnum
\returns
\tcode{std::forward<QP>(qp)}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { @\atsign@qp.@\exposidnc{quantity-from-origin}@; }
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator++}{quantity_point}
\indexlibrarymember{operator--}{quantity_point}
\begin{itemdecl}
constexpr quantity_point operator++(int)
requires @\seebelownc@;
constexpr quantity_point operator--(int)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return \{\exposid{quantity-from-origin}@, PO\};}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { @\exposid{quantity-from-origin}@@\atsign@; }
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.assign.ops]{Compound assignment operations}
\indexlibrarymember{operator+=}{quantity_point}
\indexlibrarymember{operator+=}{quantity}
\indexlibrarymember{operator-=}{quantity_point}
\indexlibrarymember{operator-=}{quantity}
\begin{itemdecl}
template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q);
template<@\exposconceptnc{Mutable}@<quantity_point> QP, auto R2, typename Rep2>
requires @\seebelownc@
friend constexpr decltype(auto) operator-=(QP&& qp, const quantity<R2, Rep2>& q);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}.
\pnum
\effects
Equivalent to
\tcode{qp.\exposid{quantity-from-origin} @ q}.
\pnum
\returns
\tcode{std::forward<QP>(qp)}.
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\exposconceptnc{QuantityConvertibleTo}@<quantity<R2, Rep2>, quantity_type> &&
requires { qp.@\exposid{quantity-from-origin}@ @\atsign@ q; }
\end{codeblock}
\end{itemdescr}
\rSec2[qty.pt.arith.ops]{Arithmetic operations}
\pnum
In the following descriptions,
let \tcode{@} be the \fakegrammarterm{operator}.
\indexlibrarymember{operator+}{quantity_point}
\indexlibrarymember{operator+}{quantity}
\indexlibrarymember{operator-}{quantity_point}
\indexlibrarymember{operator-}{quantity}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const QP& qp, const quantity<R2, Rep2>& q)
requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator+(const quantity<R2, Rep2>& q, const QP& qp)
requires @\seebelownc@;
template<std::@\stdconcept{derived_from}@<quantity_point> QP, auto R2, typename Rep2>
friend constexpr @\libconcept{QuantityPoint}@ auto operator-(const QP& qp, const quantity<R2, Rep2>& q)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
if constexpr (@\exposidnc{is-specialization-of}@<PO, zeroth_point_origin>())
return ::mp_units::quantity_point{qp.quantity_ref_from(PO) @\atsign@ q};
else
return ::mp_units::quantity_point{qp.quantity_ref_from(PO) @\atsign@ q, PO};
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\libconcept{ReferenceOf}@<decltype(R2), PO.@\exposidnc{quantity-spec}@> && requires {
qp.quantity_ref_from(PO) @\atsign@ q;
}
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{operator-}{quantity_point}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& lhs, const QP2& rhs)
requires @\seebelownc@;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin) +
(lhs.point_origin - rhs.point_origin);
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
requires { lhs.quantity_ref_from(point_origin) - rhs.quantity_ref_from(QP2::point_origin); }
\end{codeblock}
\pnum
\recommended
The subtraction of two equal origins is not evaluated.
\end{itemdescr}
\indexlibrarymember{operator-}{quantity_point}
\indexlibrarymember{operator-}{PointOrigin}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(const QP& qp, PO2 po);
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{PointOrigin}@ PO2>
requires @\seebelownc@
friend constexpr @\libconcept{Quantity}@ auto operator-(PO2 po, const QP& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
For the first signature,
equivalent to:
\begin{codeblock}
if constexpr (point_origin == po)
return qp.quantity_ref_from(point_origin);
else if constexpr (@\exposidnc{is-derived-from-specialization-of}@<PO2,
::mp_units::absolute_point_origin>()) {
return qp.quantity_ref_from(point_origin) + (qp.point_origin - qp.absolute_point_origin);
} else {
return qp.quantity_ref_from(point_origin) -
po.@\exposidnc{quantity-point}@.quantity_ref_from(po.@\exposidnc{quantity-point}@.point_origin) +
(qp.point_origin - po.@\exposidnc{quantity-point}@.point_origin);
}
\end{codeblock}
For the second signature,
equivalent to: \tcode{return -(qp - po);}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\libconcept{QuantityPointOf}@<quantity_point, PO2{}> &&
@\libconcept{ReferenceOf}@<decltype(auto(reference)), PO2::@\exposidnc{quantity-spec}@>
\end{codeblock}
\pnum
\recommended
The subtraction of two equal origins is not evaluated.
\end{itemdescr}
\rSec2[qty.pt.cmp]{Comparison}
\indexlibrarymember{operator==}{quantity_point}
\indexlibrarymember{operator<=>}{quantity_point}
\begin{itemdecl}
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
requires @\seebelownc@
friend constexpr bool operator==(const QP& lhs, const QP2& rhs);
template<std::@\stdconcept{derived_from}@<quantity_point> QP, @\libconcept{QuantityPointOf}@<absolute_point_origin> QP2>
requires @\seebelownc@
friend constexpr auto operator<=>(const QP& lhs, const QP2& rhs);
\end{itemdecl}
\begin{itemdescr}
\pnum
Let \tcode{@} be the \fakegrammarterm{operator}, and
let \placeholder{C} be
\tcode{std::\stdconcept{equality_comparable_with}} if \tcode{@} is \tcode{==}, and
\tcode{std::\stdconcept{three_way_comparable_with}} if \tcode{@} is \tcode{<=>}.
\pnum
\effects
Equivalent to:
\begin{codeblock}
return lhs - lhs.absolute_point_origin @\atsign@ rhs - rhs.absolute_point_origin;
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
@\placeholder{C}@<quantity_type, typename QP2::quantity_type>
\end{codeblock}
\pnum
\recommended
If the origins are equal, instead evaluate
\begin{codeblock}
lhs.quantity_ref_from(point_origin) @\atsign@ rhs.quantity_ref_from(QP2::point_origin)
\end{codeblock}
\end{itemdescr}
\rSec2[qty.point]{Construction helper \tcode{point}}
\indexlibraryglobal{point}
\begin{codeblock}
namespace mp_units {
template<@\libconcept{Reference}@ R>
struct point_ {
template<typename FwdRep,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const;
};
}
\end{codeblock}
\indexlibrarymember{operator()}{point_}
\begin{itemdecl}
template<typename FwdRep,
@\libconcept{RepresentationOf}@<get_quantity_spec(R{})> Rep = std::remove_cvref_t<FwdRep>>
constexpr quantity_point<R{}, default_point_origin(R{}), Rep> operator()(FwdRep&& lhs) const;
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return quantity_point\{quantity\{std::forward<FwdRep>(lhs), R\{\}\}\};}
\end{itemdescr}
\rSec2[qty.pt.non.mem.conv]{Non-member conversions}
\indexlibrarymemberexpos{quantity_point}{sudo-cast}
\begin{itemdecl}
template<@\libconcept{QuantityPoint}@ ToQP, typename FwdFromQP,
@\libconcept{QuantityPoint}@ FromQP = std::remove_cvref_t<FwdFromQP>>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto @\exposidnc{sudo-cast}@(FwdFromQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\returns
TBD.
\end{itemdescr}
\pnum
\tcode{value_cast} is an explicit cast that allows truncation.
\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToU))
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_point{value_cast<ToU>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@),
QP::point_origin};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Representation}@ ToRep, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires @\libconcept{RepresentationOf}@<ToRep, QP::quantity_spec> &&
std::@\stdconcept{constructible_from}@<ToRep, typename QP::rep>
constexpr quantity_point<QP::reference, QP::point_origin, ToRep> value_cast(FwdQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return {value_cast<ToRep>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@), QP::point_origin};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Unit}@ auto ToU, @\libconcept{Representation}@ ToRep, typename FwdQP,
@\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
template<@\libconcept{Representation}@ ToRep, @\libconcept{Unit}@ auto ToU, typename FwdQP,
@\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires @\seebelownc@
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_point{value_cast<ToU, ToRep>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@),
QP::point_origin};
\end{codeblock}
\pnum
\remarks
The expression in the \fakegrammarterm{requires-clause} is equivalent to:
\begin{codeblock}
(convertible(QP::reference, ToU)) && @\libconcept{RepresentationOf}@<ToRep, QP::quantity_spec> &&
std::@\stdconcept{constructible_from}@<ToRep, typename QP::rep>
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{Quantity}@ ToQ, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToQ::unit)) && (ToQ::quantity_spec == QP::quantity_spec) &&
std::@\stdconcept{constructible_from}@<typename ToQ::rep, typename QP::rep>
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return quantity_point{value_cast<ToQ>(std::forward<FwdQP>(qp).@\exposidnc{quantity-from-origin}@),
QP::point_origin};
\end{codeblock}
\end{itemdescr}
\indexlibrarymember{value_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantityPoint}@ ToQP, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires(convertible(QP::reference, ToQP::unit)) &&
(ToQP::quantity_spec == QP::quantity_spec) &&
(@\exposidnc{same-absolute-point-origins}@(ToQP::point_origin, QP::point_origin)) &&
std::@\stdconcept{constructible_from}@<typename ToQP::rep, typename QP::rep>
constexpr @\libconcept{QuantityPoint}@ auto value_cast(FwdQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\tcode{return \exposidnc{sudo-cast}<ToQP>(std::forward<FwdQP>(qp));}
\end{itemdescr}
\pnum
\tcode{quantity_cast} is an explicit cast that allows converting to more specific quantities.
\indexlibrarymember{quantity_cast}{quantity_point}
\begin{itemdecl}
template<@\libconcept{QuantitySpec}@ auto ToQS, typename FwdQP, @\libconcept{QuantityPoint}@ QP = std::remove_cvref_t<FwdQP>>
requires @\exposconceptnc{QuantitySpecCastableTo}@<QP::quantity_spec, ToQS>
constexpr @\libconcept{QuantityPoint}@ auto quantity_cast(FwdQP&& qp);
\end{itemdecl}
\begin{itemdescr}
\pnum
\effects
Equivalent to:
\begin{codeblock}
return QP{quantity_cast<ToQS>(std::forward<FwdQP>(qp).@\exposidnc{quantity_from_origin}@),
QP::point_origin};
\end{codeblock}
\end{itemdescr}
2024-09-08 08:20:26 +02:00
\rSec1[qty.systems]{Systems}
2024-10-12 22:25:53 -04:00
\rSec1[qty.chrono]{\tcode{std::chrono} interoperability}
\begin{codeblock}
namespace mp_units {
template<typename Period>
consteval auto @\exposidnc{time-unit-from-chrono-period}@()
{
using namespace si;
if constexpr (is_same_v<Period, std::chrono::nanoseconds::period>)
return nano<second>;
else if constexpr (is_same_v<Period, std::chrono::microseconds::period>)
return micro<second>;
else if constexpr (is_same_v<Period, std::chrono::milliseconds::period>)
return milli<second>;
else if constexpr (is_same_v<Period, std::chrono::seconds::period>)
return second;
else if constexpr (is_same_v<Period, std::chrono::minutes::period>)
return minute;
else if constexpr (is_same_v<Period, std::chrono::hours::period>)
return hour;
else if constexpr (is_same_v<Period, std::chrono::days::period>)
return day;
else if constexpr (is_same_v<Period, std::chrono::weeks::period>)
return mag<7> * day;
else
return mag_ratio<Period::num, Period::den> * second;
}
template<typename Rep, typename Period>
struct @\libspec{quantity_like_traits}{std::chrono::duration}@<std::chrono::duration<Rep, Period>> {
static constexpr auto reference = @\exposidnc{time-unit-from-chrono-period}@<Period>();
static constexpr bool explicit_import = false;
static constexpr bool explicit_export = false;
using rep = Rep;
using @\exposidnc{T}@ = std::chrono::duration<Rep, Period>;
static constexpr rep to_numerical_value(const @\exposid{T}@& q) noexcept(
std::is_nothrow_copy_constructible_v<rep>)
{
return q.count();
}
static constexpr @\exposidnc{T}@ from_numerical_value(const rep& v) noexcept(
std::is_nothrow_copy_constructible_v<rep>)
{
return @\exposidnc{T}@(v);
}
};
template<typename Clock>
struct @\libglobal{chrono_point_origin_}@ final : absolute_point_origin<isq::time> {
using clock = Clock;
};
template<typename Clock, typename Rep, typename Period>
struct @\libspec{quantity_point_like_traits}{std::chrono::time_point}@<
std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>> {
static constexpr auto reference = @\exposidnc{time-unit-from-chrono-period}@<Period>();
static constexpr auto point_origin = chrono_point_origin<Clock>;
static constexpr bool explicit_import = false;
static constexpr bool explicit_export = false;
using rep = Rep;
using @\exposidnc{T}@ = std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>;
static constexpr rep to_numerical_value(const @\exposid{T}@& tp) noexcept(
std::is_nothrow_copy_constructible_v<rep>)
{
return tp.time_since_epoch().count();
}
static constexpr @\exposidnc{T}@ from_numerical_value(const rep& v) noexcept(
std::is_nothrow_copy_constructible_v<rep>)
{
return @\exposidnc{T}@(std::chrono::duration<Rep, Period>(v));
}
};
}
\end{codeblock}