Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(ref): document mp_units.core #628

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
644b8d1
docs(ref): document `mp_units.core`
JohelEGP Oct 13, 2024
600a69b
docs(ref): document `mp_units.core`
JohelEGP Oct 13, 2024
e819430
docs(ref): document `mp_units.core`
JohelEGP Oct 13, 2024
9a9c343
docs(ref): document `mp_units.core`
JohelEGP Oct 13, 2024
543254a
docs(ref): document `mp_units.core`
JohelEGP Oct 13, 2024
d454ccc
docs(ref): document `mp_units.core`
JohelEGP Oct 13, 2024
60dd2cb
docs(ref): fill [qty.ref]
JohelEGP Oct 24, 2024
d9248b1
[mp.units.core.syn] Update pi's UCN
JohelEGP Oct 25, 2024
824f0c1
[qty.unit.types] Update `Magnitude * Unit`
JohelEGP Oct 25, 2024
8bce9c6
[qty.dim.types] Fix `derived_dimension` example
JohelEGP Oct 25, 2024
58487d6
[qty.spec.concepts] Update _`QuantityKindSpec`_
JohelEGP Oct 25, 2024
0cab71d
Merge branch 'master' into ref_docs
JohelEGP Oct 25, 2024
1f6be11
[mp.units.core.syn] Add \u03C0
JohelEGP Oct 26, 2024
17585ce
[qty.spec.types] Improve description of `kind_of`
JohelEGP Oct 26, 2024
9b35ad4
[qty.unit.types] Fix `named_unit` description of "kind" parameter
JohelEGP Oct 26, 2024
ae58e6c
[qty.unit.types] Improve `named_unit` example comment
JohelEGP Oct 26, 2024
14c0ee6
[qty.unit.types] Further improve `named_unit` example comments
JohelEGP Oct 26, 2024
f542ffb
[qty.unit.types] Mark `derived_unit` as `final`
JohelEGP Oct 26, 2024
24842ca
[qty] Avoid idiom in detailed specifications
JohelEGP Oct 26, 2024
ac09cec
[qty.ratio] Implement `common_ratio` in terms of `std::`
JohelEGP Oct 26, 2024
399dcd0
[qty.spec] Update for removal of _`DerivedQuantitySpecExpr`_
JohelEGP Oct 26, 2024
2f8c2b1
[qty.unit] Update for removal of _`DerivedUnitExpr`_
JohelEGP Oct 26, 2024
aa5aa63
[qty.mag] Update for removal of _`MagnitudeSpecExpr`_
JohelEGP Oct 26, 2024
9ecd87e
[qty.spec] Update for removal of _`QuantitySpecWithNoSpecifiers`_
JohelEGP Oct 26, 2024
49cb247
[qty.mag] Update for parameter renames
JohelEGP Oct 26, 2024
0248136
[qty.dim] Update for removal of _`DerivedDimensionExpr`_
JohelEGP Oct 26, 2024
04eab10
Merge branch 'master' into ref_docs
JohelEGP Oct 26, 2024
71bfcf8
[qty.ratio] Fix "Equivalent to:" formatting
JohelEGP Oct 26, 2024
b94ec34
[qty.spec.types] Improve the kind of quantity hierarchy function
JohelEGP Oct 26, 2024
1917e12
[qty.ref] Avoid adjacent `itemdecl` `codeblock` environments
JohelEGP Oct 26, 2024
2b23001
[qty.val.traits] Do not use `std::chrono::duration_values<Rep>::one()`
JohelEGP Oct 26, 2024
df90897
[mp.units.core.syn] Fix `derived_quantity_spec`'s template parameter
JohelEGP Oct 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions docs/api_reference/src/intro.tex
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@
Available from: \url{https://wg21.link/\IsoCpp{}}
\item
The \Cpp{} Standards Committee.
P2900R10: \doccite{Contracts for \Cpp{}}.
Edited by Joshua Berne.
Available from: \url{https://wg21.link/P2900R10}
\item
The \Cpp{} Standards Committee.
P2996R7: \doccite{Reflection for \Cpp{}26}.
Edited by Barry Revzin.
Available from: \url{https://wg21.link/P2996R7}
Expand Down
167 changes: 58 additions & 109 deletions docs/api_reference/src/quantities.tex
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we specify that some public identifiers should not be exported from the std module?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading https://wg21.link/std.modules, it seems like there's no way.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will ask LWG members

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping in mid-stream here -- is there a problem with marking them as exposition only? That basically says -- we're going to act like this thing exists in the standard, but we might implement it differently or call it something different.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exposition-only is not a solution, as I wrote in the LWG reflector.

Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@
template<symbol_text Symbol>
struct base_dimension;

template<@\seebelownc@>
template<typename... Expr>
struct derived_dimension;

struct dimension_one;
inline constexpr dimension_one dimension_one = @\seebelownc@;
inline constexpr dimension_one @\libglobal{dimension_one}@{};

consteval @\libconcept{Dimension}@ auto @\liboverload{inverse}{\cname{Dimension}}@(@\libconcept{Dimension}@ auto d) { return dimension_one / d; }

Expand Down Expand Up @@ -133,11 +133,11 @@
requires @\seebelownc@
struct quantity_spec<QS, Eq, Args...>;

template<@\exposconceptnc{DerivedQuantitySpecExpr}@... Expr>
template<typename Expr>
JohelEGP marked this conversation as resolved.
Show resolved Hide resolved
struct derived_quantity_spec;

struct dimensionless;
inline constexpr dimensionless dimensionless = @\seebelownc@;
inline constexpr dimensionless @\libglobal{dimensionless}@{};

template<typename Q>
requires @\seebelownc@
Expand Down Expand Up @@ -181,7 +181,7 @@
requires(Value > 0)
struct mag_constant;

template<@\exposconceptnc{MagnitudeSpecExpr}@ auto... Ms>
template<auto... Ms>
struct magnitude;

template<@\exposconceptnc{MagArg}@ auto V>
Expand Down Expand Up @@ -274,11 +274,11 @@
template<@\libconcept{Unit}@ U1, @\libconcept{Unit}@ U2, @\libconcept{Unit}@... Rest>
struct common_unit;

template<@\exposconceptnc{DerivedUnitExpr}@... Expr>
template<typename... Expr>
struct derived_unit;

struct one;
inline constexpr one one = @\seebelownc@;
inline constexpr one @\libglobal{one}@{};

consteval @\libconcept{Unit}@ auto @\liboverload{inverse}{\cname{Unit}}@(@\libconcept{Unit}@ auto u) { return one / u; }

Expand Down Expand Up @@ -570,24 +570,17 @@

consteval bool is_integral(@\exposidnc{ratio}@ r) { return r.num % r.den == 0; }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it should be a public interface or exposition-only?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it exposition-only unless there's a reason not to.
The thing could blow up to be its own proposal.


consteval @\exposidnc{ratio}@ common_ratio(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2)
{
if (r1.num == r2.num && r1.den == r2.den) return r1;

// $\operatorname{gcd}(a/b, c/d) = \operatorname{gcd}(ad, cb) / bd$
contract_assert(std::numeric_limits<std::intmax_t>::max() / r1.num > r2.den);
contract_assert(std::numeric_limits<std::intmax_t>::max() / r2.num > r1.den);
contract_assert(std::numeric_limits<std::intmax_t>::max() / r1.den > r2.den);

const std::intmax_t num = std::gcd(r1.num * r2.den, r2.num * r1.den);
const std::intmax_t den = r1.den * r2.den;
const std::intmax_t gcd = std::gcd(num, den);
return @\exposidnc{ratio}@{num / gcd, den / gcd};
}
consteval @\exposidnc{ratio}@ common_ratio(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2);

}
\end{codeblock}

\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}.

\begin{itemdecl}
consteval @\exposidnc{ratio}@(std::intmax_t n, std::intmax_t d = 1);
\end{itemdecl}
Expand All @@ -612,15 +605,30 @@

\begin{itemdescr}
\pnum
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}.
Let \tcode{Res} be \tcode{std::ratio_multiply<R(lhs), R(rhs)>}.

