Date: Sun, 5 Apr 2026 00:27:57 +0800
>
> Currently, the creation of `mdspans` with `iterator_accessor` relies on
> the following CTAD:
> ```
> template<class MappingType, class AccessorType>
> mdspan(const typename AccessorType::data_handle_type&, const
> MappingType&,
> const AccessorType&)
> -> mdspan<typename AccessorType::element_type, typename
> MappingType::extents_type,
> typename MappingType::layout_type, AccessorType>;
> ```
> We must spell with
> ```
> auto _3x3 = std::layout_right::mapping(std::extents(3, 3));
> auto ms = std::mdspan(r.begin(), _3x3, std::iterator_accessor(r.begin()));
Typing `r.begin()` twice is unsatisfactory to me.
I think we can provide an additional constructor for `mdspan` to indicate
that it is constructed from ranges:
```
template<ranges::*random_access_range* Range, class... OIndexTypes>
requires ranges::*borrowed_range*<Range>
constexpr explicit
mdspan(*from_range_t*, *Range*&& r, OIndexTypes... exts) :
ptr_(ranges::begin(r)), ...
```
Along with the following CTAD:
```
template<ranges::random_access_range Range, class... Integrals>
explicit mdspan(from_range_t, Range&&, Integrals...)
-> mdspan<typename
*iterator_accessor<ranges::iterator_t<Range>>::element_type*,
extents<size_t, maybe-static-ext<Integrals>...>,
layout_right,
*iterator_accessor<ranges::iterator_t<Range>>>*;
```
This allows the user to spell it out simply with:
```
vector x_coords = {0, 10, 20};
vector y_coords = {0, 5};
vector z_coords = {15, 10, 5, 20};
auto r = views::cartesian_product(x_coords, y_coords, z_coords);
auto ms1 = mdspan(from_range, r, x_coords.size(), y_coords.size(),
z_coords.size());
std::vector posX = {0.0, 1.0, 2.0, 3.0};
std::vector posY = {0.0, 0.5, 1.0, 1.5};
std::vector mask = {1, 0, 1, 0};
auto ms2 = mdspan(from_range, std::views::zip(posX, posY, mask), 2, 2);
```
I think this clearly shows that the user intends to make mdspans from
ranges rather than a raw pointer.
And there is no spelling of .begin(), and no duplicate spelling, which
looks satisfactory to me.
What do you think?
Hewill
Hewill Kang <hewillk_at_[hidden]> 於 2026年4月4日週六 下午5:22寫道:
> Currently, the creation of `mdspans` with `iterator_accessor` relies on
> the following CTAD:
> ```
> template<class MappingType, class AccessorType>
> mdspan(const typename AccessorType::data_handle_type&, const
> MappingType&,
> const AccessorType&)
> -> mdspan<typename AccessorType::element_type, typename
> MappingType::extents_type,
> typename MappingType::layout_type, AccessorType>;
> ```
>
> We must spell with
> ```
> auto _3x3 = std::layout_right::mapping(std::extents(3, 3));
> auto ms = std::mdspan(r.begin(), _3x3, std::iterator_accessor(r.begin()));
> ```
>
> A subsequent question is, once we have an `iterator_accessor`, should we
> enhance mdspan's CTAD so that:
>
> ```
> auto ms = std::mdspan(r.*begin*(), 3, 3); // call *begin*() instead of
> *data*()
> ```
>
> Works well? For example, enhance `ElementType*` parts in the current CTAD
> for `random_access_iterator`:
> ```
> template<random_access_iterator I, class... Integrals>
> requires ((is_convertible_v<Integrals, size_t> && ...) &&
> sizeof...(Integrals) > 0)
> explicit mdspan(I, Integrals...)
> -> mdspan<typename *iterator_accessor*<I>::*element_type*,
> extents<size_t, maybe-static-ext<Integrals>...>,
> layout_right,
> *iterator_accessor*<I>>;
> ```
> This eliminates the need for spelling of *r.begin()* twice.
> However, it's uncertain whether this *relaxation* for users dealing with
> contiguous_iterator/random_access_iteratorer instead of a raw pointer is
> good.
>
> Hewill Kang <hewillk_at_[hidden]> 於 2026年4月4日週六 上午11:54寫道:
>
>> Thank you, that makes sense.
>> I updated the paper.
>>
>>
>>
>>
>> Mark Hoemmen <mark.hoemmen_at_[hidden]> 於 2026年4月4日週六 上午3:16寫道:
>>
>>> On Fri, Apr 3, 2026 at 11:27 AM Hewill Kang <hewillk_at_[hidden]> wrote:
>>> >>
>>> >> Also, iterator_accessor has to deal with pointers as a special case of
>>> >> iterators, so it should have the same safeguard as default_accessor
>>> and
>>> >> friends against converting a pointer-to-derived to a pointer-to-base.
>>> >
>>> >
>>> > That's reasonable, thank you. I updated the paper.
>>> >
>>> > This is the current final version of the paper:
>>> https://isocpp.org/files/papers/P4173R0.html
>>> > And implementation with libstdc++: https://godbolt.org/z/86MKa3oa5
>>>
>>> Would you consider making those conversion operators to
>>> `default_accessor` explicit?
>>>
>>> I ask because container authors sometimes provide iterators that model
>>> `contiguous_iterator` but do run-time bounds checking. Implicit
>>> conversion from `iterator_accessor` to `default_accessor` would
>>> silently strip away this protection.
>>>
>>> Thanks!
>>> mfh
>>>
>>>
>>> >
>>> > Thanks.
>>> > Hewill
>>> >
>>> > Ell <ell.ell.se_at_[hidden]> 於 2026年4月3日週五 上午2:48寫道:
>>> >>
>>> >> On Thursday, April 2nd, 2026 at 8:24 PM, Mark Hoemmen via
>>> Std-Proposals <std-proposals_at_[hidden]> wrote:
>>> >>
>>> >> > >> 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.
>>> >> >
>>> >>
>>> >> Also, iterator_accessor has to deal with pointers as a special case of
>>> >> iterators, so it should have the same safeguard as default_accessor
>>> and
>>> >> friends against converting a pointer-to-derived to a pointer-to-base.
>>>
>>
> Currently, the creation of `mdspans` with `iterator_accessor` relies on
> the following CTAD:
> ```
> template<class MappingType, class AccessorType>
> mdspan(const typename AccessorType::data_handle_type&, const
> MappingType&,
> const AccessorType&)
> -> mdspan<typename AccessorType::element_type, typename
> MappingType::extents_type,
> typename MappingType::layout_type, AccessorType>;
> ```
> We must spell with
> ```
> auto _3x3 = std::layout_right::mapping(std::extents(3, 3));
> auto ms = std::mdspan(r.begin(), _3x3, std::iterator_accessor(r.begin()));
Typing `r.begin()` twice is unsatisfactory to me.
I think we can provide an additional constructor for `mdspan` to indicate
that it is constructed from ranges:
```
template<ranges::*random_access_range* Range, class... OIndexTypes>
requires ranges::*borrowed_range*<Range>
constexpr explicit
mdspan(*from_range_t*, *Range*&& r, OIndexTypes... exts) :
ptr_(ranges::begin(r)), ...
```
Along with the following CTAD:
```
template<ranges::random_access_range Range, class... Integrals>
explicit mdspan(from_range_t, Range&&, Integrals...)
-> mdspan<typename
*iterator_accessor<ranges::iterator_t<Range>>::element_type*,
extents<size_t, maybe-static-ext<Integrals>...>,
layout_right,
*iterator_accessor<ranges::iterator_t<Range>>>*;
```
This allows the user to spell it out simply with:
```
vector x_coords = {0, 10, 20};
vector y_coords = {0, 5};
vector z_coords = {15, 10, 5, 20};
auto r = views::cartesian_product(x_coords, y_coords, z_coords);
auto ms1 = mdspan(from_range, r, x_coords.size(), y_coords.size(),
z_coords.size());
std::vector posX = {0.0, 1.0, 2.0, 3.0};
std::vector posY = {0.0, 0.5, 1.0, 1.5};
std::vector mask = {1, 0, 1, 0};
auto ms2 = mdspan(from_range, std::views::zip(posX, posY, mask), 2, 2);
```
I think this clearly shows that the user intends to make mdspans from
ranges rather than a raw pointer.
And there is no spelling of .begin(), and no duplicate spelling, which
looks satisfactory to me.
What do you think?
Hewill
Hewill Kang <hewillk_at_[hidden]> 於 2026年4月4日週六 下午5:22寫道:
> Currently, the creation of `mdspans` with `iterator_accessor` relies on
> the following CTAD:
> ```
> template<class MappingType, class AccessorType>
> mdspan(const typename AccessorType::data_handle_type&, const
> MappingType&,
> const AccessorType&)
> -> mdspan<typename AccessorType::element_type, typename
> MappingType::extents_type,
> typename MappingType::layout_type, AccessorType>;
> ```
>
> We must spell with
> ```
> auto _3x3 = std::layout_right::mapping(std::extents(3, 3));
> auto ms = std::mdspan(r.begin(), _3x3, std::iterator_accessor(r.begin()));
> ```
>
> A subsequent question is, once we have an `iterator_accessor`, should we
> enhance mdspan's CTAD so that:
>
> ```
> auto ms = std::mdspan(r.*begin*(), 3, 3); // call *begin*() instead of
> *data*()
> ```
>
> Works well? For example, enhance `ElementType*` parts in the current CTAD
> for `random_access_iterator`:
> ```
> template<random_access_iterator I, class... Integrals>
> requires ((is_convertible_v<Integrals, size_t> && ...) &&
> sizeof...(Integrals) > 0)
> explicit mdspan(I, Integrals...)
> -> mdspan<typename *iterator_accessor*<I>::*element_type*,
> extents<size_t, maybe-static-ext<Integrals>...>,
> layout_right,
> *iterator_accessor*<I>>;
> ```
> This eliminates the need for spelling of *r.begin()* twice.
> However, it's uncertain whether this *relaxation* for users dealing with
> contiguous_iterator/random_access_iteratorer instead of a raw pointer is
> good.
>
> Hewill Kang <hewillk_at_[hidden]> 於 2026年4月4日週六 上午11:54寫道:
>
>> Thank you, that makes sense.
>> I updated the paper.
>>
>>
>>
>>
>> Mark Hoemmen <mark.hoemmen_at_[hidden]> 於 2026年4月4日週六 上午3:16寫道:
>>
>>> On Fri, Apr 3, 2026 at 11:27 AM Hewill Kang <hewillk_at_[hidden]> wrote:
>>> >>
>>> >> Also, iterator_accessor has to deal with pointers as a special case of
>>> >> iterators, so it should have the same safeguard as default_accessor
>>> and
>>> >> friends against converting a pointer-to-derived to a pointer-to-base.
>>> >
>>> >
>>> > That's reasonable, thank you. I updated the paper.
>>> >
>>> > This is the current final version of the paper:
>>> https://isocpp.org/files/papers/P4173R0.html
>>> > And implementation with libstdc++: https://godbolt.org/z/86MKa3oa5
>>>
>>> Would you consider making those conversion operators to
>>> `default_accessor` explicit?
>>>
>>> I ask because container authors sometimes provide iterators that model
>>> `contiguous_iterator` but do run-time bounds checking. Implicit
>>> conversion from `iterator_accessor` to `default_accessor` would
>>> silently strip away this protection.
>>>
>>> Thanks!
>>> mfh
>>>
>>>
>>> >
>>> > Thanks.
>>> > Hewill
>>> >
>>> > Ell <ell.ell.se_at_[hidden]> 於 2026年4月3日週五 上午2:48寫道:
>>> >>
>>> >> On Thursday, April 2nd, 2026 at 8:24 PM, Mark Hoemmen via
>>> Std-Proposals <std-proposals_at_[hidden]> wrote:
>>> >>
>>> >> > >> 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.
>>> >> >
>>> >>
>>> >> Also, iterator_accessor has to deal with pointers as a special case of
>>> >> iterators, so it should have the same safeguard as default_accessor
>>> and
>>> >> friends against converting a pointer-to-derived to a pointer-to-base.
>>>
>>
Received on 2026-04-04 16:28:11
