diff --git a/docs/api_reference/src/CMakeLists.txt b/docs/api_reference/src/CMakeLists.txt index 28e29d64e..fe271dd7b 100644 --- a/docs/api_reference/src/CMakeLists.txt +++ b/docs/api_reference/src/CMakeLists.txt @@ -5,8 +5,8 @@ include(JEGPAddStandardeseSources) set(pdf_title "mp-units Library") set(page_license "MIT License") -set(first_library_chapter "qties") -set(last_library_chapter "qties") +set(first_library_chapter "quantities") +set(last_library_chapter "quantities") set(cover_title "mp-units Library Reference Documentations") set(reply_to "\\href{${PROJECT_HOMEPAGE_URL}/discussions}{Discussions}, \\href{${PROJECT_HOMEPAGE_URL}/issues}{issues}") jegp_add_standardese_sources( @@ -21,6 +21,7 @@ jegp_add_standardese_sources( # Latex commands. [[\\href{([^}]+)}{([^}]+)};HREF(\1)(\2)]] # Macros extensions. + [[\\txtrm;\\textrm]] [[\\refcpp{([^}]+)};REFCPP(\1)]] [[\\irefcpp{([^}]+)};~(REFCPP(\1))]] [[\\refcppx{([^}]+)}{([^}]+)};REFCPPX(\1)(\2)]] diff --git a/docs/api_reference/src/intro.tex b/docs/api_reference/src/intro.tex index 4daca1c50..a42d36094 100644 --- a/docs/api_reference/src/intro.tex +++ b/docs/api_reference/src/intro.tex @@ -38,6 +38,11 @@ Available from: \url{https://wg21.link/\IsoCpp{}} \item The \Cpp{} Standards Committee. +P3094R5: \doccite{\tcode{std::basic_fixed_string}}. +Edited by Mateusz Pusz. +Available from: \url{https://wg21.link/P3094R5} +\item +The \Cpp{} Standards Committee. SD-8: \doccite{Standard Library Compatibility}. Edited by Bryce Lelbach. Available from: \url{https://wg21.link/SD8} @@ -102,11 +107,11 @@ {ll} \topline \hdstyle{Clause} & \hdstyle{Category} \\ \capsep -\ref{qties} & Quantities library \\ +\ref{quantities} & Quantities library \\ \end{floattable} \pnum -The quantities library\iref{qties} +The quantities library\iref{quantities} describes components for dealing with quantities. \rSec1[spec.mods]{Modules} diff --git a/docs/api_reference/src/macros_extensions.tex b/docs/api_reference/src/macros_extensions.tex index 53eabe670..a8aaa747c 100644 --- a/docs/api_reference/src/macros_extensions.tex +++ b/docs/api_reference/src/macros_extensions.tex @@ -1,5 +1,13 @@ \newcommand{\IsoCpp}{N4971} +\newcommand{\txtrm}[1]{\textnormal{\textrm{#1}}} + +\newcommand{\stdconcept}[1]{#1} + +\newcommand{\indexlibraryglobalexpos}[1]{\indexlibrary{#1@\exposid{#1}}} +\newcommand{\indexlibraryctorexpos}[1]{\indexlibrarymisc{#1@\exposid{#1}}{constructor}} +\newcommand{\indexlibraryexposmemberexpos}[2]{\indexlibraryboth{#1@\exposid{#1}}{#2@\exposid{#2}}} + %% Inline non-parenthesized C++ reference \newcommand{\refcpp}[1]{\href{https://wg21.link/#1}{\IsoCpp{}, [#1]}} \newcommand{\irefcpp}[1]{\nolinebreak[3] (\refcpp{#1})} @@ -8,4 +16,15 @@ %% Inline IEV reference \newcommand{\refiev}[1]{\href{https://www.electropedia.org/iev/iev.nsf/display?openform&ievref=#1}{IEC 60050, #1}} -\newcommand{\irefiev}[1]{\nolinebreak[3] (\refiev{#1})} +\ExplSyntaxOn +\NewDocumentCommand \irefiev { m } { + \clist_set:Nx \l_tmpa_clist { #1 } + \nolinebreak[3] ~ ( + \clist_map_inline:Nn \l_tmpa_clist { + \clist_put_right:Nn \g_tmpa_clist { \refiev{##1} } + } + \clist_use:Nn \g_tmpa_clist { ,~ } + ) + \clist_clear:N \g_tmpa_clist +} +\ExplSyntaxOff diff --git a/docs/api_reference/src/quantities.tex b/docs/api_reference/src/quantities.tex index 56e0d69e5..f02db9463 100644 --- a/docs/api_reference/src/quantities.tex +++ b/docs/api_reference/src/quantities.tex @@ -1,266 +1,6729 @@ %!TEX root = std.tex -\rSec0[qties]{Quantities library} +\rSec0[quantities]{Quantities and units library} -\rSec1[qties.summary]{Summary} +\rSec1[quantities.summary]{Summary} \pnum -This Clause describes components for dealing with quantities, -as summarized in \tref{qties.summary}. +This Clause describes components for dealing with quantities and units, +as summarized in \tref{quantities.summary}. -\begin{modularlibsumtab}{Quantities library summary}{qties.summary} -\ref{qty.helpers} & Helpers & \tcode{mp_units.core} \\ -\ref{qty.traits} & Traits & \\ -\ref{qty.concepts} & Concepts & \\ -\ref{qty.types} & Types & \\ -\ref{qty.compat} & Compatibility & \\ -\ref{qty.one} & Dimension one & \\ \rowsep +\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 \ref{qty.systems} & Systems & \tcode{mp_units.systems} \\ -\ref{qty.chrono} & \tcode{std::chrono} compatibility & \\ +\ref{qty.chrono} & \tcode{std::chrono} interoperability & \\ \end{modularlibsumtab} -\rSec1[mp.units.syn]{Module \tcode{mp_units} synopsis} +\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} + \indexmodule{mp_units}% \begin{codeblock} -export module mp_units; +export module mp_units; + +export import mp_units.core; +export import mp_units.systems; +\end{codeblock} + +\rSec2[mp.units.core.syn]{Module \tcode{mp_units.core} synopsis} +\indexmodule{mp_units.core}% +\begin{codeblock} +// mostly freestanding +export module mp_units.core; + +import std; + +export namespace mp_units { + +// \ref{qty.utils}, utilities + +// \ref{qty.sym.txt}, symbol text + +enum class @\libglobal{character_set}@ : std::int8_t { utf8, portable, default_character_set = utf8 }; + +template +class symbol_text; + +// \ref{qty.sym.expr}, symbolic expressions + +// \ref{qty.sym.expr.types}, types + +template +struct per; + +template + requires @\seebelownc@ +struct power; + +// \ref{qty.ref}, reference + +// \ref{qty.dim}, dimension + +// \ref{qty.dim.concepts}, concepts + +template +concept Dimension = @\seebelownc@; + +template +concept DimensionOf = @\seebelownc@; + +// \ref{qty.dim.types}, types + +template +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 + 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 Out, @\libconcept{Dimension}@ D> +constexpr Out dimension_symbol_to(Out out, D d, const dimension_symbol_formatting& fmt = {}); + +template +consteval std::string_view dimension_symbol(D); + +// \ref{qty.spec}, quantity specification + +// \ref{qty.spec.concepts}, concepts + +template +concept QuantitySpec = @\seebelownc@; + +template +concept QuantitySpecOf = @\seebelownc@; + +// \ref{qty.spec.types}, types + +// \ref{named.qty}, named + +struct is_kind; +inline constexpr is_kind @\libglobal{is_kind}@{}; + +template +struct quantity_spec; // \notdef + +template<@\exposconceptnc{BaseDimension}@ auto Dim, @\exposconceptnc{QSProperty}@ auto... Args> +struct quantity_spec; + +template<@\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args> +struct quantity_spec; + +template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{QSProperty}@ auto... Args> +struct quantity_spec; + +template<@\exposconceptnc{NamedQuantitySpec}@ auto QS, @\exposconceptnc{DerivedQuantitySpec}@ auto Eq, @\exposconceptnc{QSProperty}@ auto... Args> +struct quantity_spec; + +// \ref{derived.qty}, derived + +template<@\exposconceptnc{SymbolicConstant}@... Expr> +struct derived_quantity_spec; + +// \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_; } +inline constexpr kind_of_ @\libglobal{kind_of}@{}; + +// \ref{qty.spec.ops}, operations + +consteval @\libconcept{QuantitySpec}@ auto inverse(@\libconcept{QuantitySpec}@ auto q); + +template + 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 +concept MagConstant = @\seebelownc@; + +template +concept UnitMagnitude = @\seebelownc@; + +// \ref{qty.unit.mag.types}, types + +template + requires(Value > 0) +struct mag_constant; + +// \ref{qty.unit.mag.ops}, operations + +template<@\exposconceptnc{MagArg}@ auto V> +constexpr @\libconcept{UnitMagnitude}@ auto mag = @\seebelownc@; + +template + 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> { +} @\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}@ = false; + +// \ref{qty.unit.concepts}, concepts + +template +concept Unit = @\seebelownc@; + +template +concept PrefixableUnit = @\seebelownc@; + +template +concept AssociatedUnit = @\seebelownc@; + +template +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 +struct named_unit; // \notdef + +template + requires @\seebelownc@ +struct named_unit; + +template + requires @\seebelownc@ +struct named_unit; + +template + requires @\seebelownc@ +struct named_unit; + +template + requires @\seebelownc@ +struct named_unit; + +template + requires @\seebelownc@ +struct named_unit; + +template + requires @\seebelownc@ +struct named_unit; + +template + requires @\seebelownc@ +struct named_unit; + +// \ref{qty.prefixed.unit}, prefixed + +template + 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 * 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 + 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 Out, @\libconcept{Unit}@ U> +constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {}); + +template +consteval std::string_view unit_symbol(U); + +// \ref{qty.ref.concepts}, concepts + +template +concept @\deflibconcept{Reference}@ = @\seebelownc@; + +template +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 Rep = std::remove_cvref_t> + requires(!@\exposconceptnc{OffsetUnit}@) +constexpr quantity operator*(FwdRep&& lhs, R r); + +template Rep = std::remove_cvref_t> + requires(!@\exposconceptnc{OffsetUnit}@) +constexpr @\libconcept{Quantity}@ auto operator/(FwdRep&& lhs, R); + +template> +constexpr @\libconcept{Quantity}@ auto operator*(FwdQ&& q, R); + +template> +constexpr @\libconcept{Quantity}@ auto operator/(FwdQ&& q, R); + +template<@\libconcept{Reference}@ R, typename Rep> + requires @\libconcept{RepresentationOf}@, get_quantity_spec(R{})> +constexpr auto operator*(R, Rep&&) = delete; + +template<@\libconcept{Reference}@ R, typename Rep> + requires @\libconcept{RepresentationOf}@, get_quantity_spec(R{})> +constexpr auto operator/(R, Rep&&) = delete; + +template<@\libconcept{Reference}@ R, typename Q> + requires @\libconcept{Quantity}@> +constexpr auto operator*(R, Q&&) = delete; + +template<@\libconcept{Reference}@ R, typename Q> + requires @\libconcept{Quantity}@> +constexpr auto operator/(R, Q&&) = delete; + +// \ref{qty.ref.obs}, observers + +template +consteval @\libconcept{QuantitySpec}@ auto get_quantity_spec(reference); + +template +consteval @\libconcept{Unit}@ auto get_unit(reference); + +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 +constexpr bool treat_as_floating_point = @\seebelownc@; + +// \ref{qty.char.traits}, quantity character + +template +constexpr bool disable_scalar = false; +template<> +inline constexpr bool @\libspec{disable_scalar}{bool}@ = true; +template +constexpr bool @\libspec{disable_scalar}{std::complex}@> = true; + +template +constexpr bool disable_complex = false; + +template +constexpr bool disable_vector = false; + +// \ref{qty.val.traits}, values + +template +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 +concept Representation = @\seebelownc@; + +template +concept RepresentationOf = @\seebelownc@; + +// \ref{qty}, quantity + +// \ref{qty.like}, interoperability + +template +struct quantity_like_traits; // \notdef + +template +concept QuantityLike = @\seebelownc@; + +// \ref{qty.syn}, class template \tcode{quantity} + +template +concept Quantity = @\seebelownc@; + +template +concept QuantityOf = @\seebelownc@; + +template<@\libconcept{Reference}@ auto R, @\libconcept{RepresentationOf}@ Rep = double> +class quantity; + +// \ref{qty.delta}, construction helper \tcode{delta} + +template<@\libconcept{Reference}@ R> +struct delta_; + +template<@\libconcept{Reference}@ auto R> +constexpr delta_ @\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 + requires @\seebelownc@ +struct std::common_type; + +template + requires @\seebelownc@ +struct std::common_type; + +template + requires requires { typename std::common_type; } +struct @\libspec{std::common_type}{quantity}@ : std::common_type {}; + +namespace mp_units { + +// \ref{qty.pt}, quantity point + +// \ref{qty.pt.orig}, point origin + +// \ref{qty.pt.orig.concepts}, concepts + +template +concept PointOrigin = @\seebelownc@; + +template +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_ @\libglobal{zeroth_point_origin}@{}; + +// \ref{qty.def.pt.orig}, default + +template<@\libconcept{Reference}@ R> +consteval @\libconcept{PointOriginFor}@ auto default_point_origin(R); + +// \ref{qty.pt.like}, interoperability + +template +struct quantity_point_like_traits; // \notdef + +template +concept QuantityPointLike = @\seebelownc@; + +// \ref{qty.pt.syn}, class template \tcode{quantity_point} + +template +concept QuantityPoint = @\seebelownc@; + +template +concept QuantityPointOf = @\seebelownc@; + +template<@\libconcept{Reference}@ auto R, + @\libconcept{PointOriginFor}@ auto PO = default_point_origin(R), + @\libconcept{RepresentationOf}@ Rep = double> +class quantity_point; + +// \ref{qty.point}, construction helper \tcode{point} + +template<@\libconcept{Reference}@ R> +struct point_; + +template<@\libconcept{Reference}@ auto R> +constexpr point_ @\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); + +} +\end{codeblock} + +\rSec2[mp.units.systems.syn]{Module \tcode{mp_units.systems} synopsis} +\indexmodule{mp_units.systems}% +\begin{codeblock} +export module mp_units.systems; + +export import mp_units.core; +import std; + +export namespace mp_units { + +// \ref{qty.chrono}, \tcode{std::chrono} interoperability + +template +struct quantity_like_traits>; + +template +struct chrono_point_origin_; +template +constexpr chrono_point_origin_ @\libglobal{chrono_point_origin}@{}; + +template +struct quantity_point_like_traits< + std::chrono::time_point>>; + +} +\end{codeblock} + +\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 U> +consteval bool @\exposidnc{is-specialization-of}@(); // \expos +template 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}, +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}. + +\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}. + +\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>::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 +class symbol_text { +public: + std::fixed_u8string @\exposidnc{utf8}@; // \expos + std::fixed_string @\exposidnc{portable}@; // \expos + + // constructors + constexpr symbol_text(char portable); + consteval symbol_text(const char (&portable)[N + 1]); + constexpr symbol_text(const std::fixed_string& portable); + consteval symbol_text(const char8_t (&utf8)[N + 1], const char (&portable)[M + 1]); + constexpr symbol_text(const std::fixed_u8string& utf8, + const std::fixed_string& 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 + friend constexpr symbol_text operator+(const symbol_text& lhs, + const symbol_text& rhs); + + // comparison + template + friend constexpr bool operator==(const symbol_text& lhs, + const symbol_text& rhs) noexcept; + template + friend constexpr auto operator<=>(const symbol_text& lhs, + const symbol_text& rhs) noexcept; +}; + +symbol_text(char) -> symbol_text<1, 1>; + +template +symbol_text(const char (&)[N]) -> symbol_text; + +template +symbol_text(const std::fixed_string&) -> symbol_text; + +template +symbol_text(const char8_t (&)[N], const char (&)[M]) -> symbol_text; + +template +symbol_text(const std::fixed_u8string&, const std::fixed_string&) -> symbol_text; + +} +\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} 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& portable); +consteval symbol_text(const char8_t (&utf8)[N + 1], const char (&portable)[M + 1]); +constexpr symbol_text(const std::fixed_u8string& utf8, const std::fixed_string& 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::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 +friend constexpr symbol_text operator+(const symbol_text& lhs, + const symbol_text& rhs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return symbol_text(lhs.utf8() + rhs.utf8(), + lhs.portable() + rhs.portable()); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator==}{symbol_text} +\indexlibrarymember{operator<=>}{symbol_text} +\begin{itemdecl} +template +friend constexpr bool operator==(const symbol_text& lhs, + const symbol_text& rhs) noexcept; +template +friend constexpr auto operator<=>(const symbol_text& lhs, + const symbol_text& 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_, per>>} +\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}} + +\begin{itemdecl} +template +concept @\defexposconceptnc{SymbolicConstant}@ = // \expos + std::is_empty_v && std::is_final_v && std::is_trivially_default_constructible_v && + std::is_trivially_copy_constructible_v && std::is_trivially_move_constructible_v && + std::is_trivially_destructible_v; +\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 +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 + 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 +using @\exposidnc{expr-type}@ = @\seebelownc@; // \expos +\end{codeblock} + +\pnum +\tcode{\exposidnc{expr-type}} denotes +\tcode{U} if \tcode{T} is of the form \tcode{power}, and +\tcode{T} otherwise. + +\indexlibraryglobalexpos{type-less-impl} +\begin{itemdecl} +template +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 +struct @\exposidnc{type-less}@ : // \expos + std::bool_constant<@\exposidnc{is-specialization-of}@() || + @\exposidnc{type-less-impl}@<@\exposidnc{expr-type}@, @\exposidnc{expr-type}@>()> {}; +\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 +struct @\exposidnc{type-list}@ {}; // \expos + +template +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}>}, +then +\begin{itemize} +\item +\tcode{EF::\exposidnc{num}} denotes \tcode{\exposidnc{type-list}}, and +\item +\tcode{EF::\exposidnc{den}} denotes \tcode{\exposidnc{type-list}}. +\end{itemize} +\item +Otherwise, \tcode{EF} is of the form \tcode{\exposidnc{expr-fractions}}, and +\begin{itemize} +\item +\tcode{EF::\exposidnc{num}} denotes \tcode{\exposidnc{type-list}}, 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 typename To, typename OneType, + template typename Pred = @\exposidnc{type-less}@, typename Lhs, typename Rhs> +consteval auto @\exposidnc{expr-multiply}@(Lhs, Rhs); // \expos + +template typename To, typename OneType, + template typename Pred = @\exposidnc{type-less}@, typename Lhs, typename Rhs> +consteval auto @\exposidnc{expr-divide}@(Lhs lhs, Rhs rhs); // \expos + +template typename To, typename OneType, typename T> +consteval auto @\exposidnc{expr-invert}@(T); // \expos + +template typename To, + typename OneType, template 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}. +\tcode{Pred} 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}, +then its input is $\tcode{F}^\tcode{Num}$, or +a specialization of the form \tcode{power}, +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, per>}, +\begin{itemize} +\item +to $\tcode{decltype(km)} \times \tcode{per}$ (product of \tcode{To}'s arguments), +\item +to $\tcode{decltype(km)} \times 1/\tcode{power}$ (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 typename Proj, template typename To, typename OneType, + template 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}} be +\tcode{power, Ints...>} if \tcode{U} is of the form \tcode{power}, and +\tcode{Proj} otherwise, +\item +\tcode{\exposidnc{map-power}(u)} be +\tcode{pow(F\{\})} if \tcode{decltype(u)} is of the form \tcode{power}, 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}@{})) / +(OneType{} * ... * @\exposidnc{map-power}@(@\exposidnc{expr-type-map}@{})) +\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 +concept @\deflibconcept{Dimension}@ = @\exposconceptnc{SymbolicConstant}@ && std::@\stdconcept{derived_from}@; + +template +concept @\defexposconceptnc{BaseDimension}@ = // \expos + @\libconcept{Dimension}@ && (@\exposidnc{is-derived-from-specialization-of}@()); + +template +concept @\deflibconcept{DimensionOf}@ = @\libconcept{Dimension}@ && @\libconcept{Dimension}@ && (T{} == D); +\end{itemdecl} + +\rSec3[qty.dim.types]{Types} + +\begin{codeblock} +namespace mp_units { + +template +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 +struct @\exposidnc{derived-dimension-impl}@ // \expos + : @\exposidnc{expr-fractions}@ {}; + +template<@\exposconceptnc{SymbolicConstant}@... Expr> +struct derived_dimension final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@ {}; + +} +\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>>} +\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}(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}(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}. +\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 + requires(Den != 0) +consteval @\libconcept{Dimension}@ auto pow(D d); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\exposidnc{expr-pow}(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 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 +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 +concept @\deflibconcept{QuantitySpec}@ = @\exposconceptnc{SymbolicConstant}@ && std::@\stdconcept{derived_from}@; + +template +concept @\defexposconceptnc{QuantityKindSpec}@ = // \expos + @\libconcept{QuantitySpec}@ && @\exposidnc{is-specialization-of}@(); + +template +concept @\defexposconceptnc{NamedQuantitySpec}@ = // \expos + @\libconcept{QuantitySpec}@ && @\exposidnc{is-derived-from-specialization-of}@() && + (!@\exposconceptnc{QuantityKindSpec}@); + +template +concept @\defexposconceptnc{DerivedQuantitySpec}@ = // \expos + @\libconcept{QuantitySpec}@ && + (@\exposidnc{is-specialization-of}@() || + (@\exposconceptnc{QuantityKindSpec}@ && + @\exposidnc{is-specialization-of}@())); + +template +concept @\defexposconceptnc{ChildQuantitySpecOf}@ = (@\exposidnc{is-child-of}@(Child, Parent)); // \expos + +template +concept @\defexposconceptnc{NestedQuantityKindSpecOf}@ = // \expos + @\libconcept{QuantitySpec}@ && @\libconcept{QuantitySpec}@ && + (get_kind(From) != get_kind(To)) && @\exposconceptnc{ChildQuantitySpecOf}@; + +template +concept @\defexposconceptnc{QuantitySpecConvertibleTo}@ = // \expos + @\libconcept{QuantitySpec}@ && @\libconcept{QuantitySpec}@ && implicitly_convertible(From, To); + +template +concept @\defexposconceptnc{QuantitySpecExplicitlyConvertibleTo}@ = // \expos + @\libconcept{QuantitySpec}@ && @\libconcept{QuantitySpec}@ && explicitly_convertible(From, To); + +template +concept @\defexposconceptnc{QuantitySpecCastableTo}@ = // \expos + @\libconcept{QuantitySpec}@ && @\libconcept{QuantitySpec}@ && castable(From, To); + +template +concept @\deflibconcept{QuantitySpecOf}@ = + @\libconcept{QuantitySpec}@ && @\libconcept{QuantitySpec}@ && @\exposconceptnc{QuantitySpecConvertibleTo}@ && + !@\exposconceptnc{NestedQuantityKindSpecOf}@ && + (@\exposconceptnc{QuantityKindSpec}@ || !@\exposconceptnc{NestedQuantityKindSpecOf}@); + +template +concept @\defexposconceptnc{QSProperty}@ = (!@\libconcept{QuantitySpec}@); // \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 : @\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 : @\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 : @\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}@ +struct quantity_spec : @\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 { +} length; // Length is a base quantity. + +// The second signature defines a derived quantity. +inline constexpr struct area final : quantity_spec(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 { +} 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 { +} 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 +struct @\exposidnc{derived-quantity-spec-impl}@ : // \expos + @\exposidnc{quantity-spec-interface}@, + @\exposidnc{expr-fractions}@ { + using @\exposidnc{base-type}@ = @\exposidnc{derived-quantity-spec-impl}@; + using @\exposidnc{base}@ = @\exposidnc{expr-fractions}@; + + 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}@ {}; + +} +\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>} +\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}@::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> {}; + +} +\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}@) && (@\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} 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}@)) + return kind_of; +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}@) + 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}@) || @\libconcept{UnitOf}@ +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{}; +\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 U> + consteval @\libconcept{Reference}@ auto operator[](this Self self, U u); + + template> + requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@ + 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}@(@\exposidnc{expr-multiply}@( + @\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}@(@\exposidnc{expr-divide}@( + @\exposidnc{remove-kind}@(lhs), @\exposidnc{remove-kind}@(rhs))) +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{operator[]}{QuantitySpec} +\begin{itemdecl} +template 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> + requires @\exposconceptnc{QuantitySpecExplicitlyConvertibleTo}@ +constexpr @\libconcept{Quantity}@ auto operator()(this Self self, FwdQ&& q); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +quantity{std::forward(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}. +\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 + requires(Den != 0) +consteval @\libconcept{QuantitySpec}@ auto pow(Q q); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{codeblock} +@\exposidnc{clone-kind-of}@( + @\exposidnc{expr-pow}@(@\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}} is \tcode{true}, +returns \tcode{\exposidnc{remove-kind}(q)}. +\item +Otherwise, if +\tcode{\exposidnc{is-derived-from-specialization-of}()} +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}} 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) + return q1; + else if constexpr (@\exposconceptnc{NestedQuantityKindSpecOf}@) + return QQ1{}; + else if constexpr (@\exposconceptnc{NestedQuantityKindSpecOf}@) + return QQ2{}; + else if constexpr ((@\exposconceptnc{QuantityKindSpec}@ && !@\exposconceptnc{QuantityKindSpec}@) || + (@\exposconceptnc{DerivedQuantitySpec}@ && @\exposconceptnc{NamedQuantitySpec}@ && + implicitly_convertible(Q1{}, Q2{}))) + return q2; + else if constexpr ((!@\exposconceptnc{QuantityKindSpec}@ && @\exposconceptnc{QuantityKindSpec}@) || + (@\exposconceptnc{NamedQuantitySpec}@ && @\exposconceptnc{DerivedQuantitySpec}@ && + implicitly_convertible(Q2{}, Q1{}))) + return q1; + else if constexpr (constexpr auto common_base = @\exposidnc{get-common-base}@()) + 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 +concept @\deflibconcept{MagConstant}@ = @\exposconceptnc{SymbolicConstant}@ && @\exposidnc{is-derived-from-specialization-of}@(); + +template +concept @\deflibconcept{UnitMagnitude}@ = (@\exposidnc{is-specialization-of}@()); + +template +concept @\defexposconceptnc{MagArg}@ = std::@\stdconcept{integral}@ || @\libconcept{MagConstant}@; // \expos +\end{itemdecl} + +\rSec4[qty.unit.mag.types]{Types} + +\indexlibraryglobal{mag_constant} +\begin{codeblock} +namespace mp_units { + +template + 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 +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 + 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 + friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@, // \expos + @\exposidnc{unit-magnitude}@); +}; + +} +\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>}, 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 +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}} is satisfied, +initializes \tcode{mag} with \tcode{\exposidnc{unit-magnitude}\{\}}. +Otherwise, initializes \tcode{mag} with +an unspecified value equal to \tcode{V}. +\end{itemdescr} + +\indexlibraryglobal{mag_ratio} +\begin{itemdecl} +template + 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}@(mag); +\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 +friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@, @\exposidnc{unit-magnitude}@); // \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 +concept @\deflibconcept{Unit}@ = @\exposconceptnc{SymbolicConstant}@ && std::@\stdconcept{derived_from}@; + +template +concept @\deflibconcept{PrefixableUnit}@ = @\libconcept{Unit}@ && @\exposidnc{is-derived-from-specialization-of}@(); + +template +concept @\deflibconcept{AssociatedUnit}@ = @\libconcept{Unit}@ && @\exposidnc{has-associated-quantity}@(U{}); + +template +concept @\deflibconcept{UnitOf}@ = @\libconcept{AssociatedUnit}@ && @\libconcept{QuantitySpec}@ && + @\exposconceptnc{QuantitySpecConvertibleTo}@ && + (get_kind(QS) == get_kind(get_quantity_spec(U{})) || + !@\exposconceptnc{NestedQuantityKindSpecOf}@); + +template +concept @\defexposconceptnc{UnitConvertibleTo}@ = // \expos + @\libconcept{Unit}@ && @\libconcept{Unit}@ && (convertible(From, To)); + +template +concept @\defexposconceptnc{UnitCompatibleWith}@ = // \expos + @\libconcept{Unit}@ && @\libconcept{Unit}@ && @\libconcept{QuantitySpec}@ && + (!@\libconcept{AssociatedUnit}@ || @\libconcept{UnitOf}@) && @\exposconceptnc{UnitConvertibleTo}@; + +template +concept @\defexposconceptnc{OffsetUnit}@ = @\libconcept{Unit}@ && requires { T::@\exposidnc{point-origin}@; }; // \expos + +template +concept @\defexposconceptnc{PotentiallyConvertibleTo}@ = // \expos + @\libconcept{Unit}@ && @\libconcept{Unit}@ && + ((@\libconcept{AssociatedUnit}@ && @\libconcept{AssociatedUnit}@ && + implicitly_convertible(get_quantity_spec(From{}), get_quantity_spec(To{}))) || + (!@\libconcept{AssociatedUnit}@ && !@\libconcept{AssociatedUnit}@)); +\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} 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 + requires(!Symbol.empty()) && @\exposconceptnc{BaseDimension}@ +struct named_unit : @\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 + requires(!Symbol.empty()) && @\exposconceptnc{BaseDimension}@ +struct named_unit : @\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 + requires(!Symbol.empty()) +struct named_unit : @\exposidnc{unit-interface}@ { + using @\exposidnc{base-type}@ = named_unit; // \expos + static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos +}; + +template + requires(!Symbol.empty()) +struct named_unit : decltype(U)::@\exposidnc{base-type}@ { + using @\exposidnc{base-type}@ = named_unit; // \expos + static constexpr auto @\exposidnc{symbol}@ = Symbol; // \expos +}; + +template + requires(!Symbol.empty()) +struct named_unit : 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 + requires(!Symbol.empty()) && (QS.dimension == @\exposidnc{get-associated-quantity}@(U).dimension) +struct named_unit : 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 + requires(!Symbol.empty()) && (QS.dimension == @\exposidnc{get-associated-quantity}@(U).dimension) +struct named_unit : 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