libstdc++: questions about P3663
Mark Hoemmen
mark.hoemmen@gmail.com
Sun Nov 2 20:41:31 GMT 2025
On Sun, Nov 2, 2025 at 6:51 AM Luc Grosheintz <luc.grosheintz@gmail.com> wrote:
>
> Hi Mark,
>
> thank you for your detailed response!
>
> On 10/31/25 7:46 PM, Mark Hoemmen wrote:
> >
> >> 1. What are the requirements for user provided integer-like objects?
> >
> > The reference implementation copies slices all over the place. I
> > think it's fair to assume that slice specifiers are copyable and
> > movable.
>
> The context is that for libstdc++ we've been careful to not require
> move or copy ctors for mapping::operator(), or in `extents`. This
> means we've been very careful to immediately convert them to
> index_type, via `static_cast<index_type>(std::move(i))`.
>
> Therefore, I wanted to double check the following (8.15.2):
>
> auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...);
>
> this copies `raw_slices`, while later in during canonicalization
> `std::move` is used very carefully. Allowing strange types like:
>
> struct RValueInt {
> operator int()&& {
> return 42;
> }
> };
>
> i.e. object that can convert to `int` only via an r-value reference.
>
> As for Tomasz point: "it's not explicit and anything for which
> submdspan_canonicalize_slices is well-formed is valid". That's
> true and I'm not suggesting to change the code. However, I thought
> it would make sense to understand which ctors are intended/implied.
> (It helps checking for typos.)
>
> >
> >> 2. What happens if the standard adds a new kind of *canonical* selection?
> >
> > The idea is that it's never a breaking change to go from "ill-formed"
> > (status quo after adopting P3663) to "well-formed and well-defined"
> > (after hypothetical addition of a new kind of selection).
>
> Thank you, that's also how I understood it. Thanks for confirming.
> >
> >> 3. Is there a way to `static_assert` the mandate ...?
> >
> > If you're referring to [mdspan.sub.helpers] 6, in the specification of
> > _`canonical-slice`_, then the way that you implement the Mandates is
> > by means of the code in [mdspan.sub.helpers] 7. That code will be
> > ill-formed otherwise.
>
> No, I mean the one for non-canonical slice types. Tomasz confirmed
> it's not static assertable. I just wanted to make sure that it's
> really not possible and not intended to be statically assertable.
> (There's always the risk that of: not possible "by me".)
>
> >
> > We do it that way because you can't write an expression (to use in a
> > `static_assert` or the definition of a concept) to express that a
> > structured binding declaration is well-formed.
>
> Offtopic: Is there's a good intuitive reason why it's impossible
> to check if a structured binding is well-formed?
>
> >
> >> 4. The notion of "unit-stride slice" [...]
> >
> > I debated that with Tomasz (CC'd) and lost ; - ) [...]
>
> In his reply he makes the point again. I don't feel to strongly
> either way. Personally, I think it would be nice to only define
> the idea: "canonical unit-stride slice". The advantage is that
> if I read that term I correctly guess the definition. Whereas
> if I read "unit-stride slice" my brain tries to be "clever" and
> find the other slices with unit-stride; and hence as a result
> guesses incorrectly how it's defined.
>
> >
> >> 5. [...] the question is what is the "lower bound"?
> >
> > [mdspan.sub.overview] 8.2 defines the lower bound for this case as the
> > offset `n`. The upper bound is also `n` for this case.
>
> I'm sorry I can't find it:
>
> * In N5014 the first time the string "lower" appears after
> [mdspan.sub.overview] is lower_bound (think bisection).
>
> * In P3663, the term is string "lower" appears exactly
> twice, neither defines it. Both are: "lower bound of
> the submdspan slice range"; and the slice range is
> defined as an interval.
>
> The term is perfectly clear if the interval is non-empty.
> However for empty intervals, I wanted to point out that
> one possible way of reading P3663 is that's "lower bound"
> isn't obviously n if the interval is `[n,n)`.
>
> It's really just double checking some pedantry. If the
> two of you think it's perfectly clear, then there's nothing
> left to discuss :)
I think it's clear : - ) . I appreciate you checking the wording, though!
mfh
> >> Is `pair{n, n}` a valid slice for dimension `i`?
> >
> > Yes, it is. [...]
> >
> >> `pair{n+1, n+1}` would be valid, but not `pair{cw<n+1>, cw<n+1>}`
> >
> > That's a good point. `pair{cw<n+1>, cw<n+1>}` would have a
> > canonicalization that is invalid per [mdspan.sub.overview] 9.1.1.
> >
> > We should file an LWG issue about this. Would you like to do it?
>
> You mean a LWG to clarify the wording of P3663, such that
> pair{n+1, n+1} is invalid?
>
> I'm happy to help, though personally, I thought that the
> formulation using first_ and last_ along with the condition:
>
> 0 <= first_ <= last_ <= n
>
> was simple and clear. Also made it immediately obvious that
> pair<size_t, size_t>{5, 3} is invalid. (I think it still is
> invalid but the reason is less easy to check, IMO.)
>
> The easiest way seems to repeat the block (8.4.9.1) for
> (8.4.10).
>
> (10.4) - if S is a specialization of strided_slice:
> (10.4.1) + if s.offset <= x
> (10.4.2) + if s.extent <= x
> (10.4.3) + if s.offset + s.extent <= x
>
> (where x is the k-th extent of `e`.) I think (10.4.2) is
> redundant and it feels clumsy because it overlaps with:
>
> (10.2) the k-th interval of e contains the submdspan slice
> range of s for the kth extent of e;
>
> Alternatively, something like:
> (10.4) - if the slice range of s is empty then:
> (10.4.1-3) as above.
>
> >
> >> 6. I'd like to suggest adding "canonical" to "valid submdspan slice":
> > [...]
> > Saying "valid canonical" would incorrectly imply that something can be
> > valid but not canonical.
>
> Understood, and that makes sense. Intuitively, I think of the two
> terms "valid" and "canonical" as orthogonal. Something can be
> canonical, but not valid and the other way around.
>
> Consider, `exts = extents(3, 5)` then both
> auto s1 = pair{1, 3};
> int s2 = 2;
>
> are *intutively* valid (as in they can be passed to `submdspan`),
> non-canonical, slices of the `k-th` extent (k = 0, 1).
> For example the term could be defined as:
>
> `s` is a valid slice of the k-th extent if
> canonical-slice<IndexType>(s) is a valid canonical slice
> of the k-th exent.
>
> Then the precondition for submdspan_mapping is:
>
> For each k, slices...[k] is a valid canonical slice for the k-th
> extent.
>
> Whereas submdspan and submdspan_canonocial_slices can simply write:
>
> For each k, slices...[k] is a valid slice for the k-th extent.
>
> I don't have a strong preference. Therefore, if the argument wasn't
> convincing, I'm happy to not "protest" further.
>
More information about the Libstdc++
mailing list