forked from mpusz/mp-units
6730 lines
226 KiB
TeX
6730 lines
226 KiB
TeX
%!TEX root = std.tex
|
|
\rSec0[quantities]{Quantities and units library}
|
|
|
|
\rSec1[quantities.summary]{Summary}
|
|
|
|
\pnum
|
|
This Clause describes components for dealing with quantities and units,
|
|
as summarized in \tref{quantities.summary}.
|
|
|
|
\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} interoperability & \\
|
|
\end{modularlibsumtab}
|
|
|
|
\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 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<std::size_t N, std::size_t M>
|
|
class symbol_text;
|
|
|
|
// \ref{qty.sym.expr}, symbolic expressions
|
|
|
|
// \ref{qty.sym.expr.types}, types
|
|
|
|
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
|
|
|
|
template<typename T>
|
|
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
|
|
|
|
template<typename T>
|
|
concept QuantitySpec = @\seebelownc@;
|
|
|
|
template<typename T, auto QS>
|
|
concept QuantitySpecOf = @\seebelownc@;
|
|
|
|
// \ref{qty.spec.types}, types
|
|
|
|
// \ref{named.qty}, named
|
|
|
|
struct is_kind;
|
|
inline constexpr is_kind @\libglobal{is_kind}@{};
|
|
|
|
template<auto...>
|
|
struct quantity_spec; // \notdef
|
|
|
|
template<@\exposconceptnc{BaseDimension}@ auto Dim, @\exposconceptnc{QSProperty}@ auto... Args>
|
|
struct quantity_spec<Dim, Args...>;
|
|
|
|
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>
|
|
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_<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>
|
|
class quantity;
|
|
|
|
// \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>
|
|
class quantity_point;
|
|
|
|
// \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);
|
|
|
|
}
|
|
\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<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>>>;
|
|
|
|
}
|
|
\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 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}}
|
|
|
|
\begin{itemdecl}
|
|
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);
|
|
\end{itemdecl}
|
|
|
|
\begin{itemdescr}
|
|
\pnum
|
|
\expects
|
|
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}}.
|
|
|
|
\pnum
|
|
\returns
|
|
\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}.
|
|
\end{itemdescr}
|
|
|
|
\indexlibrarymember{operator*=}{quantity}
|
|
\indexlibrarymember{operator/=}{quantity}
|
|
\begin{itemdecl}
|
|
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);
|
|
\end{itemdecl}
|
|
|
|
\begin{itemdescr}
|
|
\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)}.
|
|
|
|
\pnum
|
|
\remarks
|
|
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}
|
|
\end{itemdescr}
|
|
|
|
\indexlibrarymember{operator*=}{quantity}
|
|
\indexlibrarymember{operator/=}{quantity}
|
|
\begin{itemdecl}
|
|
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);
|
|
\end{itemdecl}
|
|
|
|
\begin{itemdescr}
|
|
\pnum
|
|
\effects
|
|
Equivalent to:
|
|
\tcode{return std::forward<Q>(lhs) @ rhs.\exposid{numerical-value};}
|
|
|
|
\pnum
|
|
\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}
|
|
|
|
\pnum
|
|
In the following descriptions,
|
|
let \tcode{@} be the \fakegrammarterm{operator}.
|
|
|
|
\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}
|
|
|
|
\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_}
|
|
\begin{codeblock}
|
|
namespace mp_units {
|
|
|
|
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;
|
|
};
|
|
|
|
}
|
|
\end{codeblock}
|
|
|
|
\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}
|
|
|
|
\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}
|
|
|
|
\begin{codeblock}
|
|
namespace mp_units {
|
|
|
|
template<@\libconcept{QuantitySpec}@ auto QS>
|
|
struct @\libglobal{absolute_point_origin}@ : @\exposidnc{point-origin-interface}@ {
|
|
static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = QS; // \expos
|
|
};
|
|
|
|
}
|
|
\end{codeblock}
|
|
|
|
\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.
|
|
|
|
\rSec4[qty.rel.pt.orig]{Relative}
|
|
|
|
\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}
|
|
|
|
\rSec1[qty.systems]{Systems}
|
|
|
|
\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}
|