\pnum
\effects
Equivalent to: \tcode{return \exposidnc{ratio}\{Res::num, Res::den\}}.
\end{itemdescr}

\begin{itemdecl}
consteval @\exposidnc{ratio}@ common_ratio(@\exposidnc{ratio}@ r1, @\exposidnc{ratio}@ r2);
\end{itemdecl}

\begin{itemdescr}
\pnum
Let \tcode{Res} be
\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 \exposidnc{ratio}\{Res::num, Res::den\}}.
\end{itemdescr}

\rSec2[qty.fixed.string]{Class template \exposidnc{basic-fixed-string}}

\rSec2[qty.symbol.text]{Class template \tcode{symbol_text}}
Expand Down Expand Up @@ -837,26 +845,6 @@
template<typename T>
concept @\defexposconceptnc{BaseDimension}@ = @\libconcept{Dimension}@<T> && std::@\stdconcept{derived_from}@<T, base_dimension>;

consteval bool @\exposidnc{is-dimension-one}@(std::meta::info type_alias) {
return dealias(type_alias) == ^dimension_one;
}

template<typename T>
concept @\defexposconceptnc{IsPowerOfDim}@ =
(@\exposidnc{is-specialization-of}@(^T, ^power) &&
(@\exposconceptnc{BaseDimension}@<typename T::factor> || @\exposidnc{is-dimension-one}@(^typename T::factor)));

