C++ Logo

std-proposals

Advanced search

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

From: Hewill Kang <hewillk_at_[hidden]>
Date: Fri, 3 Apr 2026 02:14:24 +0800
Hi Mark,

Regarding "Deduction of element_type and reference," the intent is
> that `element_type` is a cv-qualified `value_type`. This is why
> mdspan defines `value_type` as `remove_cv_t<element_type>`. Note that
> [mdspan.mdspan.overview] 2.3 Mandates that the first template argument
> of mdspan matches the accessor's element_type.


I found this to be a very interesting topic.
Currently, I define `element_type` as
`remove_reference_t<iter_reference_t<I>>`; this is not a problem for
reference types that are truly reference, but does indeed have some issue
with proxy iterators:

```
  auto r1 = vector{true, false, true, false};
  auto ms1 = mdspan(r1.begin(), _2x2, iterator_accessor(r1.begin()));

  vector posX = {0.0, 1.0, 2.0, 3.0};
  vector posY = {0.0, 0.5, 1.0, 1.5};
  vector mask = {1, 0, 1, 0};
  auto r2 = views::zip(posX, posY, mask);
  auto ms2 = mdspan(r1.begin(), _2x2, iterator_accessor(r1.begin()));
```

The above seems to work well, but `mdspan` is deduced to be
`mdspan<vector<bool>::reference, ...>` or `mdspan<tuple<double&, double&
int&>`.
This is not satisfactory to me, and we also can not just use
`iter_value_t` as the `element_type` because it is never `const`-qualified.
I really like your suggestion to derive `const`-ness from
`indirectly_writable<Iterator, value_type>`, but I'm not sure if it's
entirely reliable.

Another interesting issue is that it seems we can't use
`iter_difference_t` as the `offset` parameter according to the
[mdspan.accessor]
<https://eel.is/c++draft/mdspan.accessor>requirements, `access` should take
`size_t`. So I perform `static_cast` internally and added a *Precondition*
to ensure the mapping is well-defined, as such:

```
constexpr reference access(data_handle_type p, size_t i) const;
-1- Preconditions: i is representable as a value of type
iter_difference_t<I>.
-2- Effects: Equivalent to: return p[static_cast<iter_difference_t<I>>(i)];
```

Hewill



Mark Hoemmen <mark.hoemmen_at_[hidden]> 於 2026年4月3日週五 上午1:24寫道:

