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.
mdspan
layout mapping::operator()
Section: 23.7.3.4 [mdspan.layout] Status: New Submitter: Luc Grosheintz Opened: 2025-08-13 Last modified: 2025-08-16
Priority: Not Prioritized
View other active issues in [mdspan.layout].
View all other issues in [mdspan.layout].
View all issues with New status.
Discussion:
Numerous template classes in <mdspan>
have template parameter IndexType
.
While this template parameter is restricted to be a signed or unsigned integer,
these classes often accept user-defined classes that convert to IndexType
.
OtherIndexType
; or as a template parameter pack.
When passed as a template parameter pack, the common pattern is
template<class... OtherIndexTypes> requires std::is_convertible_v<OtherIndexTypes, IndexType> && ... void dummy(OtherIndexTypes... indices) { something(static_cast<IndexType>(std::move(indices))...); }
This pattern allows passing in objects that convert to IndexType only as an rvalue reference, e.g.
class RValueInt { constexpr operator int() && noexcept { return m_int; } private: int m_int; };
This pattern can be found in:
a ctor of extents
,
a ctor of mdspan
,
mdspan::operator[]
.
The five standardized layout mappings use a different pattern in their operator(), namely,
static_cast<IndexType>(indices)...
This prevents the passing in objects of type RValueInt
, because the
conversion isn't happening from an rvalue reference. This is addressed by
Items 1 - 5 in the Proposed Resolution.
layout_{left,right}_padded
.
Namely, directly passing an object of type OtherIndexType
to
LEAST-MULTIPLE-AT-LEAST
. This is addressed in Items 6 and 7
in the Proposed Resolution.
This inconsistency was noticed while fixing
PR121061
and these changes have been applied to all layout mappings implemented in libstdc++.
Proposed resolution:
This wording is relative to N5014.
Modify 23.7.3.4.5.3 [mdspan.layout.left.obs] as indicated:
template<class... Indices> constexpr index_type operator()(Indices... i) const noexcept;-2- Constraints: […]
-3- Preconditions: […] -4- Effects: LetP
be a parameter pack such thatis_same_v<index_sequence_for<Indices...>, index_sequence<P...>>is
true
. Equivalent to:return ((static_cast<index_type>(std::move(i)) * stride(P)) + ... + 0);
Modify 23.7.3.4.6.3 [mdspan.layout.right.obs] as indicated:
template<class... Indices> constexpr index_type operator()(Indices... i) const noexcept;-2- Constraints: […]
-3- Preconditions: […] -4- Effects: LetP
be a parameter pack such thatis_same_v<index_sequence_for<Indices...>, index_sequence<P...>>is
true
. Equivalent to:return ((static_cast<index_type>(std::move(i)) * stride(P)) + ... + 0);
Modify 23.7.3.4.7.4 [mdspan.layout.stride.obs] as indicated:
template<class... Indices> constexpr index_type operator()(Indices... i) const noexcept;-2- Constraints: […]
-3- Preconditions: […] -4- Effects: LetP
be a parameter pack such thatis_same_v<index_sequence_for<Indices...>, index_sequence<P...>>is
true
. Equivalent to:return ((static_cast<index_type>(std::move(i)) * stride(P)) + ... + 0);
Modify 23.7.3.4.8.4 [mdspan.layout.leftpad.obs] as indicated:
template<class... Indices> constexpr index_type operator()(Indices... idxs) const noexcept;-3- Constraints: […]
-4- Preconditions: […] -5- Returns:((static_cast<index_type>(std::move(idxs)) * stride(P_rank)) + ... + 0)
.
Modify 23.7.3.4.9.4 [mdspan.layout.rightpad.obs] as indicated:
template<class... Indices> constexpr index_type operator()(Indices... idxs) const noexcept;-3- Constraints: […]
-4- Preconditions: […] -5- Returns:((static_cast<index_type>(std::move(idxs)) * stride(P_rank)) + ... + 0)
.
Modify 23.7.3.4.8.3 [mdspan.layout.leftpad.cons] as indicated:
template<class OtherIndexType> constexpr mapping(const extents_type& ext, OtherIndexType padding);Let
-3- Constraints: […] -4- Preconditions:pad = static_cast<index_type>(std::move(padding))
.
(4.1) —
padding
is representable as a value of typeindex_type
.(4.2) —
pad is greater than zero.extents_type::index-cast(pad)
(4.3) — If
rank_
is greater than one, thenLEAST-MULTIPLE-AT-LEAST(pad, ext.extent(0))
is representable as a value of typeindex_type
.(4.4) — If
rank_
is greater than one, then the product ofLEAST-MULTIPLE-AT-LEAST(pad, ext.extent(0))
and all valuesext.extent(k)
withk
in the range of[1, rank_)
is representable as a value of typeindex_type
.(4.5) — If
padding_value
is not equal todynamic_extent
,padding_value
equals.
extents_type::index-cast(pad)pad-5- Effects: […]
Modify 23.7.3.4.9.3 [mdspan.layout.rightpad.cons] as indicated:
template<class OtherIndexType> constexpr mapping(const extents_type& ext, OtherIndexType padding);Let
-3- Constraints: […] -4- Preconditions:pad = static_cast<index_type>(std::move(padding))
.
(4.1) —
padding
is representable as a value of typeindex_type
.(4.2) —
pad is greater than zero.extents_type::index-cast(pad)
(4.3) — If
rank_
is greater than one, thenLEAST-MULTIPLE-AT-LEAST(pad, ext.extent(rank_ - 1))
is representable as a value of typeindex_type
.(4.4) — If
rank_
is greater than one, then the product ofLEAST-MULTIPLE-AT-LEAST(pad, ext.extent(rank_ - 1))
and all valuesext.extent(k)
withk
in the range of[1, rank_ - 1)
is representable as a value of typeindex_type
.(4.5) — If
padding_value
is not equal todynamic_extent
,padding_value
equals.
extents_type::index-cast(pad)pad-5- Effects: […]