C++ Logo

std-proposals

Advanced search

Re: [std-proposals] `random_access_iterator_accessor` for `std::mdspan`?

From: Hewill Kang <hewillk_at_[hidden]>
Date: Thu, 2 Apr 2026 00:20:28 +0800
Hi Arthur,

Thanks for your valuable feedback (as always).

The main thing I worry about is that your proposal essentially nerfs any
> optimization potential inside the implementation.


The paper is about accessors; the aim is to provide a simple mechanism to
allow random-access iterators to work well with mdspan.
The random-access operation of the random-access iterator is constant-time,
as far as I know.
Although there may be some room for optimization, I think it is still
acceptable for now because this is not an accessor specialized for
performance, it's for convenience.

The latter would be really annoying IMHO. However, it brings me back to my
> first fear: Is there a *reason* that all accessors are currently
> specified to be trivially copyable?


My understanding is that standard accessors are (always) empty classes.
For this new accessor, its empty classes, the constructor takes an iterator
*only* for CTAD purposes; it does *not* store iterators itself, and I don't
see any situation we need to store iterators.

Why not specify that iterator_accessor<I> is always an *empty* type?


I thought the current wording might have already hinted at it, but it seems
not.
I also prefer this, but just simply copied the wording from
`default_accessor`.

Best,
Hewill

Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> 於 2026年4月1日週三 下午10:49寫道:

> Your four Examples are excellent. I do wish you'd present them in
> Tony-table form, though: IIUC today each of the four examples is ill-formed
> (rejected at compile-time), and after P4173 they'd all be well-formed and
> Do The Right Thing, is that correct?
>
> The main thing I worry about is that your proposal essentially nerfs any
> optimization potential inside the implementation. You write:
> > mdspan essentially treats multi-dimensional access as a layer on top of
> contiguous memory, rather than a generalized abstraction for any indexed
> data source.
> But is it just "*treating*" multi-dimensional access as a layer on top of
> contiguous memory, interface-wise; or does mdspan internally *implement*
> multi-dimensional access as raw-pointer operations, in order to reduce code
> bloat and to reduce pressure on the compiler's optimizer? I fear mdspan
> does the latter.
> So I fear that your proposal is basically asking implementors to implement
> (certain parts of) mdspan twice: one time for contiguous iterators, which
> can be lowered to raw pointers; and a second time (non-existent today, but
> forced by your proposal) for random-access-but-non-contiguous iterators,
> which will be forbidden to use any clever optimizations.
> I'm not necessarily right about that fear; and even if implementors *are*
> forced to implement two codepaths, there's certainly precedent in the STL
> for that.
>
> But basically this indicates that your D4173R0 is conspicuously missing an
> "Implementation experience" section.
>
> Nit: "Lastest" should be "Latest."
> Bikeshed: "__cpp_lib_iterator_accessor" should perhaps be
> "__cpp_lib_mdspan_iterator_accessor" for clarity.
> Pre-existing nit: Your *Mandates* element has the words "is required to
> be"; that should be just "is". Do you feel like submitting an editorial PR
> for the pre-existing misuses of "is required to be" in [mdspan.accessor]?
>
> You write:
> > -3- Each specialization of iterator_accessor is a trivially copyable
> type that models semiregular.
> Is this "trivially copyable" implementable? *If iterator_accessor<I>
> contains an I data member*, it's not. At least this should say
> "iterator_accessor<I> is trivially copyable if I is trivially copyable."
> Or, alternatively, add "*Mandates:* I is trivially copyable."
> The latter would be really annoying IMHO. However, it brings me back to my
> first fear: Is there a *reason* that all accessors are currently
> specified to be trivially copyable? Does that help the implementor
> somewhere later on, that we can copy (a contiguous array of) accessors with
> memcpy without knowing their exact type? If so, then permitting
> `iterator_accessor<I>` to be non-trivially copyable is going to be an
> implementation burden. So again, I want to see an "Implementation
> Experience" section and I want to see it deal with these (imagined/feared)
> optimization issues head-on.
> Alternatively, *if iterator_accessor<I> does not contain an I data
> member,* then why stop at "trivially copyable"? Why not specify that
> iterator_accessor<I> is always an *empty* type? (And then, pre-existing,
> why do none of the other accessors bother to specify that? What data
> members are they imagined to have, then?)
>
> Other than the big fear that this will turn out to be unimplementable for
> some technical reason, IMHO this sounds great. Again, those four Examples
> are very motivating.
>
> HTH,
> Arthur
>
>
> On Wed, Apr 1, 2026 at 10:01 AM Hewill Kang via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> Hi, I wrote a paper on this: https://isocpp.org/files/papers/P4173R0.html
>> Thanks.
>>
>> Hewill Kang <hewillk_at_[hidden]> 於 2026年3月30日週一 下午8:33寫道:
>>
>>> Hi all,
>>>
>>> Currently, although `mdspan` is designed as a general-purpose multiview,
>>> it mostly accepts a pointer and accesses different elements through a
>>> pointer algorithm.
>>> However, I am not satisfied with these *pointer*-based mandates because
>>> I do not think they are much different from a general
>>> `contiguous_iterator`, which can be a common iterator such as
>>> `vector::iterator`.
>>> If we look at the `default_accessor`, we can see the clue:
>>>
>>> ```cpp
>>> template<class ElementType>
>>> struct default_accessor {
>>> using offset_policy = default_accessor;
>>> using element_type = ElementType;
>>> using reference = ElementType&;
>>> using data_handle_type = ElementType*;
>>>
>>> constexpr default_accessor() noexcept = default;
>>> constexpr reference access(data_handle_type p, size_t i) const
>>> noexcept
>>> { return p[i]; }
>>> constexpr data_handle_type offset(data_handle_type p, size_t i)
>>> const noexcept
>>> { return p + i; }
>>> };
>>> ```
>>> Then, upon closer inspection, we discovered that this is *exactly* the
>>> operation supported by C++20 `random_access_iterator`, i.e.,
>>> `operator[]` and `operator+`.
>>> Given this, I think we can introduce a new accessor class that wraps the
>>> `random_access_iterator`, for example:
>>>
>>> ```cpp
>>> template<random_access_iterator I>
>>> struct *iter_accessor* {
>>> using offset_policy = iter_accessor;
>>> using reference = iter_reference_t<I>;
>>> using element_type = remove_reference_t<reference>;
>>> using data_handle_type = I;
>>>
>>> iter_accessor() noexcept = default;
>>> constexpr reference
>>> access(data_handle_type p, std::iter_difference_t<I> i) const
>>> { return p[i]; }
>>> constexpr data_handle_type
>>> offset(data_handle_type p, std::iter_difference_t<I> i) const
>>> { return p + i; }
>>> };
>>> ```
>>>
>>> This fully inherits the natural characteristics of a
>>> `random_access_iterator`, which allows us to very easily make `mdspan`s
>>> with a wide variety of different `random_access_range`s, such as:
>>>
>>> ```
>>> using Layout = std::layout_right::mapping<std::extents<int, 3, 3>>;
>>>
>>> auto r = std::views::iota(0, 9);
>>> auto ms1 = std::mdspan(r.begin(), Layout{}, *iter_accessor*
>>> <decltype(r.begin())>{});
>>> /* 0 1 2
>>> 3 4 5
>>> 6 7 8 */
>>>
>>> auto v = std::vector<bool>{true, false, true, false, true, false,
>>> true, false, true};
>>> auto ms2 = std::mdspan(v.begin(), Layout{}, *iter_accessor*
>>> <decltype(v.begin())>{});
>>> /* true false true
>>> false true false
>>> true false true */
>>>
>>> std::vector<int> v1{1, 2, 3}, v2{4, 5}, v3{};
>>> std::array a{6, 7, 8};
>>> auto s = std::views::single(9);
>>> auto r3 = std::views::concat(v1, v2, v3, a, s);
>>> auto ms3 = std::mdspan(r3.begin(), Layout{}, *iter_accessor*
>>> <decltype(r3.begin())>{});
>>> /* 1 2 3
>>> 4 5 6
>>> 7 8 9 */
>>> ```
>>> Demo: https://godbolt.org/z/xb5vrejba
>>>
>>> I think this is a very useful utility.
>>> Based on C++26, we have a large majority of range adaptors in `<ranges>`
>>> that can support `random_access_range`.
>>> Introducing this `accessor` makes them better integrated with `mdspan`,
>>> which also opens the door for third-party custom range types.
>>>
>>> What do you think? Appreciate any feedback.
>>>
>>> Hewill
>>>
>>>
>>>
>>>
>>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>

Received on 2026-04-01 16:20:42