template<typename T>
constexpr bool @\exposidnc{is-per-of-dims}@ = false;

template<typename... Ts>
constexpr bool @\exposidnc{is-per-of-dims}@<per<Ts...>> =
(... && (@\exposconceptnc{BaseDimension}@<Ts> || @\exposidnc{is-dimension-one}@(^Ts) || @\exposconceptnc{IsPowerOfDim}@<Ts>));

template<typename T>
concept @\defexposconceptnc{DerivedDimensionExpr}@ =
@\exposconceptnc{BaseDimension}@<T> || @\exposidnc{is-dimension-one}@(^T) || @\exposconceptnc{IsPowerOfDim}@<T> || @\exposidnc{is-per-of-dims}@<T>;

template<typename T, auto D>
concept @\deflibconcept{DimensionOf}@ = @\libconcept{Dimension}@<T> && @\libconcept{Dimension}@<decltype(D)> && T{} == D;
\end{itemdecl}
Expand Down Expand Up @@ -903,10 +891,10 @@
\begin{codeblock}
namespace mp_units {

template<@\exposconceptnc{DerivedDimensionExpr}@... Expr>
template<typename... Expr>
struct @\exposidnc{derived-dimension-impl}@ : @\exposidnc{expr-fractions}@<struct dimension_one, Expr...> {};

template<@\exposconceptnc{DerivedDimensionExpr}@... Expr>
template<typename... Expr>
struct @\libglobal{derived_dimension}@ final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<Expr...> {};

}
Expand All @@ -926,8 +914,7 @@
\begin{codeblock}
namespace mp_units {

inline constexpr struct @\libglobal{dimension_one}@ final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<> {
} @\libglobal{dimension_one}@;
struct @\libglobal{dimension_one}@ final : @\exposidnc{dimension-interface}@, @\exposidnc{derived-dimension-impl}@<> {};

}
\end{codeblock}
Expand Down Expand Up @@ -999,26 +986,6 @@
concept @\defexposconceptnc{NamedQuantitySpec}@ =
@\libconcept{QuantitySpec}@<T> && std::@\stdconcept{derived_from}@<T, quantity_spec> && !@\exposconceptnc{QuantityKindSpec}@<T>;

consteval bool @\exposidnc{is-dimensionless}@(std::meta::info type_alias) {
return dealias(type_alias) == ^dimensionless;
}

template<typename T>
concept @\defexposconceptnc{IsPowerOfQuantitySpec}@ =
(@\exposidnc{is-specialization-of}@(^T, ^power) &&
(@\exposconceptnc{NamedQuantitySpec}@<typename T::factor> || @\exposidnc{is-dimensionless}@(^typename T::factor)));

template<typename T>
constexpr bool @\exposidnc{is-per-of-quantity-specs}@ = false;

template<typename... Ts>
constexpr bool @\exposidnc{is-per-of-quantity-specs}@<per<Ts...>> =
(... && (@\exposconceptnc{NamedQuantitySpec}@<Ts> || @\exposidnc{is-dimensionless}@(^Ts) || @\exposconceptnc{IsPowerOfQuantitySpec}@<Ts>));

template<typename T>
concept @\defexposconceptnc{DerivedQuantitySpecExpr}@ = @\exposconceptnc{NamedQuantitySpec}@<T> || @\exposidnc{is-dimensionless}@(^T) ||
@\exposconceptnc{IsPowerOfQuantitySpec}@<T> || @\exposidnc{is-per-of-quantity-specs}@<T>;

