Created on 2026-07-15.00:00:00 last changed 1 week ago
Proposed resolution:
This wording is relative to N5054 with modifications from LWG 4603.
Modify [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:
(4.1) — extents_type::index-cast(s[i]) is non-negative and representable as a value of type index_type ([basic.fundamental]) for all i in the range [0, rank_).
(4.2) — REQUIRED-SPAN-SIZE(e, s) is representable as a value of type
index_type.(4.3) — If both rank_ and the size of the multidimensional index space extents() are greater than 0, then there exists a permutation P of the integers in the range [0, rank_) and value m, such that
where pk is the kth element of P.
(4.3.1) — e.extent(i) == 1 is true for all i in the range [0, m),
(4.3.2) — e.extent(i) > 1 is true for all i in the range [m, rank_),
(4.3.3) — if m < rank_ is true, then s[p
0m] > 0 is true and for all i in the range [m+1, rank_), s[pi]>=is greater than sum of s[pi-1j] * (e.extent(pij)-1)is truefor allij in the range[1, rank_)[m, i),[Note: For layout_stride, this condition is
necessary andsufficient for is_unique() to be true. — end note]-5- Effects: […]
[ 2026-07-31 LWG telecon; Status changed: New → Ready. ]
[ 2026-07-24; Tomasz provides updated wording. ]
Patch implementing the proposed resolution can be found here.
The note is adjusted as below condition is sufficient, but not necessary to guarantee uniqueness, consider strides (3, 5) and extents (5, 3). They do not meet the requirements but produce unique mapping:
0 1 2 3 4
----------------------
0| 0 3 6 9 12
1| 5 8 11 14 17
2| 10 13 16 19 22
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 ([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));
This wording is relative to N5054.
[Drafting note: The proposed wording currently misses to account for extents of zero or 1]
Modify [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:
(4.1) — The result of converting s[i] to `index_type` is greater than `0` for all i in the range [0, rank_).
(4.2) — REQUIRED-SPAN-SIZE(e, s) is representable as a value of type `index_type` ([basic.fundamental]).
(4.3) — If rank_ is greater than `0`, then there exists a permutation P of the integers in the range [0, rank_), such that
[Note 1: For `layout_stride`, this condition is necessary and sufficient for `is_unique()` to be `true`. — end note]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.-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]).
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2026-07-31 16:46:35 | admin | set | messages: + msg16547 |
| 2026-07-31 16:46:35 | admin | set | status: new -> ready |
| 2026-07-28 16:41:22 | admin | set | messages: + msg16533 |
| 2026-07-18 14:22:55 | admin | set | messages: + msg16526 |
| 2026-07-15 00:00:00 | admin | create | |