Date: Mon, 30 Mar 2026 20:33:20 +0800
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
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
Received on 2026-03-30 12:33:36