template<typename T>
concept @\defexposconceptnc{DerivedQuantitySpec}@ =
@\libconcept{QuantitySpec}@<T> &&
Expand Down Expand Up @@ -1263,7 +1230,7 @@
\begin{codeblock}
namespace mp_units {

template<@\exposconceptnc{DerivedQuantitySpecExpr}@... Expr>
template<typename... Expr>
struct @\exposidnc{derived-quantity-spec-impl}@ :
@\exposidnc{quantity-spec-interface}@,
@\exposidnc{expr-fractions}@<struct dimensionless, Expr...> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this, I had a "chicken and egg problem". This is why I used is_dimensionless instead. Did you manage to workaround this issue and use dimensionless directly here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I had no idea.

But the C++ standard specification is not code.
Implementors are expected to make it work,
just like how we use names introduced later without a forward declaration.

But I suppose there'd be less friction
if we avoided that for this implementation detail.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where a complete type for the OneType is needed
in the mp-units implementation of expr_fractions.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what you mean. It is used here:

if constexpr (size == 2 && OneType<type_list_front<List>>::value)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, yes, that's called OneType.
I mean the actual type representing the neutral element.
In these cases, one, dimension_one, and dimensionless.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never provided those in my implementation. It was your design change 😉

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reference documentation doesn't need the OneType to be complete.
Even if it did, maybe it's OK:

But the C++ standard specification is not code.
Implementors are expected to make it work,
just like how we use names introduced later without a forward declaration.

I also don't see where you need a complete type in mp-units.
So maybe it was a problem in the past, but it wouldn't be anymore.

Expand All @@ -1276,7 +1243,7 @@
@\exposidnc{derived-quantity-character}@(typename @\exposidnc{base}@::@\exposidnc{num}@{}, typename @\exposidnc{base}@::@\exposidnc{den}@{});
};

