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.

4545. Some converting constructors of layout_left_padded::mapping and layout_right_padded::mapping are missing a representability precondition for the padded stride

Section: 23.7.3.4.8.3 [mdspan.layout.leftpad.cons], 23.7.3.4.9.3 [mdspan.layout.rightpad.cons] Status: New Submitter: Xi Chen Opened: 2026-03-18 Last modified: 2026-03-21

Priority: Not Prioritized

View all issues with New status.

Discussion:

It appears that these constructors are missing a precondition requiring the incoming padded stride to be representable as a value of the destination index_type.

The existing preconditions check that other.required_span_size() is representable as a value of type index_type, but that is not sufficient when the source mapping is empty. In that case, other.required_span_size() can be 0 even though the source padded stride is too large for the destination index_type. The padded stride is then silently truncated, and that truncation is observable through stride().

Example:

#include <mdspan>
#include <cstdint>
#include <cassert>

void test() {
  using Src = std::layout_left_padded<std::dynamic_extent>::mapping<std::extents<uint32_t, 1, 0>>;
  using Dst = std::layout_left_padded<std::dynamic_extent>::mapping<std::extents<uint8_t, 1, 0>>;

  // src.stride(1) == 256.
  Src src(std::extents<uint32_t, 1, 0>(), 256);

  // other.required_span_size() is 0, so the existing preconditions are met.
  // The stored padded stride is then converted to uint8_t and truncated to 0.
  Dst dst(src);

  assert(dst.stride(1) == 0);
}

Proposed resolution:

This wording is relative to N5032.

  1. Modify 23.7.3.4.8.3 [mdspan.layout.leftpad.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -10- Constraints: […]

    -11- Preconditions:

    • (11.1) — […]

    • (11.2) — […]

    • (11.3) — […]

    • (11.4) — other.required_span_size() is representable as a value of type index_type.

    • (11.5) — If rank_ is greater than 1 and static-padding-stride equals dynamic_extent, other.stride(1) is representable as a value of type index_type.

    -12- Effects: […]

    -13- Remarks: […]

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

    -14- Constraints: […]

    -15- Mandates: […]

    -16- Preconditions:

    • (16.1) — […]

    • (16.2) — other.required_span_size() is representable as a value of type index_type.

    • (16.3) — If rank_ is greater than 1 and static-padding-stride equals dynamic_extent, other.stride(1) is representable as a value of type index_type.

    -17- Effects: […]

    -18- Remarks: […]

  2. Modify 23.7.3.4.9.3 [mdspan.layout.rightpad.cons] as indicated:

    template<class OtherExtents>
      constexpr explicit(see below)
        mapping(const layout_stride::mapping<OtherExtents>& other);
    

    -10- Constraints: […]

    -11- Preconditions:

    • (11.1) — […]

    • (11.2) — […]

    • (11.3) — […]

    • (11.4) — other.required_span_size() is representable as a value of type index_type.

    • (11.5) — If rank_ is greater than 1 and static-padding-stride equals dynamic_extent, other.stride(rank_ - 2) is representable as a value of type index_type.

    -12- Effects: […]

    -13- Remarks: […]

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

    -14- Constraints: […]

    -15- Mandates: […]

    -16- Preconditions:

    • (16.1) — […]

    • (16.2) — other.required_span_size() is representable as a value of type index_type.

    • (16.3) — If rank_ is greater than 1 and static-padding-stride equals dynamic_extent, other.stride(rank_ - 2) is representable as a value of type index_type.

    -17- Effects: […]

    -18- Remarks: […]