-
Notifications
You must be signed in to change notification settings - Fork 92
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 most of mp_units.core
#628
Conversation
This is great! Thanks! Regarding magnitudes, please note that they are meant to be implementation-defined. Only a few user-facing API things are public (construction helpers (mag, mag_ratio, and mag_power), concept, operators, magnitude<...> where ... is implementation-defined). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is huge!!! Lots of great work! Thank you!!!
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
\label{term.quantity.type} | ||
A \defnadj{quantity}{type} | ||
is a type \tcode{\placeholder{Q}} | ||
that is a specialization of \tcode{quantity} or \tcode{quantity_point}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some users that derive from quantity already. We support this in mp-units with derived_from. Should we remove this support?
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove this support?
I've always been against it.
Do you have the related issue/PR numbers?
I hope to convince you to do that with my TBD review here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is controversial for me as well. In C++ we typically discourage people from inheriting from std
types. It would be great if we could find a better solution here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The most glaring issue is that for a parameter constrained with
std::derived_from<quantity>
or std::derived_from<quantity_point>
,
the implementation doesn't convert to the quantity
base subobject.
For example, in operator+
:
template<std::derived_from<quantity> Q, auto R2, typename Rep2>
requires detail::CommonlyInvocableQuantities<std::plus<>, quantity, quantity<R2, Rep2>>
[[nodiscard]] friend constexpr Quantity auto operator+(const Q& lhs, const quantity<R2, Rep2>& rhs)
{
using ret = detail::common_quantity_for<std::plus<>, quantity, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
We need this conversion from Q
, type of lhs
, to ret
,
to be the same as ret(static_cast<const quantity&>(lhs))
.
The implementation doesn't do that (like as-variant
),
so we need wording to require those parameter types
to not hide members
and prevent conversions like the above to have a different meaning.
Perhaps by requiring Q
to behave as-if the base template in the specified wording
(e.g., by borrowing https://eel.is/c++draft/namespace.std#2.2).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not oppose removing the support for deriving from a quantity
.
05ab0a8
to
8bf5db5
Compare
Could you please not squash or rebase the branch? It is impossible to track what changes between commits this way. I need to start reviewing all 2500 lines from scratch as I do not know what has changed. Maybe provide something for merge and open another PR with additional changes? |
This comment was marked as outdated.
This comment was marked as outdated.
I try to review in LatTeX as it is easier to provide comments that way, and I also need to learn the syntax. |
\label{term.quantity.type} | ||
A \defnadj{quantity}{type} | ||
is a type \tcode{\placeholder{Q}} | ||
that is a specialization of \tcode{quantity} or \tcode{quantity_point}. |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if it looks right, it still might be broken. This is why I asked to have all the changed code in the repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huge work @JohelEGP! Thank you so much for doing this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
\item | ||
If the result of an operation on \tcode{std::intmax_t} values is outside its range, | ||
the behavior is | ||
\impldef{behavior of \tcode{magnitude} operations that do not fit in a \tcode{std::intmax_t}}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an implementation, how would mp-units define this behavior?
Here's my take on it.
- There are terms for powers of each prime number that represents the magnitude.
[ Note:
It doesn't matter that above reads "[t]here is a single term for eachbase-type
".
mag<INTMAX_MAX> * mag<INTMAX_MAX>
is implementation-defined.
Butmag<INTMAX_MAX>
having more than one term withbase-type
=std::intmax_t
is unobservable.
-- end note ]. mag_power<2, INTMAX_MAX> * mag_power<2, 1>
naturally fails
(althoughmag_power<2, INTMAX_MAX> * mag_power<3, INTMAX_MAX>
doesn't).- Big bases just run into the limits of
constexpr
evaluation
(although there's work going around to push this limit).
This comment was marked as resolved.
This comment was marked as resolved.
Sure, I am not sure if that worked in C++20 already, though. So, as long as doing it for API reference is fine, it might break the mp-units code. |
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it OK to use (Den != 0)
instead of detail::non_zero<Den>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! Someone added those math concepts but I also consider them often more an issue than help. If you are OK with that, I can remove them from the code and replace with proper expressions.
template<std::intmax_t Num, std::intmax_t Den = 1, @\libconcept{Dimension}@ D> | ||
requires(Den != 0) | ||
consteval @\libconcept{Dimension}@ auto pow(D d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kind of ratio in template parameters only require that Den != 0
.
However, ratio{Num, Den}
would fail when Abs
or Den
is INTMAX_MAX
due to abs
.
Is that a problem in any of these interfaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. I did not think about it so far. We may need dedicated Issues to track things like that.
Actually, it is even better (or worse). It turns out that |
quantity_point(quantity_point<std::remove_reference_t<Q>::reference, PO2{}, | ||
typename std::remove_reference_t<Q>::rep>{ | ||
std::forward<FwdQ>(q), PO2{}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these std::remove_reference_t<Q>
for Clang diagnostics?
Q
is defaulted to std::remove_cvref_t<FwdQ>
.
quantity_point(quantity_point<std::remove_reference_t<Q>::reference, PO2{}, | ||
typename std::remove_reference_t<Q>::rep>{ | ||
std::forward<FwdQ>(q), PO2{}}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm...
This constructs a quantity point with a different point origin
and delegates to the converting constructor,
which just extracts the quantity type member.
There's no need to go out of our way to construct the quantity point.
Let's just initialize the quantity type member directly with q
.
The expression in the \fakegrammarterm{requires-clause} is equivalent to: | ||
\begin{codeblock} | ||
(quantity_point_like_traits<QP>::point_origin == point_origin) && | ||
std::@\stdconcept{convertible_to}@<quantity<quantity_point_like_traits<QP>::reference, | ||
typename quantity_point_like_traits<QP>::rep>, | ||
quantity_type> | ||
\end{codeblock} | ||
The expression inside \tcode{explicit} is equivalent to: | ||
\begin{codeblock} | ||
quantity_point_like_traits<QP>::explicit_import || | ||
!std::@\stdconcept{convertible_to}@<quantity<quantity_point_like_traits<QP>::reference, | ||
typename quantity_point_like_traits<QP>::rep>, | ||
quantity_type> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constraint already includes convertibility to quantity_type
.
Its negation in the explicit-specifier will never be exercised.
Do you think the same applies to the equivalent constructor of quantity
?
Construction is done with sudo-cast
, so it isn't as evident.
But I suppose that implies convertibility.
Also, the same applies to the conversion operators
from quantity
to some QuantityLike
and
from quantity_point
to some QuantityPointLike
.
Their deduction guides already do it right.
\remarks | ||
The expression in the \fakegrammarterm{requires-clause} is equivalent to: | ||
\begin{codeblock} | ||
requires { qp.@\exposid{quantity-from-origin}@ @\atsign@ q; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In code, this is:
template<detail::Mutable<quantity_point> QP, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity_type> &&
requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
friend constexpr decltype(auto) operator+=(QP&& qp, const quantity<R2, Rep2>& q)
{
qp.quantity_from_origin_is_an_implementation_detail_ += q;
requires(quantity_type q) { quantity_from_origin_is_an_implementation_detail_ += q; }
should have been
requires(quantity<R2, Rep2> q) { quantity_from_origin_is_an_implementation_detail_ += q; }
I suggest just using a trailing requires-clause that uses the actual expression.
That would also make the detail::QuantityConvertibleTo
redundant.
Same for operator-=
.
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()}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should QP.quantity_from_zero()
actually be QP.quantity_from(QP.absolute_point_origin)
?
(Q::unit == ::mp_units::one) && @\placeholder{C}@<Rep, Value> | ||
(Q::unit == mp_units::one) && @\placeholder{C}@<Rep, Value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a good reason for this change? Should I also update the sources? I used ::
to ensure that we will not have mp_units::mp_units
by accident 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a good reason for this change? Should I also update the sources?
I thought that's how the C++ Standard library did it.
Now I searched for ::std::
, and found that this is also used in 2 places:
d.operator ::std::basic_string_view
inbasic_string_view::basic_string_view
.- In [locale.facet], a requirement on an
id
member.
Besides CPO(-like)s, move
, forward
, compatibility subclauses, and examples,
just std::
is used for
- [format]'s types' use of
std::locale
(since they have alocale
member). prm
'susing X = std::X
.- container(-like)'s
using reverse_iterator = std::reverse_iterator
, span
'susing const_iterator = std::const_iterator
,span
's use ofstd::data
(since it has adata
member),- view's use of
std::min
(sincestd::ranges
has amin
), - view's use of
std::get
(sincestd::ranges
has aget
), - [alg.reverse]'s use of
std::iter_swap
(along withranges::iter_swap
), linalg
types' use ofstd::extents
(since they have anextents
member),- I/O types' use of
std::span
(since they have aspan
member), path
'sstd::Xstring Xstring()
members, and- [future.state]'s use of
std::async
(for no apparent reason), - [future.async]'s use of
std::bad_alloc
(for no apparent reason),
std::chrono::zoned_traits
, which has a locate_zone
member, uses
std::chrono::locate_zone
instead of
::std::chrono::locate_zone
or
chrono::locate_zone
.
So I might prepend ::
to all occurrences of mp_units::
.
I don't know if it'd be worth it, considering that these names might not live in ::std
.
I used
::
to ensure that we will not havemp_units::mp_units
by accident 😉
How is that possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The probability is low, but there is always a chance to have incorrect curly braces in headers or a user that will do some strange thing. Anyway, I am fine with mp_units::
as well. I just wanted to check if there is a bigger reason that I am not aware of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's just bad practice.
Everyone should be following [using.headers]p3 unless otherwise documented for the header.
I'm making this change right now.
You don't follow it in the specializations for std::common_type
of quantity
.
mp_units.core
mp_units.core
There are some things I still want to do, but you can merge this for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!!!
This is still a WIP:
TBDs and still missing:
Representation
concepts.sudo_cast
.system_reference
math.h
random.h