template<@\exposconceptnc{DerivedQuantitySpecExpr}@... Expr>
template<typename... Expr>
struct @\libglobal{derived_quantity_spec}@ final : @\exposidnc{derived-quantity-spec-impl}@<Expr...> {};

}
Expand All @@ -1295,8 +1262,7 @@
\begin{codeblock}
namespace mp_units {

inline constexpr struct @\libglobal{dimensionless}@ final : quantity_spec<derived_quantity_spec<>> {
} @\libglobal{dimensionless}@;
struct @\libglobal{dimensionless}@ final : quantity_spec<derived_quantity_spec<>> {};

}
\end{codeblock}
Expand All @@ -1307,11 +1273,8 @@
\begin{codeblock}
namespace mp_units {

template<typename T>
concept @\defexposconceptnc{QuantitySpecWithNoSpecifiers}@ = @\exposconceptnc{NamedQuantitySpec}@<T> || @\exposconceptnc{DerivedQuantitySpec}@<T>;

template<typename Q>
requires @\exposconceptnc{QuantitySpecWithNoSpecifiers}@<Q> && @\exposconceptnc{SameQuantitySpec}@<@\exposidnc{get-kind-tree-root}@(Q{}), Q{}>
requires(!@\exposconceptnc{QuantityKindSpec}@<Q>) && @\exposconceptnc{SameQuantitySpec}@<@\exposidnc{get-kind-tree-root}@(Q{}), Q{}>
struct @\libglobal{kind_of_}@ final : Q::@\exposidnc{base-type}@ {
using @\exposidnc{base-type}@ = kind_of_;
static constexpr auto @\exposidnc{quantity-spec}@ = Q{};
Expand Down Expand Up @@ -1576,12 +1539,6 @@
template<typename T>
concept @\deflibconcept{MagConstant}@ = @\exposidnc{tag-type}@<T> && @\exposidnc{is-convertible-to-base-subobject-of}@(^T, ^mag_constant);

template<typename T>
concept @\defexposconceptnc{PowerVBase}@ = (^T == ^int) || ^T == ^std::intmax_t || @\libconcept{MagConstant}@<T>;

template<typename T>
concept @\defexposconceptnc{MagnitudeSpecExpr}@ = @\exposconceptnc{PowerVBase}@<T> || @\unspecnc@;

template<typename T>
concept @\deflibconcept{Magnitude}@ = @\exposidnc{is-specialization-of}@(^T, ^magnitude);

Expand Down Expand Up @@ -1611,19 +1568,22 @@
\begin{codeblock}
namespace mp_units {

template<@\exposconceptnc{MagnitudeSpecExpr}@ auto... Ms>
template<auto... Ms>
struct @\libglobal{magnitude}@ {
friend consteval @\libconcept{Magnitude}@ auto operator*(magnitude m1, @\libconcept{Magnitude}@ auto m2);
friend consteval @\libconcept{Magnitude}@ auto operator*(magnitude lhs, @\libconcept{Magnitude}@ auto rhs);

friend consteval auto operator/(magnitude l, @\libconcept{Magnitude}@ auto r) { return l * @\exposidnc{pow}@<-1>(r); }
friend consteval auto operator/(magnitude lhs, @\libconcept{Magnitude}@ auto rhs)
{
return lhs * @\exposidnc{pow}@<-1>(rhs);
}

template<int Num, int Den = 1>
friend consteval auto @\exposidnc{pow}@(magnitude);

template<@\libconcept{Magnitude}@ M2>
friend consteval bool operator==(magnitude, M2)
template<@\libconcept{Magnitude}@ Rhs>
friend consteval bool operator==(magnitude, Rhs)
{
return ^magnitude == ^M2;
return ^magnitude == ^Rhs;
}

friend consteval bool @\exposidnc{is-positive-integral-power}@(magnitude);
Expand All @@ -1637,7 +1597,7 @@
represents the product of its template arguments.

\begin{itemdecl}
friend consteval @\libconcept{Magnitude}@ auto operator*(magnitude m1, @\libconcept{Magnitude}@ auto m2);
friend consteval @\libconcept{Magnitude}@ auto operator*(magnitude lhs, @\libconcept{Magnitude}@ auto rhs);
\end{itemdecl}

\begin{itemdescr}
Expand All @@ -1647,7 +1607,7 @@
\item
If the type of a parameter is \tcode{magnitude<>}, returns the other parameter.
\item
Otherwise, returns an unspecified model of \libconcept{Magnitude} equal to $\tcode{m1} \times \tcode{m2}$.
Otherwise, returns an unspecified model of \libconcept{Magnitude} equal to $\tcode{lhs} \times \tcode{rhs}$.
\end{itemize}
\end{itemdescr}

Expand Down Expand Up @@ -1744,20 +1704,6 @@
template<typename T>
concept @\deflibconcept{PrefixableUnit}@ = @\libconcept{Unit}@<T> && @\exposidnc{is-convertible-to-base-subobject-of}@(^T, ^named_unit);

template<typename T>
constexpr bool @\exposidnc{is-power-of-unit}@ = requires {
requires @\exposidnc{is-convertible-to-base-subobject-of}@(^T, ^power) && @\libconcept{Unit}@<typename T::factor>;
};

template<typename T>
constexpr bool @\exposidnc{is-per-of-units}@ = false;

template<typename... Ts>
constexpr bool @\exposidnc{is-per-of-units}@<per<Ts...>> = (... && (@\libconcept{Unit}@<Ts> || @\exposidnc{is-power-of-unit}@<Ts>));

template<typename T>
concept @\defexposconceptnc{DerivedUnitExpr}@ = @\libconcept{Unit}@<T> || @\exposidnc{is-power-of-unit}@<T> || @\exposidnc{is-per-of-units}@<T>;

template<typename U, auto... Vs>
consteval bool @\exposidnc{has-associated-quantity}@(power<U, Vs...>)
{
Expand Down Expand Up @@ -2052,15 +1998,15 @@
\pnum
\begin{example}
\begin{codeblock}
// The first signature defines a base unit restricted to a kind of quantity.
// 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 restricts the unit to a kind of quantity.
// 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}$
Expand Down Expand Up @@ -2144,11 +2090,14 @@
\begin{codeblock}
namespace mp_units {

template<@\exposconceptnc{DerivedUnitExpr}@... Expr>
struct @\libglobal{derived_unit}@ : @\exposidnc{unit-interface}@, @\exposidnc{expr-fractions}@<struct one, Expr...> {
using @\exposidnc{base-type}@ = derived_unit; // \expos
template<typename... Expr>
struct @\exposid{derived-unit-impl}@ : @\exposidnc{unit-interface}@, @\exposidnc{expr-fractions}@<struct one, Expr...> {
using @\exposidnc{base-type}@ = @\exposid{derived-unit-impl}@; // \expos
};

template<typename... Expr>
struct @\libglobal{derived_unit}@ final : @\exposid{derived-unit-impl}@<Expr...> {};

}
\end{codeblock}

Expand All @@ -2166,7 +2115,7 @@
\begin{codeblock}
namespace mp_units {

inline constexpr struct @\libglobal{one}@ final : derived_unit<> {} @\libglobal{one}@;
struct @\libglobal{one}@ final : @\exposid{derived-unit-impl}@<> {};

}
\end{codeblock}
Expand Down