5 Quantities and units library [quantities]

5.3 Utilities [qty.utils]

5.3.4 Symbolic expressions [qty.sym.expr]

5.3.4.4 Algorithms [qty.sym.expr.algos]

template<typename T> using expr-type = see below; // exposition only
expr-type<T> denotes U if T is of the form power<U, Ints...>, and T otherwise.
template<typename T, typename U> consteval bool type-less-impl(); // exposition only
Returns: true if T is less than U in an implementation-defined total order for types, and false otherwise.
template<typename Lhs, typename Rhs> struct type-less : // exposition only std::bool_constant<is-specialization-of<Rhs, power>() || type-less-impl<expr-type<Lhs>, expr-type<Rhs>>()> {};
type-less meets the requirements of the Pred parameter of the symbolic expression algorithms below.
template<typename... Ts> struct type-list {}; // exposition only template<typename OneType, typename... Ts> struct expr-fractions { // exposition only using num = see below; // exposition only using den = see below; // exposition only }
expr-fractions divides a symbolic expression to numerator and denominator parts.
Let EF be a specialization of expr-fractions.
  • If EF is of the form expr-fractions<OneType, Ts..., per<Us...>>, then
    • EF​::​num denotes type-list<Ts...>, and
    • EF​::​den denotes type-list<Us...>.
  • Otherwise, EF is of the form expr-fractions<OneType, Ts...>, and
    • EF​::​num denotes type-list<Ts...>, and
    • EF​::​den denotes type-list<>.
The symbolic expression algorithms perform operations on symbolic constants.
A symbolic constant is a type that is a model of SymbolicConstant.
[Example 1: 
The dimension dim_length, the quantity time, and the unit 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.
template<template<typename...> typename To, typename OneType, template<typename, typename> typename Pred = type-less, typename Lhs, typename Rhs> consteval auto expr-multiply(Lhs, Rhs); // exposition only template<template<typename...> typename To, typename OneType, template<typename, typename> typename Pred = type-less, typename Lhs, typename Rhs> consteval auto expr-divide(Lhs lhs, Rhs rhs); // exposition only template<template<typename...> typename To, typename OneType, typename T> consteval auto expr-invert(T); // exposition only template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To, typename OneType, template<typename, typename> typename Pred = type-less, typename T> requires(Den != 0) consteval auto expr-pow(T); // exposition only
Mandates:
  • OneType is the neutral element (IEC 60050, 102-01-19) of the operation, and
  • Pred is a Cpp17BinaryTypeTrait (N4971, [meta.rqmts]) with a base characteristic of std​::​bool_constant<B>.
    Pred<T, U> implements a total order for types; B is true if T is ordered before U, and false otherwise.
Effects:
First, inputs to the operations are obtained from the types of the function parameters.
If the type of a function parameter is:
  • A specialization of To, then its input is the product of its template arguments, and the following also apply.
  • A specialization of per, then its input is the product of the inverse of its template arguments, and the following also apply.
  • A specialization of the form power<F, Num>, then its input is , or a specialization of the form power<F, Num, Den>, then its input is , and the following also applies.
  • Otherwise, the input is the symbolic constant itself.
[Example 2: 
Item by item, this algorithm step goes from the C++ parameter type decltype(km / square(h)), styled in diagnostics like derived_unit<si​::​kilo_<si​::​metre>, per<power<non_si​::​hour, 2>>,
  • to decltype(km) ×per<power<decltype(h), 2> (product of To's arguments),
  • to (product of inverse of per's arguments),
  • to (powers as powers),
  • to where and (symbolic substitution) in the mathematical domain.
— end example]
Then, the operation takes place:
  • expr-multiply multiplies its inputs,
  • expr-divide divides the input of its first parameter by the input of its second parameter,
  • expr-invert divides 1 by its input, and
  • expr-pow raises its input to the .
Finally, let r be the result of the operation simplified as follows:
  • All terms are part of the same fraction (if any).
  • There is at most a single term with a given symbolic constant.
  • There are no negative exponents.
  • 1 is only present as r and as a numerator with a denominator not equal to 1.
[Example 3: 
Item by item:

(single fraction)
(unique symbolic constants)
(positive exponents)
(non-redundant 1s)
— end example]
Returns: r is mapped to the return type:
  • If , returns OneType{}.
  • Otherwise, if r is a symbolic constant, returns r.
  • Otherwise, first applies the following mappings to the terms of r:
    • is mapped to power<x, n, d>, and is mapped to power<x, n>, and
    • 1 is mapped to OneType{}.
  • Then, a denominator x of r (if any) is mapped to per<x>.
  • Then, sorts r without per (if any) and the template arguments of per (if any) according to Pred.
  • Finally, returns To<r>{}, where per (if any) is the last argument.
Remarks: A valid template argument list for To and per is formed by interspersing commas between each mapped term.
If a mapping to std​::​intmax_t is not representable, the program is ill-formed.
expr-map maps the contents of one symbolic expression to another resulting in a different type list.
template<template<typename> typename Proj, template<typename...> typename To, typename OneType, template<typename, typename> typename Pred = type-less, typename T> consteval auto expr-map(T); // exposition only
Let
  • expr-type-map<U> be power<Proj<F>, Ints...> if U is of the form power<F, Ints...>, and Proj<U> otherwise,
  • map-power(u) be pow<Ints...>(F{}) if decltype(u) is of the form power<F, Ints...>, and u otherwise, and
  • Nums and Dens be packs denoting the template arguments of T​::​nums and T​::​dens, respectively.
Returns: (OneType{} * ... * map-power(expr-type-map<Nums>{})) / (OneType{} * ... * map-power(expr-type-map<Dens>{}))