-
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 mp_units.core
#628
base: master
Are you sure you want to change the base?
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.
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
I try to review in LatTeX as it is easier to provide comments that way, and I also need to learn the syntax. |
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
Co-authored-by: Mateusz Pusz <[email protected]>
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.
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.
has_associated_quantity
and all_are_kinds
share the navigation algorithm.
They only differ in the returned expression when U::_quantity_spec_
is valid.
The former returns true
and the latter QuantityKindSpec<MP_UNITS_NONCONST_TYPE(U::_quantity_spec_)>
.
The former also returns false
when nothing works, whereas the latter returns nothing (I suppose it's guarded by the former).
You can factor out the navigation algorithm parameterized on the predicate.
Then the former simply becomes navigation_algorithm(always_true_unary_predicate{})
and the latter navigation_algorithm(nonconst_type_is_model_of_quantity_kind_spec{})
.
Actually, it is even better (or worse). It turns out that |
template<typename FromRep, typename ToRep, auto FromUnit = one, auto ToUnit = one> | ||
concept @\defexposconceptnc{ValuePreservingTo}@ = | ||
requires(FromRep&& from, ToRep to) { | ||
{ to = std::forward<FromRep>(from) } -> std::@\stdconcept{same_as}@<ToRep&>; | ||
} && |
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.
Why not std::assignable_from<ToRep&, FromRep>
?
\begin{itemdescr} | ||
\pnum | ||
\effects | ||
Equivalent to \tcode{\exposidnc{sudo-cast}<quantity>(q)}\iref{qty.non.mem.conv}. |
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 actually the mem-initializer-list
numerical_value_is_an_implementation_detail_( detail::sudo_cast<quantity>(q).numerical_value_is_an_implementation_detail_)
This makes a quantity
temporary, to just jank-out its numerical value.
There would be no such temporary if instead the mem-initializer-list was
quantity(detail::sudo_cast<quantity>(q))
.
\pnum | ||
\expects | ||
If \tcode{@} is \tcode{\%=} or \tcode{/=}, then | ||
\begin{codeblock} | ||
@\placeholdernc{TO-NUMERICAL-VALUE}@(rhs) != representation_values<RhsRep>::zero() | ||
\end{codeblock} | ||
is \tcode{true}. |
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 operator%
:
template<detail::Mutable<quantity> Q, auto R2, typename Rep2>
requires detail::QuantityConvertibleTo<quantity<R2, Rep2>, quantity> && (!treat_as_floating_point<rep>) &&
requires(rep a, Rep2 b) {
{ a %= b } -> std::same_as<rep&>;
}
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity<R2, Rep2>& rhs)
{
MP_UNITS_EXPECTS_DEBUG(rhs != zero());
This compares rhs
to lhs.zero()
.
There's no requirement that rep
and Rep2
be equality comparable.
I suggest instead: MP_UNITS_EXPECTS_DEBUG(is_neq_zero(rhs));
.
Similarly for other
Or perhaps just prepend rhs.
to zero()
, as done elsewhere.
This one is also missing the contract:
template<typename Value, std::derived_from<quantity> Q>
requires(!Quantity<Value>) &&
(!Reference<Value>) && detail::InvokeResultOf<quantity_spec, std::divides<>, const Value&, Rep>
[[nodiscard]] friend constexpr Quantity auto operator/(const Value& val, const Q& q)
{
return ::mp_units::quantity{val / q.numerical_value_ref_in(unit), ::mp_units::one / R};
}
The expression in the \fakegrammarterm{requires-clause} is equivalent to: | ||
\begin{codeblock} | ||
(@\placeholder{C}@) && @\exposconceptnc{ValuePreservingTo}@<RhsRep, Rep> && requires { | ||
{ lhs.@\exposid{numerical-value}@ @\atsign@ @\placeholdernc{TO-NUMERICAL-VALUE}@(rhs) } -> std::@\stdconcept{same_as}@<rep&>; | ||
} |
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.
You can remove some of these requirements thanks to the new representation concepts.
For example, +
's
requires(rep a, Rep2 b) {
{ a += b } -> std::same_as<rep&>;
}
When do you plan to do that?
Otherwise, those parameters also need to be made const
for the implicit expression variations.
This is still a WIP:
This is also blocked on
a number of minor points which I'll review later.
There are some TBDs, mainly for algorithms which need wording.
These are:
Representation
concepts.sudo_cast
.Work left (besides the TBDs above):
system_reference
math.h
random.h