This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4606. Bullet (4.3) preconditions are too strict to implement submdspan

Section: 23.7.3.4.7.3 [mdspan.layout.stride.cons] Status: New Submitter: Mark Hoemmen Opened: 2026-07-15 Last modified: 2026-07-20

Priority: Not Prioritized

View other active issues in [mdspan.layout.stride.cons].

View all other issues in [mdspan.layout.stride.cons].

View all issues with New status.

Discussion:

For layout_stride::mapping's constructor that takes an extents object and an array (or span) of strides, the preconditions on the strides are too strict. This makes it impossible to implement submdspan.

For an example see here. Let x be an mdspan such that x.mapping() is layout_right::mapping with extents (2, 5).

// slice denotes indices {0,2,4} out of original {0,1,2,3,4}.
std::extent_slice slice{.offset=0, .extent=3, .stride=2};
auto x_sub = std::submdspan(x, std::full_extent, slice);
assert(x_sub.extent(0) == 2);
assert(x_sub.extent(1) == 3);
assert(x_sub.stride(0) == 5);
assert(x_sub.stride(1) == 2);

x_sub's layout_type is layout_stride. However, the only way to construct layout_stride::mapping with these extents and strides would be to call the constructor that takes an extents object and an array (or span) of strides, and the above extents and strides would violate the preconditions.

// Extents and strides violate precondition of layout_stride::mapping
// constructor (23.7.3.4.7.3 [mdspan.layout.stride.cons] 4.3).
assert(! (x_sub.stride(1) >= x_sub.stride(0) * x_sub.extent(0)));
assert(! (x_sub.stride(0) >= x_sub.stride(1) * x_sub.extent(1)));

The fix is to relax the preconditions so that they test only the possibility of overlap.

assert(! (x_sub.stride(1) >= 1 + (x_sub.extent(0) - 1) * x_sub.stride(0)));
assert(   x_sub.stride(0) >= 1 + (x_sub.extent(1) - 1) * x_sub.stride(1));

Proposed resolution:

This wording is relative to N5054.

[Drafting note: The proposed wording currently misses to account for extents of zero or 1]

  1. Modify 23.7.3.4.7.3 [mdspan.layout.stride.cons] as indicated:

    template<class OtherIndexType>
      constexpr mapping(const extents_type& e, span<OtherIndexType, rank_> s) noexcept;
    template<class OtherIndexType>
      constexpr mapping(const extents_type& e, const array<OtherIndexType, rank_>& s) noexcept;
    

    -3- Constraints: […]

    -4- Preconditions:

    1. (4.1) — The result of converting s[i] to index_type is greater than 0 for all i in the range [0, rank_).

    2. (4.2) — REQUIRED-SPAN-SIZE(e, s) is representable as a value of type index_type (6.9.2 [basic.fundamental]).

    3. (4.3) — If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), such that s[pi] >= s[pi-1] * e.extent(pi-1) s[pi] >= 1 + (e.extent(pi-1) - 1) * s[pi-1] is true for all i in the range [1, rank_), where pi is the ith element of P.

      [Note 1: For layout_stride, this condition is necessary and sufficient for is_unique() to be true. — end note]

    -5- Effects: Direct-non-list-initializes extents_ with e, and for all d in the range [0, rank_), direct-non-list-initializes strides_[d] with as_const(s[d]).