Title
`layout_stride` should accept zero strides for empty `extents`
Status
new
Section
[mdspan.layout.stride.cons]
Submitter
Tomasz Kamiński

Created on 2026-06-07.00:00:00 last changed 6 days ago

Messages

Date: 2026-07-10.16:31:11

Proposed resolution:

This wording is relative to N5046.

  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 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 ([basic.fundamental]).

    • (4.3) — If both rank_ and the size of the multidimensional index space extents() areis greater than 0, then there exists a permutation P of the integers in the range [0, rank_), such that s[p0] > 0 is true and s[pi] >= s[pi-1] * e.extent(pi) is true for all i in the range [1, rank_), where pik is the ikth element of P.

    -5- Effects: […]

    template<class StridedLayoutMapping>
      constexpr explicit(see below)
        mapping(const StridedLayoutMapping& other) noexcept;
    

    -6- Constraints: […]

    -7- Preconditions:

    • (7.1) — StridedLayoutMapping meets the layout mapping requirements ([mdspan.layout.reqmts]),

    • (7.2) — other.stride(r) > 0 is true for every rank index r of extents(),

    • (7.3) — other.required_span_size() is representable as a value of type index_type ([basic.fundamental]), and,

    • (7.4) — OFFSET(other) == 0 is true.

    -5- Effects: […]

Date: 2026-07-15.00:00:00

[ 2026-07-10; Tomasz provides updated wording. ]

Date: 2026-07-15.00:00:00

[ 2026-07-10; LWG telecon. ]

Set priority to 3 after telecon poll. Tomasz to revise proposed resolution to incorporate other change from P3959R0, which deals with this same issue.

This wording is relative to N5046.

  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 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 ([basic.fundamental]).

    • (4.3) — If both rank_ and the size of the multidimensional index space extents() areis greater than 0, then there exists a permutation P of the integers in the range [0, rank_), such that s[p0] > 0 is true and s[pi] >= s[pi-1] * e.extent(pi) is true for all i in the range [1, rank_), where pik is the ikth element of P.

    -5- Effects: […]

Date: 2026-06-07.00:00:00

`layout_stride` constructor accepting `extents` and `strides` values, requires that stride values are always greater than zero, even if the `extents` represents empty multidimensional index space. As for such `extents` types `layout_left` and `layout_right` mappings will result in zero strides, leads to inconsistencies in behavior:

  std::dextents<size_t, 3> ext{1, 0, 4};
  std::layout_left ll{ext};
  std::layout_stride ls{std::layout_left{ext}}; // OK, no precondition on constructor

  std::array<size, 3> strides{ll.stride(0), ll.stride(1), ll.stride(2)};
  std::layout_stride lse{ext, strides}; // UB, ll.stride(2) is zero

As by definition any mapping over empty multidimensional index space is unique, we should weaken that precondition and require non-zero strides only for non-empty `extents`.

Furthermore, the current wording "result of converting `s[i]` to `index_type` is greater than `0`", forces implementation to convert the inputs to (mostly unsigned) `index_type` before the check, preventing detection of negative values. We should use index-cast instead.

History
Date User Action Args
2026-07-10 16:31:11adminsetmessages: + msg16508
2026-07-10 16:01:38adminsetmessages: + msg16503
2026-07-10 15:48:09adminsetstatus: ready -> new
2026-07-07 14:33:31adminsetmessages: + msg16502
2026-06-07 00:00:00admincreate