> On Wed, Apr 1, 2026 at 7:48 PM Hewill Kang <hewillk_at_[hidden]> wrote:
> >
> > Hi Mark,
> >
> > Thank you for your continued detailed clarification and explanation for
> mdspan; I have benefited greatly from it.
>
> Thank you for taking the time to revisit this! It's much improved.
>
> Regarding "Deduction of element_type and reference," the intent is
> that `element_type` is a cv-qualified `value_type`. This is why
> mdspan defines `value_type` as `remove_cv_t<element_type>`. Note that
> [mdspan.mdspan.overview] 2.3 Mandates that the first template argument
> of mdspan matches the accessor's element_type.
>
> This means that your current design won't work correctly with proxy
> reference types. Users would have to specify the proxy reference type
> (e.g., std::vector<bool>::reference) as the first template argument of
> mdspan, instead of the cv-qualified value type (e.g., bool).
>
> mdspan was designed to work with proxy reference types. Users of
> mdspan don't need to spell out the reference type, because that would
> unnecessarily couple mdspan to the accessor type. The accessor type
> already has the `reference` type alias; users shouldn't have to spell
> it out again.
>
> I suspect what you want is first to get the value_type with
> iter_value_t, and then deduce const-ness from
> indirectly_writable<Iterator, value_type>.
>
> >> Have you considered adding converting constructors so that users can
> >> go from an iterator-to-nonconst to an iterator-to-const?
> >
> > The proposed wording has the following converting constructors:
> >
> > template<convertible_to<I> I2>
> > constexpr iterator_accessor(iterator_accessor<I2>) noexcept {}
> >
> > I think it's enough to cover it?
>
> The analog of this is enough for `default_accessor`, but that only has
> to deal with pointers. If I is constructible from I2, but I2 is not
> convertible to I, then the same should be true of the accessor. As a
> result, mdspan conversion would work in the same way as accessor
> conversion. This is the design intent of mdspan.
>
> Thanks!
> mfh
>
> >
> >> My only concern is that the
> >> non-wording sections of the paper say some things about mdspan's
> >> design that I don't think are quite accurate.
> >
> >
> > Thank you for pointing it out.
> > In fact, a large part of the discussion section was written with AI
> assistance. :)
> > I neglected to proofread it, resulting in overly aggressive words, given
> that it might not fully understand mdspan. I have revised the discussion.
> >
> > Additionally, note that I used __cpp_lib_iterator_accessor because the
> standard already has a similar __cpp_lib_aligned_accessor.
> >
> > Here is the revised one: https://isocpp.org/files/papers/P4173R0.html
> >
> > Hewill
> >
> > Mark Hoemmen <mark.hoemmen_at_[hidden]> 於 2026年4月2日週四 上午1:51寫道:
> >>
> >> Hewill Kang wrote:
> >> > Hi, I wrote a paper on this:
> https://isocpp.org/files/papers/P4173R0.html
> >>
> >> Hi and thanks for your interest in mdspan!
> >>
> >> I do think a "random access iterator accessor" would be useful. I've
> >> actually implemented this for some of my colleagues, who asked for a
> >> proposal like this.
> >>
> >> Have you considered adding converting constructors so that users can
> >> go from an iterator-to-nonconst to an iterator-to-const?
> >>
> >> I generally approve of this proposal. My only concern is that the
> >> non-wording sections of the paper say some things about mdspan's
> >> design that I don't think are quite accurate.
> >>
> >> > Standard mdspan accessors are primarily limited to raw pointers,
> hindering direct integration with non-contiguous C++ Ranges and proxy-based
> containers.
> >>
> >> It's true that default_accessor and aligned_accessor work on pointers.
> >> However, mdspan's design actively encourages users to write custom
> >> accessors. Just like the Standard can't foresee all possible
> >> containers, the Standard can't foresee all possible custom accessors
> >> that users might like to write for their custom hardware. That's why
> >> it's a customization point. There are a few other places in the paper
> >> that say things like this. Would you consider correcting them?
> >>
> >> > ... hindering direct integration with non-contiguous C++ Ranges
> >>
> >> mdspan integrates perfectly well with ranges.
> >>
> >> template<class ElementType, class Extents, class Layout, class Accessor>
> >> constexpr auto to_index_range(extents<IndexType, Exts...> e) {
> >> auto [...index_views] =
> >> [] <size_t... Inds> (const auto& exts, index_sequence<Inds>) {
> >> return tuple{views::indices(exts.extent(Inds))...};
> >> } (e, make_index_sequence<sizeof...(Exts)>());
> >> return views::cartesian_product(index_views...);
> >> }
> >>
> >> template<class ElementType, class Extents, class Layout, class Accessor>
> >> constexpr auto to_range(mdspan<ElementType, Extents, Layout, Accessor>
> x) {
> >> if constexpr (std::is_same_v<Layout, layout_right>) {
> >> return views::indices(x.required_span_size()) |
> >> views::transform(
> >> [acc = x.accessor(), handle = x.data_handle()] (size_t k) {
> >> return acc.access(handle, k);
> >> });
> >> } else {
> >> return to_index_range(x.extents()) | views::transform([=] (auto t) {
> >> auto [...indices] = t;
> >> return x[indices...];
> >> });
> >> }
> >> }
> >>
> >> There, now you have `to_range(x)`. I haven't proposed this for the
> >> Standard for two reasons.
> >>
> >> 1. What would it mean to `std::copy` from a 2 x 3 x 5 x 7 mdspan to a
> >> 6 x 15 x 7 mdspan?
> >>
> >> 2. Compilers are unlikely to be able to optimize a "multidimensional
> iterator."
> >>
> >> 3. It might be a surprising pessimization that `layout_left` mdspan
> >> would still be iterated in row-major order.
> >>
> >> It's important to understand WHY mdspan uses accessors instead of
> >> iterators. The design intent is that accessors are easy to write for
> >> hardware experts who are not C++ experts, because it's much more
> >> likely that users will want to write a custom accessor (to support the
> >> huge variety of custom memory access patterns and network hardware
> >> that exists in practice) than it is that they will want to write a
> >> custom layout mapping. Iterators are hard to write correctly -- hard
> >> enough that proposals like Zach Laine's P2727 exist to make this
> >> easier.
> >>
> >> All that being said, I don't object to the proposal! I just want to
> >> help clear up the design intent of mdspan.
> >>
> >> Thanks!
> >> mfh
>

Received on 2026-04-02 18:14:38