On Mon, Apr 1, 2024 at 10:38 AM Hewill Kang via Std-Proposals <std-proposals@lists.isocpp.org> wrote:

Hi all,

I'm wondering if we should also support slice(1) or slice(1, 10, 3), i.e.:

views::slice(1)        -> views::drop(1)
views::slice(1, 10)    -> views::drop(1) | views::take(9)
views::slice(1, 10, 3) -> views::drop(1) | views::take(9) | views::strde(3)

Although this may be confused with std::strided_slice ([mdspan.submdspan.strided.slice]) (or std::slice [class.slice.overview]), because the second argument of the latter is not the end but the extent, so views::slice(1, 10, 3) will get 1, 4, 7, while strided_slice(1, 10, 3) will get 1, 4, 7, 10.

What do you think? Would it make sense to provide two more variants for views::slice?


If you do, they should certainly have "extent" not "end" semantics. This also matches `substr`. This also matches the expansion you gave: `views::slice(a, b)` should expand to `views::drop(a) | views::take(b)`, not `views::drop(a) | views::take(b - a)`.

Although if that's all it is... then why have this in the STL at all? Is there going to be some performance benefit to writing
    rg | views::slice(1, 10, 3)
versus just writing
    rg | views::slice(1, 10) | views::stride(3)
which is definitely more explicit about what the third parameter is doing? In fact, is there any benefit to writing
    rg | views::slice(1, 10)
instead of just
    rg | views::drop(1) | views::take(10)
?

Bonus: Note that you can get "end" semantics by rewriting `views::slice(start=a, end=b)` into
    rg | views::take(b) | views::drop(a)
If I have the choice between writing the line above, or writing
    rg | views::drop(a) | views::take(b - a)
, is there a performance cost to one or the other? Naïvely it seems like the latter might be faster, but the answer could also be "it doesn't matter, they both compile to the same thing."

–Arthur