[views] (original) (raw)
23 Containers library [containers]
23.7 Views [views]
23.7.1 General [views.general]
23.7.2 Contiguous access [views.contiguous]
23.7.2.1 Header synopsis [span.syn]
23.7.2.2 Class template span [views.span]
23.7.2.2.1 Overview [span.overview]
23.7.2.2.2 Constructors, copy, and assignment [span.cons]
23.7.2.2.3 Deduction guides [span.deduct]
23.7.2.2.4 Subviews [span.sub]
23.7.2.2.5 Observers [span.obs]
23.7.2.2.6 Element access [span.elem]
23.7.2.2.7 Iterator support [span.iterators]
23.7.2.3 Views of object representation [span.objectrep]
23.7.3 Multidimensional access [views.multidim]
23.7.3.1 Overview [mdspan.overview]
23.7.3.2 Header synopsis [mdspan.syn]
23.7.3.3 Class template extents [mdspan.extents]
23.7.3.3.1 Overview [mdspan.extents.overview]
23.7.3.3.2 Exposition-only helpers [mdspan.extents.expo]
23.7.3.3.3 Constructors [mdspan.extents.cons]
23.7.3.3.4 Observers of the multidimensional index space [mdspan.extents.obs]
23.7.3.3.5 Comparison operators [mdspan.extents.cmp]
23.7.3.3.6 Alias template dextents [mdspan.extents.dextents]
23.7.3.3.7 Alias template dims [mdspan.extents.dims]
23.7.3.4 Layout mapping [mdspan.layout]
23.7.3.4.1 General [mdspan.layout.general]
23.7.3.4.2 Requirements [mdspan.layout.reqmts]
23.7.3.4.3 Layout mapping policy requirements [mdspan.layout.policy.reqmts]
23.7.3.4.4 Layout mapping policies [mdspan.layout.policy.overview]
23.7.3.4.5 Class template layout_left::mapping [mdspan.layout.left]
23.7.3.4.5.1 Overview [mdspan.layout.left.overview]
23.7.3.4.5.2 Constructors [mdspan.layout.left.cons]
23.7.3.4.5.3 Observers [mdspan.layout.left.obs]
23.7.3.4.6 Class template layout_right::mapping [mdspan.layout.right]
23.7.3.4.6.1 Overview [mdspan.layout.right.overview]
23.7.3.4.6.2 Constructors [mdspan.layout.right.cons]
23.7.3.4.6.3 Observers [mdspan.layout.right.obs]
23.7.3.4.7 Class template layout_stride::mapping [mdspan.layout.stride]
23.7.3.4.7.1 Overview [mdspan.layout.stride.overview]
23.7.3.4.7.2 Exposition-only helpers [mdspan.layout.stride.expo]
23.7.3.4.7.3 Constructors [mdspan.layout.stride.cons]
23.7.3.4.7.4 Observers [mdspan.layout.stride.obs]
23.7.3.4.8 Class template layout_left_padded::mapping [mdspan.layout.leftpad]
23.7.3.4.8.1 Overview [mdspan.layout.leftpad.overview]
23.7.3.4.8.2 Exposition-only members [mdspan.layout.leftpad.expo]
23.7.3.4.8.3 Constructors [mdspan.layout.leftpad.cons]
23.7.3.4.8.4 Observers [mdspan.layout.leftpad.obs]
23.7.3.4.9 Class template layout_right_padded::mapping [mdspan.layout.rightpad]
23.7.3.4.9.1 Overview [mdspan.layout.rightpad.overview]
23.7.3.4.9.2 Exposition-only members [mdspan.layout.rightpad.expo]
23.7.3.4.9.3 Constructors [mdspan.layout.rightpad.cons]
23.7.3.4.9.4 Observers [mdspan.layout.rightpad.obs]
23.7.3.5 Accessor policy [mdspan.accessor]
23.7.3.5.1 General [mdspan.accessor.general]
23.7.3.5.2 Requirements [mdspan.accessor.reqmts]
23.7.3.5.3 Class template default_accessor [mdspan.accessor.default]
23.7.3.5.3.1 Overview [mdspan.accessor.default.overview]
23.7.3.5.3.2 Members [mdspan.accessor.default.members]
23.7.3.5.4 Class template aligned_accessor [mdspan.accessor.aligned]
23.7.3.5.4.1 Overview [mdspan.accessor.aligned.overview]
23.7.3.5.4.2 Members [mdspan.accessor.aligned.members]
23.7.3.6 Class template mdspan [mdspan.mdspan]
23.7.3.6.1 Overview [mdspan.mdspan.overview]
23.7.3.6.2 Constructors [mdspan.mdspan.cons]
23.7.3.6.3 Members [mdspan.mdspan.members]
23.7.3.7 submdspan [mdspan.sub]
23.7.3.7.1 Overview [mdspan.sub.overview]
23.7.3.7.2 strided_slice [mdspan.sub.strided.slice]
23.7.3.7.3 submdspan_mapping_result [mdspan.sub.map.result]
23.7.3.7.4 Exposition-only helpers [mdspan.sub.helpers]
23.7.3.7.5 submdspan slice canonicalization [mdspan.sub.canonical]
23.7.3.7.6 submdspan_extents function [mdspan.sub.extents]
23.7.3.7.7 Specializations of submdspan_mapping [mdspan.sub.map]
23.7.3.7.7.1 Sliceable layout mapping requirements [mdspan.sub.map.sliceable]
23.7.3.7.7.2 Common [mdspan.sub.map.common]
23.7.3.7.7.3 layout_left specialization of submdspan_mapping [mdspan.sub.map.left]
23.7.3.7.7.4 layout_right specialization of submdspan_mapping [mdspan.sub.map.right]
23.7.3.7.7.5 layout_stride specialization of submdspan_mapping [mdspan.sub.map.stride]
23.7.3.7.7.6 layout_left_padded specialization of submdspan_mapping [mdspan.sub.map.leftpad]
23.7.3.7.7.7 layout_right_padded specialization of submdspan_mapping [mdspan.sub.map.rightpad]
23.7.3.7.8 submdspan function template [mdspan.sub.sub]
23.7.1 General [views.general]
The header defines the view span.
The header defines the class template mdspan and other facilities for interacting with these multidimensional views.
In addition to being available via inclusion of the header,dynamic_extent is available when the header is included.
23.7.2 Contiguous access [views.contiguous]
23.7.2.1 Header synopsis [span.syn]
23.7.2.2 Class template span [views.span]
23.7.2.2.1 Overview [span.overview]
A span is a view over a contiguous sequence of objects, the storage of which is owned by some other object.
All member functions of span have constant time complexity.
namespace std { template<class ElementType, size_t Extent = dynamic_extent> class span { public: using element_type = ElementType;using value_type = remove_cv_t<ElementType>;using size_type = size_t;using difference_type = ptrdiff_t;using pointer = element_type*;using const_pointer = const element_type*;using reference = element_type&;using const_reference = const element_type&;using iterator = implementation-defined; using const_iterator = std::const_iterator<iterator>;using reverse_iterator = std::reverse_iterator<iterator>;using const_reverse_iterator = std::const_iterator<reverse_iterator>;static constexpr size_type extent = Extent;constexpr span() noexcept;template<class It> constexpr explicit(extent != dynamic_extent) span(It first, size_type count);template<class It, class End> constexpr explicit(extent != dynamic_extent) span(It first, End last);template<size_t N> constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;template<class T, size_t N> constexpr span(array<T, N>& arr) noexcept;template<class T, size_t N> constexpr span(const array<T, N>& arr) noexcept;template<class R> constexpr explicit(extent != dynamic_extent) span(R&& r);constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il);constexpr span(const span& other) noexcept = default;template<class OtherElementType, size_t OtherExtent> constexpr explicit(see below) span(const span<OtherElementType, OtherExtent>& s) noexcept;constexpr span& operator=(const span& other) noexcept = default;template<size_t Count> constexpr span<element_type, Count> first() const;template<size_t Count> constexpr span<element_type, Count> last() const;template<size_t Offset, size_t Count = dynamic_extent> constexpr span<element_type, _see below_> subspan() const;constexpr span<element_type, dynamic_extent> first(size_type count) const;constexpr span<element_type, dynamic_extent> last(size_type count) const;constexpr span<element_type, dynamic_extent> subspan( size_type offset, size_type count = dynamic_extent) const;constexpr size_type size() const noexcept;constexpr size_type size_bytes() const noexcept;constexpr bool empty() const noexcept;constexpr reference operator[](size_type idx) const;constexpr reference at(size_type idx) const; constexpr reference front() const;constexpr reference back() const;constexpr pointer data() const noexcept;constexpr iterator begin() const noexcept;constexpr iterator end() const noexcept;constexpr const_iterator cbegin() const noexcept { return begin(); } constexpr const_iterator cend() const noexcept { return end(); } constexpr reverse_iterator rbegin() const noexcept;constexpr reverse_iterator rend() const noexcept;constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } constexpr const_reverse_iterator crend() const noexcept { return rend(); } private: pointer data_; size_type size_; };template<class It, class EndOrSize> span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>,maybe-static-ext<EndOrSize>>;template<class T, size_t N> span(T (&)[N]) -> span<T, N>;template<class T, size_t N> span(array<T, N>&) -> span<T, N>;template<class T, size_t N> span(const array<T, N>&) -> span<const T, N>;template<class R> span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;}
ElementType is required to be a complete object type that is not an abstract class type.
For a span s, any operation that invalidates a pointer in the range [s.data(), s.data() + s.size()) invalidates pointers, iterators, and references to elements of s.
23.7.2.2.2 Constructors, copy, and assignment [span.cons]
constexpr span() noexcept;
Constraints: Extent == dynamic_extent || Extent == 0 is true.
Postconditions: size() == 0 && data() == nullptr.
template<class It> constexpr explicit(extent != dynamic_extent) span(It first, size_type count);
Constraints: Let U be remove_reference_t<iter_reference_t<It>>.
- is_convertible_v<U(*)[], element_type(*)[]> is true.
[Note 1:
The intent is to allow only qualification conversions of the iterator reference type to element_type.
— _end note_]
Preconditions:
- [first, first + count) is a valid range.
Hardened preconditions: If extent is not equal to dynamic_extent, then count == extent is true.
Effects: Initializes data_ with to_address(first) and_size__ with count.
template<class It, class End> constexpr explicit(extent != dynamic_extent) span(It first, End last);
Constraints: Let U be remove_reference_t<iter_reference_t<It>>.
- is_convertible_v<U(*)[], element_type(*)[]> is true.
[Note 2:
The intent is to allow only qualification conversions of the iterator reference type to element_type.
— _end note_] - is_convertible_v<End, size_t> is false.
Preconditions:
- [first, last) is a valid range.
Hardened preconditions: If extent is not equal to dynamic_extent, then (last - first) == extent is true.
Effects: Initializes data_ with to_address(first) and_size__ with last - first.
Throws: When and what last - first throws.
template<size_t N> constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;template<class T, size_t N> constexpr span(array<T, N>& arr) noexcept;template<class T, size_t N> constexpr span(const array<T, N>& arr) noexcept;
Constraints: Let U be remove_pointer_t<decltype(std::data(arr))>.
- extent == dynamic_extent || N == extent is true, and
- is_convertible_v<U(*)[], element_type(*)[]> is true.
[Note 3:
The intent is to allow only qualification conversions of the array element type to element_type.
— _end note_]
Effects: Constructs a span that is a view over the supplied array.
[Note 4:
type_identity_t affects class template argument deduction.
— _end note_]
Postconditions: size() == N && data() == std::data(arr) is true.
template<class R> constexpr explicit(extent != dynamic_extent) span(R&& r);
Constraints: Let U be remove_reference_t<ranges::range_reference_t<R>>.
- Either R satisfies ranges::borrowed_range oris_const_v<element_type> is true.
- remove_cvref_t<R> is not a specialization of span.
- remove_cvref_t<R> is not a specialization of array.
- is_array_v<remove_cvref_t<R>> is false.
- is_convertible_v<U(*)[], element_type(*)[]> is true.
[Note 5:
The intent is to allow only qualification conversions of the range reference type to element_type.
— _end note_]
Preconditions:
- If is_const_v<element_type> is false,R models ranges::borrowed_range.
Hardened preconditions: If extent is not equal to dynamic_extent, then ranges::size(r) == extent is true.
Effects: Initializes data_ with ranges::data(r) and_size__ with ranges::size(r).
Throws: What and when ranges::data(r) and ranges::size(r) throw.
constexpr explicit(extent != dynamic_extent) span(std::initializer_list<value_type> il);
Constraints: is_const_v<element_type> is true.
Hardened preconditions: If extent is not equal to dynamic_extent, then il.size() == extent is true.
Effects: Initializes data_ with il.data() and_size__ with il.size().
constexpr span(const span& other) noexcept = default;
Postconditions: other.size() == size() && other.data() == data().
template<class OtherElementType, size_t OtherExtent> constexpr explicit(_see below_) span(const span<OtherElementType, OtherExtent>& s) noexcept;
Constraints:
- extent == dynamic_extent || OtherExtent == dynamic_extent || extent == OtherExtent is true, and
- is_convertible_v<OtherElementType(*)[], element_type(*)[]> is true.
[Note 6:
The intent is to allow only qualification conversions of the OtherElementType to element_type.
— _end note_]
Hardened preconditions: If extent is not equal to dynamic_extent, then s.size() == extent is true.
Effects: Constructs a span that is a view over the range [s.data(), s.data() + s.size()).
Postconditions: size() == s.size() && data() == s.data().
Remarks: The expression inside explicit is equivalent to:extent != dynamic_extent && OtherExtent == dynamic_extent
constexpr span& operator=(const span& other) noexcept = default;
Postconditions: size() == other.size() && data() == other.data().
23.7.2.2.3 Deduction guides [span.deduct]
template<class It, class EndOrSize> span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>,[_maybe-static-ext_](#concept:maybe-static-ext "23.7.2.1 Header <span> synopsis [span.syn]")<EndOrSize>>;
template<class R> span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
23.7.2.2.4 Subviews [span.sub]
template<size_t Count> constexpr span<element_type, Count> first() const;
Mandates: Count <= Extent is true.
Hardened preconditions: Count <= size() is true.
Effects: Equivalent to: return R(data(), Count);where R is the return type.
template<size_t Count> constexpr span<element_type, Count> last() const;
Mandates: Count <= Extent is true.
Hardened preconditions: Count <= size() is true.
Effects: Equivalent to: return R(data() + (size() - Count), Count);where R is the return type.
template<size_t Offset, size_t Count = dynamic_extent> constexpr span<element_type, _see below_> subspan() const;
Mandates: Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset) is true.
Hardened preconditions: Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset) is true.
Effects: Equivalent to:return span<ElementType, _see below_>( data() + Offset, Count != dynamic_extent ? Count : size() - Offset);
Remarks: The second template argument of the returned span type is:Count != dynamic_extent ? Count: (Extent != dynamic_extent ? Extent - Offset: dynamic_extent)
constexpr span<element_type, dynamic_extent> first(size_type count) const;
Hardened preconditions: count <= size() is true.
Effects: Equivalent to: return R(data(), count);where R is the return type.
constexpr span<element_type, dynamic_extent> last(size_type count) const;
Hardened preconditions: count <= size() is true.
Effects: Equivalent to: return R(data() + (size() - count), count);where R is the return type.
constexpr span<element_type, dynamic_extent> subspan( size_type offset, size_type count = dynamic_extent) const;
Hardened preconditions: offset <= size() && (count == dynamic_extent || count <= size() - offset) is true.
Effects: Equivalent to:return R(data() + offset, count == dynamic_extent ? size() - offset : count);where R is the return type.
23.7.2.2.5 Observers [span.obs]
constexpr size_type size() const noexcept;
Effects: Equivalent to: return size_;
constexpr size_type size_bytes() const noexcept;
Effects: Equivalent to: return size() * sizeof(element_type);
constexpr bool empty() const noexcept;
Effects: Equivalent to: return size() == 0;
23.7.2.2.6 Element access [span.elem]
constexpr reference operator[](size_type idx) const;
Hardened preconditions: idx < size() is true.
Returns: *(data() + idx).
constexpr reference at(size_type idx) const;
Returns: *(data() + idx).
Throws: out_of_range if idx >= size() is true.
constexpr reference front() const;
Hardened preconditions: empty() is false.
constexpr reference back() const;
Hardened preconditions: empty() is false.
Returns: *(data() + (size() - 1)).
constexpr pointer data() const noexcept;
23.7.2.2.7 Iterator support [span.iterators]
using iterator = _implementation-defined_;
All requirements on container iterators ([container.reqmts]) apply tospan::iterator as well.
constexpr iterator begin() const noexcept;
Returns: An iterator referring to the first element in the span.
If empty() is true, then it returns the same value as end().
constexpr iterator end() const noexcept;
Returns: An iterator which is the past-the-end value.
constexpr reverse_iterator rbegin() const noexcept;
Effects: Equivalent to: return reverse_iterator(end());
constexpr reverse_iterator rend() const noexcept;
Effects: Equivalent to: return reverse_iterator(begin());
23.7.2.3 Views of object representation [span.objectrep]
template<class ElementType, size_t Extent> span<const byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent> as_bytes(span<ElementType, Extent> s) noexcept;
Constraints: is_volatile_v<ElementType> is false.
Effects: Equivalent to: return R{reinterpret_cast<const byte*>(s.data()), s.size_bytes()};where R is the return type.
template<class ElementType, size_t Extent> span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent> as_writable_bytes(span<ElementType, Extent> s) noexcept;
Constraints: is_const_v<ElementType> is false andis_volatile_v<ElementType> is false.
Effects: Equivalent to: return R{reinterpret_cast<byte*>(s.data()), s.size_bytes()};where R is the return type.
23.7.3 Multidimensional access [views.multidim]
23.7.3.1 Overview [mdspan.overview]
A multidimensional index space is a Cartesian product of integer intervals.
Each interval can be represented by a half-open range , where and are the lower and upper bounds of the dimension.
The rank of a multidimensional index space is the number of intervals it represents.
The size of a multidimensional index space is the product of for each dimension iif its rank is greater than 0, and 1 otherwise.
An integer r is a rank index of an index space Sif r is in the range .
A pack of integers idx is a multidimensional index in a multidimensional index space S(or representation thereof) if both of the following are true:
- sizeof...(idx) is equal to the rank of S, and
- for every rank index i of S, the value of idx is an integer in the interval of S.
23.7.3.2 Header synopsis [mdspan.syn]
23.7.3.3 Class template extents [mdspan.extents]
23.7.3.3.1 Overview [mdspan.extents.overview]
The class template extents represents a multidimensional index space of rank equal to sizeof...(Extents).
In [views],extents is used synonymously with multidimensional index space.
namespace std { template<class IndexType, size_t... Extents> class extents { public: using index_type = IndexType;using size_type = make_unsigned_t<index_type>;using rank_type = size_t;static constexpr rank_type rank() noexcept { return sizeof...(Extents); } static constexpr rank_type rank_dynamic() noexcept { return dynamic-index(rank()); } static constexpr size_t static_extent(rank_type) noexcept;constexpr index_type extent(rank_type) const noexcept;constexpr extents() noexcept = default;template<class OtherIndexType, size_t... OtherExtents> constexpr explicit(see below) extents(const extents<OtherIndexType, OtherExtents...>&) noexcept;template<class... OtherIndexTypes> constexpr explicit extents(OtherIndexTypes...) noexcept;template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) extents(span<OtherIndexType, N>) noexcept;template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) extents(const array<OtherIndexType, N>&) noexcept;template<class OtherIndexType, size_t... OtherExtents> friend constexpr bool operator==(const extents&,const extents<OtherIndexType, OtherExtents...>&) noexcept;constexpr size_t fwd-prod-of-extents(rank_type) const noexcept; constexpr size_t rev-prod-of-extents(rank_type) const noexcept; template<class OtherIndexType> static constexpr auto index-cast(OtherIndexType&&) noexcept; private: static constexpr rank_type dynamic-index(rank_type) noexcept; static constexpr rank_type dynamic-index-inv(rank_type) noexcept; array<index_type, rank_dynamic()> dynamic-extents{}; };template<class... Integrals> explicit extents(Integrals...) -> see below;}
Mandates:
- IndexType is a signed or unsigned integer type, and
- each element of Extents is either equal to dynamic_extent, or is representable as a value of type IndexType.
Each specialization of extents models regular and is trivially copyable.
Let be the element of Extents.
is a dynamic extent if it is equal to dynamic_extent, otherwise is a static extent.
Let be the value of _dynamic-extents_[dynamic-index(r)]if is a dynamic extent, otherwise .
The interval of the multidimensional index space represented by an extents object is .
23.7.3.3.2 Exposition-only helpers [mdspan.extents.expo]
static constexpr rank_type _dynamic-index_(rank_type i) noexcept;
Preconditions: i <= rank() is true.
Returns: The number of with for which is a dynamic extent.
static constexpr rank_type _dynamic-index-inv_(rank_type i) noexcept;
Preconditions: i < rank_dynamic() is true.
Returns: The minimum value of rsuch that dynamic-index(r + 1) == i + 1 is true.
constexpr size_t _fwd-prod-of-extents_(rank_type i) const noexcept;
Preconditions: i <= rank() is true.
Returns: If i > 0 is true, the product of extent(k) for all k in the range [0, i), otherwise 1.
constexpr size_t _rev-prod-of-extents_(rank_type i) const noexcept;
Preconditions: i < rank() is true.
Returns: If i + 1 < rank() is true, the product of extent(k)for all k in the range [i + 1, rank()), otherwise 1.
template<class OtherIndexType> static constexpr auto _index-cast_(OtherIndexType&& i) noexcept;
Effects:
- If remove_cvref_t<OtherIndexType> is an integral type other than bool, then equivalent to return i;,
- otherwise, equivalent to return static_cast<index_type>(i);.
[Note 1:
This function will always return an integral type other than bool.
Since this function's call sites are constrained on convertibility of OtherIndexType to index_type, integer-class types can use the static_cast branch without loss of precision.
— _end note_]
23.7.3.3.3 Constructors [mdspan.extents.cons]
template<class OtherIndexType, size_t... OtherExtents> constexpr explicit(_see below_) extents(const extents<OtherIndexType, OtherExtents...>& other) noexcept;
Constraints:
- sizeof...(OtherExtents) == rank() is true.
- ((OtherExtents == dynamic_extent || Extents == dynamic_extent || OtherExtents ==
Extents) && ...) is true.
Preconditions:
- other.extent(r) equals for each r for which is a static extent, and
- either
- sizeof...(OtherExtents) is zero, or
- other.extent(r) is representable as a value of type index_type for every rank index r of other.
Postconditions: *this == other is true.
Remarks: The expression inside explicit is equivalent to:(((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) || (numeric_limits<index_type>::max() < numeric_limits<OtherIndexType>::max())
template<class... OtherIndexTypes> constexpr explicit extents(OtherIndexTypes... exts) noexcept;
Let N be sizeof...(OtherIndexTypes), and let exts_arr bearray<index_type, N>{static_cast<
index_type>(std::move(exts))...}.
Constraints:
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
- N == rank_dynamic() || N == rank() is true.
[Note 1:
One can construct extents from just dynamic extents, which are all the values getting stored, or from all the extents with a precondition.
— _end note_]
Preconditions:
- If N != rank_dynamic() is true,exts_arr[r] equals for each r for which is a static extent, and
- either
- sizeof...(exts) == 0 is true, or
- each element of exts is representable as a nonnegative value of type index_type.
Postconditions: *this == extents(exts_arr) is true.
template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) extents(span<OtherIndexType, N> exts) noexcept;template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) extents(const array<OtherIndexType, N>& exts) noexcept;
Constraints:
- is_convertible_v<const OtherIndexType&, index_type> is true,
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and
- N == rank_dynamic() || N == rank() is true.
Preconditions:
- If N != rank_dynamic() is true,exts[r] equals for each r for which is a static extent, and
- either
- N is zero, or
- exts[r] is representable as a nonnegative value of type index_type for every rank index r.
Effects:
- If N equals rank_dynamic(), for all d in the range [0, rank_dynamic()), direct-non-list-initializes _dynamic-extents_[d]with as_const(exts[d]).
- Otherwise, for all d in the range [0, rank_dynamic()), direct-non-list-initializes _dynamic-extents_[d]with as_const(exts[dynamic-index-inv(d)]).
template<class... Integrals> explicit extents(Integrals...) -> _see below_;
Constraints: (is_convertible_v<Integrals, size_t> && ...) is true.
Remarks: The deduced type is extents<size_t, maybe-static-ext<Integrals>...>.
23.7.3.3.4 Observers of the multidimensional index space [mdspan.extents.obs]
static constexpr size_t static_extent(rank_type i) noexcept;
Preconditions: i < rank() is true.
constexpr index_type extent(rank_type i) const noexcept;
Preconditions: i < rank() is true.
23.7.3.3.5 Comparison operators [mdspan.extents.cmp]
template<class OtherIndexType, size_t... OtherExtents> friend constexpr bool operator==(const extents& lhs,const extents<OtherIndexType, OtherExtents...>& rhs) noexcept;
Returns: true if lhs.rank() equals rhs.rank() and if lhs.extent(r) equals rhs.extent(r)for every rank index r of rhs, otherwise false.
23.7.3.3.6 Alias template dextents [mdspan.extents.dextents]
template<class IndexType, size_t Rank> using dextents = _see below_;
Result: A type E that is a specialization of extentssuch that E::rank() == Rank && E::rank() == E::rank_dynamic() is true, andE::index_type denotes IndexType.
23.7.3.3.7 Alias template dims [mdspan.extents.dims]
template<size_t Rank, class IndexType = size_t> using dims = _see below_;
Result: A type E that is a specialization of extentssuch that E::rank() == Rank && E::rank() == E::rank_dynamic() is true, andE::index_type denotes IndexType.
23.7.3.4 Layout mapping [mdspan.layout]
23.7.3.4.1 General [mdspan.layout.general]
- M denotes a layout mapping class.
- m denotes a (possibly const) value of type M.
- i and j are packs of (possibly const) integers that are multidimensional indices in m.extents() ([mdspan.overview]).
[Note 1:
The type of each element of the packs can be a different integer type.
— _end note_] - r is a (possibly const) rank index of typename M::extents_type.
- is a pack of (possibly const) integers for which sizeof...() == M::extents_type::rank() is true, the element is equal to 1, and all other elements are equal to 0.
In [mdspan.layout.reqmts] through [mdspan.layout.stride]:
- Let is-mapping-of be the exposition-only variable template defined as follows:template<class Layout, class Mapping> constexpr bool is-mapping-of = is_same_v<typename Layout::template mapping<typename Mapping::extents_type>, Mapping>;
- Let is-layout-left-padded-mapping-of be the exposition-only variable template defined as follows:template<class Mapping> constexpr bool is-layout-left-padded-mapping-of = see below; where is-layout-left-padded-mapping-of<Mapping> is trueif and only if Mapping denotes a specialization of layout_left_padded<S>::mappingfor some value S of type size_t.
- Let is-layout-right-padded-mapping-of be the exposition-only variable template defined as follows:template<class Mapping> constexpr bool is-layout-right-padded-mapping-of = see below; where is-layout-right-padded-mapping-of<Mapping> is trueif and only if Mapping denotes a specialization of layout_right_padded<S>::mappingfor some value S of type size_t.
- For nonnegative integers x and y, let denote
- y if x is zero,
- otherwise, the least multiple of x that is greater than or equal to y.
23.7.3.4.2 Requirements [mdspan.layout.reqmts]
A type M meets the layout mapping requirements if
- M models copyable and equality_comparable,
- is_nothrow_move_constructible_v<M> is true,
- is_nothrow_move_assignable_v<M> is true,
- is_nothrow_swappable_v<M> is true, and
- the following types and expressions are well-formed and have the specified semantics.
Result: A type that is a specialization of extents.
Result: typename M::extents_type::index_type.
Result: typename M::extents_type::rank_type.
Result: A type MP that meets the layout mapping policy requirements ([mdspan.layout.policy.reqmts]) and for which is-mapping-of<MP, M> is true.
Result: const typename M::extents_type&
Result: typename M::index_type
Returns: A nonnegative integer less than numeric_limits<typename M::index_type>::max() and less than or equal to numeric_limits<size_t>::max().
m(i...) == m(static_cast<typename M::index_type>(i)...)
Result: typename M::index_type
Returns: If the size of the multidimensional index space m.extents() is 0, then 0, else 1 plus the maximum value of m(i...) for all i.
Returns: true only if for every i and j where (i != j || ...) is true,m(i...) != m(j...) is true.
[Note 1:
A mapping can return false even if the condition is met.
For certain layouts, it is possibly not feasible to determine efficiently whether the layout is unique.
— _end note_]
Returns: true only if for all k in the range [0, m.required_span_size())there exists an i such that m(i...) equals k.
[Note 2:
A mapping can return false even if the condition is met.
For certain layouts, it is possibly not feasible to determine efficiently whether the layout is exhaustive.
— _end note_]
Returns: true only if for every rank index r of m.extents() there exists an integer such that, for all i where is a multidimensional index in m.extents() ([mdspan.overview]),m((i + )...) - m(i...) equals .
[Note 3:
This implies that for a strided layout.
— _end note_]
[Note 4:
A mapping can return false even if the condition is met.
For certain layouts, it is possibly not feasible to determine efficiently whether the layout is strided.
— _end note_]
Preconditions: m.is_strided() is true.
Result: typename M::index_type
Returns: as defined in m.is_strided() above.
[Note 5:
It is not required for m.stride(r) to be well-formed if m.extents().rank() is zero, even if m.is_always_strided() is true.
— _end note_]
Returns: true only if m.is_unique() is truefor all possible objects m of type M.
[Note 6:
A mapping can return false even if the above condition is met.
For certain layout mappings, it is possibly not feasible to determine whether every instance is unique.
— _end note_]
M::is_always_exhaustive()
Returns: true only if m.is_exhaustive() is truefor all possible objects m of type M.
[Note 7:
A mapping can return false even if the above condition is met.
For certain layout mappings, it is possibly not feasible to determine whether every instance is exhaustive.
— _end note_]
Returns: true only if m.is_strided() is truefor all possible objects m of type M.
[Note 8:
A mapping can return false even if the above condition is met.
For certain layout mappings, it is possibly not feasible to determine whether every instance is strided.
— _end note_]
23.7.3.4.3 Layout mapping policy requirements [mdspan.layout.policy.reqmts]
A type MP meets the layout mapping policy requirements if for a type E that is a specialization of extents,MP::mapping<E> is valid and denotes a type Xthat meets the layout mapping requirements ([mdspan.layout.reqmts]), and for which the qualified-id X::layout_type is valid and denotes the type MP and the qualified-id X::extents_type denotes E.
23.7.3.4.4 Layout mapping policies [mdspan.layout.policy.overview]
namespace std { struct layout_left { template<class Extents> class mapping;};struct layout_right { template<class Extents> class mapping;};struct layout_stride { template<class Extents> class mapping;};template<size_t PaddingValue> struct layout_left_padded { template<class Extents> class mapping;};template<size_t PaddingValue> struct layout_right_padded { template<class Extents> class mapping;};}
Each of layout_left, layout_right, and layout_stride, as well as each specialization oflayout_left_padded and layout_right_padded, meets the layout mapping policy requirements and is a trivially copyable type.
Furthermore,is_trivially_default_constructible_v<T> is truefor any such type T.
23.7.3.4.5 Class template layout_left::mapping [mdspan.layout.left]
23.7.3.4.5.1 Overview [mdspan.layout.left.overview]
layout_left provides a layout mapping where the leftmost extent has stride 1, and strides increase left-to-right as the product of extents.
namespace std { template<class Extents> class layout_left::mapping { public: using extents_type = Extents;using index_type = extents_type::index_type;using size_type = extents_type::size_type;using rank_type = extents_type::rank_type;using layout_type = layout_left;constexpr mapping() noexcept = default;constexpr mapping(const mapping&) noexcept = default;constexpr mapping(const extents_type&) noexcept;template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const mapping<OtherExtents>&) noexcept;template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_right::mapping<OtherExtents>&) noexcept;template<class LayoutLeftPaddedMapping> constexpr explicit(!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type, extents_type>) mapping(const LayoutLeftPaddedMapping&) noexcept;template<class OtherExtents> constexpr explicit(see below) mapping(const layout_stride::mapping<OtherExtents>&);constexpr mapping& operator=(const mapping&) noexcept = default;constexpr const extents_type& extents() const noexcept { return extents_; } constexpr index_type required_span_size() const noexcept;template<class... Indices> constexpr index_type operator()(Indices...) const noexcept;static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type) const noexcept;template<class OtherExtents> friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept;private: extents_type extents_{}; template<class... SliceSpecifiers> constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const -> see below;template<class... SliceSpecifiers> friend constexpr auto submdspan_mapping( const mapping& src, SliceSpecifiers... slices) { return src.submdspan-mapping-impl(slices...);} };}
If Extents is not a specialization of extents, then the program is ill-formed.
layout_left::mapping<E> is a trivially copyable type that models regular for each E.
Mandates: If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents()is representable as a value of type typename Extents::index_type.
23.7.3.4.5.2 Constructors [mdspan.layout.left.cons]
constexpr mapping(const extents_type& e) noexcept;
Preconditions: The size of the multidimensional index space eis representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with e.
template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const mapping<OtherExtents>& other) noexcept;
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Preconditions: other.required_span_size() is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with other.extents().
template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_right::mapping<OtherExtents>& other) noexcept;
Constraints:
- extents_type::rank() <= 1 is true, and
- is_constructible_v<extents_type, OtherExtents> is true.
Preconditions: other.required_span_size() is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with other.extents().
template<class LayoutLeftPaddedMapping> constexpr explicit(!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type, extents_type>) mapping(const LayoutLeftPaddedMapping&) noexcept;
Constraints:
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping> is true.
- is_constructible_v<extents_type, typename LayoutLeftPaddedMapping::extents_type>
is true.
Mandates: If
- Extents::rank() is greater than one,
- Extents::static_extent(0) does not equal dynamic_extent, and
- LayoutLeftPaddedMapping::_static-padding-stride_does not equal dynamic_extent,
then Extents::static_extent(0) equalsLayoutLeftPaddedMapping::static-padding-stride.
Preconditions:
- If extents_type::rank() > 1 is true, then other.stride(1) equals other.extents().extent(0).
- other.required_span_size() is representable as a value of type index_type.
Effects: Direct-non-list-initializes extents_ with other.extents().
template<class OtherExtents> constexpr explicit(_see below_) mapping(const layout_stride::mapping<OtherExtents>& other);
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Preconditions:
- If extents_type::rank() > 0 is true, then for all r in the range [0, extents_type::rank()),other.stride(r) equalsother.extents().fwd-prod-of-extents(r), and
- other.required_span_size() is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with other.extents().
Remarks: The expression inside explicit is equivalent to:!(extents_type::rank() == 0 && is_convertible_v<OtherExtents, extents_type>)
23.7.3.4.5.3 Observers [mdspan.layout.left.obs]
constexpr index_type required_span_size() const noexcept;
Returns: extents().fwd-prod-of-extents(extents_type::rank()).
template<class... Indices> constexpr index_type operator()(Indices... i) const noexcept;
Constraints:
- sizeof...(Indices) == extents_type::rank() is true,
- (is_convertible_v<Indices, index_type> && ...) is true, and
- (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
Preconditions: extents_type::index-cast(i) is a multidimensional index in extents_ ([mdspan.overview]).
Effects: Let P be a parameter pack such thatis_same_v<index_sequence_for<Indices...>, index_sequence<P...>> is true.
Equivalent to:return ((static_cast<index_type>(i) * stride(P)) + ... + 0);
constexpr index_type stride(rank_type i) const noexcept;
Constraints: extents_type::rank() > 0 is true.
Preconditions: i < extents_type::rank() is true.
Returns: extents().fwd-prod-of-extents(i).
template<class OtherExtents> friend constexpr bool operator==(const mapping& x, const mapping<OtherExtents>& y) noexcept;
Constraints: extents_type::rank() == OtherExtents::rank() is true.
Effects: Equivalent to: return x.extents() == y.extents();
23.7.3.4.6 Class template layout_right::mapping [mdspan.layout.right]
23.7.3.4.6.1 Overview [mdspan.layout.right.overview]
layout_right provides a layout mapping where the rightmost extent is stride 1, and strides increase right-to-left as the product of extents.
namespace std { template<class Extents> class layout_right::mapping { public: using extents_type = Extents;using index_type = extents_type::index_type;using size_type = extents_type::size_type;using rank_type = extents_type::rank_type;using layout_type = layout_right;constexpr mapping() noexcept = default;constexpr mapping(const mapping&) noexcept = default;constexpr mapping(const extents_type&) noexcept;template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const mapping<OtherExtents>&) noexcept;template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_left::mapping<OtherExtents>&) noexcept;template<class LayoutRightPaddedMapping> constexpr explicit(!is_convertible_v<typename LayoutRightPaddedMapping::extents_type, extents_type>) mapping(const LayoutRightPaddedMapping&) noexcept;template<class OtherExtents> constexpr explicit(see below) mapping(const layout_stride::mapping<OtherExtents>&) noexcept;constexpr mapping& operator=(const mapping&) noexcept = default;constexpr const extents_type& extents() const noexcept { return extents_; } constexpr index_type required_span_size() const noexcept;template<class... Indices> constexpr index_type operator()(Indices...) const noexcept;static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type) const noexcept;template<class OtherExtents> friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept;private: extents_type extents_{}; template<class... SliceSpecifiers> constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const -> see below;template<class... SliceSpecifiers> friend constexpr auto submdspan_mapping( const mapping& src, SliceSpecifiers... slices) { return src.submdspan-mapping-impl(slices...);} };}
If Extents is not a specialization of extents, then the program is ill-formed.
layout_right::mapping<E> is a trivially copyable type that models regular for each E.
Mandates: If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents()is representable as a value of type typename Extents::index_type.
23.7.3.4.6.2 Constructors [mdspan.layout.right.cons]
constexpr mapping(const extents_type& e) noexcept;
Preconditions: The size of the multidimensional index space e is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with e.
template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const mapping<OtherExtents>& other) noexcept;
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Preconditions: other.required_span_size() is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with other.extents().
template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_left::mapping<OtherExtents>& other) noexcept;
Constraints:
- extents_type::rank() <= 1 is true, and
- is_constructible_v<extents_type, OtherExtents> is true.
Preconditions: other.required_span_size() is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with other.extents().
template<class LayoutRightPaddedMapping> constexpr explicit(!is_convertible_v<typename LayoutRightPaddedMapping::extents_type, extents_type>) mapping(const LayoutRightPaddedMapping&) noexcept;
Constraints:
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>is true.
- is_constructible_v<extents_type, typename LayoutRightPaddedMapping::extents_-
type>is true.
Mandates: If
- Extents::rank() is greater than one,
- Extents::static_extent(Extents::rank() - 1)does not equal dynamic_extent, and
- LayoutRightPaddedMapping::_static-padding-stride_does not equal dynamic_extent,
then Extents::static_extent(Extents::rank() - 1) equalsLayoutRightPaddedMapping::static-padding-stride.
Preconditions:
- If extents_type::rank() > 1 is true, then other.stride(extents_type::rank() - 2)
equalsother.extents().extent(extents_type::rank() - 1). - other.required_span_size() is representable as a value of type index_type.
Effects: Direct-non-list-initializes extents_ with other.extents().
template<class OtherExtents> constexpr explicit(_see below_) mapping(const layout_stride::mapping<OtherExtents>& other) noexcept;
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Preconditions:
- If extents_type::rank() > 0 is true, then for all r in the range [0, extents_type::rank()),other.stride(r) equalsother.extents()._rev-prod-of-extents_(r).
Effects: Direct-non-list-initializes extents_ with other.extents().
Remarks: The expression inside explicit is equivalent to:!(extents_type::rank() == 0 && is_convertible_v<OtherExtents, extents_type>)
23.7.3.4.6.3 Observers [mdspan.layout.right.obs]
constexpr index_type required_span_size() const noexcept;
Returns: extents().fwd-prod-of-extents(extents_type::rank()).
template<class... Indices> constexpr index_type operator()(Indices... i) const noexcept;
Constraints:
- sizeof...(Indices) == extents_type::rank() is true,
- (is_convertible_v<Indices, index_type> && ...) is true, and
- (is_nothrow_constructible_v<index_type, Indices> && ...) istrue.
Preconditions: extents_type::index-cast(i) is a multidimensional index in extents_ ([mdspan.overview]).
Effects: Let P be a parameter pack such thatis_same_v<index_sequence_for<Indices...>, index_sequence<P...>> is true.
Equivalent to:return ((static_cast<index_type>(i) * stride(P)) + ... + 0);
constexpr index_type stride(rank_type i) const noexcept;
Constraints: extents_type::rank() > 0 is true.
Preconditions: i < extents_type::rank() is true.
Returns: extents().rev-prod-of-extents(i).
template<class OtherExtents> friend constexpr bool operator==(const mapping& x, const mapping<OtherExtents>& y) noexcept;
Constraints: extents_type::rank() == OtherExtents::rank() is true.
Effects: Equivalent to: return x.extents() == y.extents();
23.7.3.4.7 Class template layout_stride::mapping [mdspan.layout.stride]
23.7.3.4.7.1 Overview [mdspan.layout.stride.overview]
layout_stride provides a layout mapping where the strides are user-defined.
namespace std { template<class Extents> class layout_stride::mapping { public: using extents_type = Extents;using index_type = extents_type::index_type;using size_type = extents_type::size_type;using rank_type = extents_type::rank_type;using layout_type = layout_stride;private: static constexpr rank_type rank_ = extents_type::rank(); public: constexpr mapping() noexcept;constexpr mapping(const mapping&) noexcept = default;template<class OtherIndexType> constexpr mapping(const extents_type&, span<OtherIndexType, _rank__>) noexcept;template<class OtherIndexType> constexpr mapping(const extents_type&, const array<OtherIndexType, _rank__>&) noexcept;template<class StridedLayoutMapping> constexpr explicit(see below) mapping(const StridedLayoutMapping&) noexcept;constexpr mapping& operator=(const mapping&) noexcept = default;constexpr const extents_type& extents() const noexcept { return extents_; } constexpr array<index_type, _rank__> strides() const noexcept { return strides_; } constexpr index_type required_span_size() const noexcept;template<class... Indices> constexpr index_type operator()(Indices...) const noexcept;static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept;static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } constexpr bool is_exhaustive() const noexcept;static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type i) const noexcept { return _strides__[i]; } template<class OtherMapping> friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept;private: extents_type extents_{}; array<index_type, _rank__> strides_{}; template<class... SliceSpecifiers> constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const -> see below;template<class... SliceSpecifiers> friend constexpr auto submdspan_mapping( const mapping& src, SliceSpecifiers... slices) { return src.submdspan-mapping-impl(slices...);} };}
If Extents is not a specialization of extents, then the program is ill-formed.
layout_stride::mapping<E> is a trivially copyable type that models regular for each E.
Mandates: If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents()is representable as a value of type typename Extents::index_type.
23.7.3.4.7.2 Exposition-only helpers [mdspan.layout.stride.expo]
Let REQUIRED-SPAN-SIZE(e, strides) be:
- 1, if e.rank() == 0 is true,
- otherwise 0, if the size of the multidimensional index space e is 0,
- otherwise 1 plus the sum of products of(e.extent(r) - 1) andextents_type::index-cast(strides[r]) for all r in the range [0, e.rank()).
Let OFFSET(m) be:
- m(), if e.rank() == 0 is true,
- otherwise 0, if the size of the multidimensional index space e is 0,
- otherwise m(z...) for a pack of integers zthat is a multidimensional index in m.extents() and each element of z equals 0.
Let is-extents be the exposition-only variable template defined as follows:template<class T> constexpr bool is-extents = false; template<class IndexType, size_t... Args> constexpr bool is-extents<extents<IndexType, Args...>> = true;
Let layout-mapping-alike be the exposition-only concept defined as follows:template<class M> concept layout-mapping-alike = requires { requires is-extents<typename M::extents_type>;{ M::is_always_strided() } -> same_as<bool>;{ M::is_always_exhaustive() } -> same_as<bool>;{ M::is_always_unique() } -> same_as<bool>; bool_constant<M::is_always_strided()>::value; bool_constant<M::is_always_exhaustive()>::value; bool_constant<M::is_always_unique()>::value;};
[Note 1:
This concept checks that the functionsM::is_always_strided(),M::is_always_exhaustive(), andM::is_always_unique() exist, are constant expressions, and have a return type of bool.
— _end note_]
23.7.3.4.7.3 Constructors [mdspan.layout.stride.cons]
constexpr mapping() noexcept;
Preconditions: layout_right::mapping<extents_type>().required_span_size()is representable as a value of type index_type ([basic.fundamental]).
Effects: Direct-non-list-initializes extents_ with extents_type(), and for all d in the range [0, rank_), direct-non-list-initializes _strides__[d] withlayout_right::mapping<extents_type>().stride(d).
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;
Constraints:
- is_convertible_v<const OtherIndexType&, index_type> is true, and
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true.
Preconditions:
- The result of converting s[i] to index_typeis greater than 0for all i in the range [0, _rank__).
- If rank_ is greater than 0, then there exists a permutation P of the integers in the range [0, rank_), such that s[] >= s[] * e.extent(p) is truefor all i in the range [1, rank__), where is the element of P.
[_Note 1:
For layout_stride, this condition is necessary and sufficient for is_unique() to be true.
— _end note_]
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]).
template<class StridedLayoutMapping> constexpr explicit(_see below_) mapping(const StridedLayoutMapping& other) noexcept;
Constraints:
- layout-mapping-alike<StridedLayoutMapping> is satisfied.
- is_constructible_v<extents_type, typename StridedLayoutMapping::extents_type> is
true. - StridedLayoutMapping::is_always_unique() is true.
- StridedLayoutMapping::is_always_strided() is true.
Preconditions:
- StridedLayoutMapping meets the layout mapping requirements ([mdspan.layout.reqmts]),
- other.stride(r) > 0 is truefor every rank index r of extents(),
- other.required_span_size() is representable as a value of type index_type ([basic.fundamental]), and
- OFFSET(other) == 0 is true.
Effects: Direct-non-list-initializes extents_ with other.extents(), and for all d in the range [0, rank_), direct-non-list-initializes _strides__[d]with other.stride(d).
Remarks: The expression inside explicit is equivalent to:!(is_convertible_v<typename StridedLayoutMapping::extents_type, extents_type> && (is-mapping-of<layout_left, StridedLayoutMapping> || is-mapping-of<layout_right, StridedLayoutMapping> || is-layout-left-padded-mapping-of<StridedLayoutMapping> || is-layout-right-padded-mapping-of<StridedLayoutMapping> || is-mapping-of<layout_stride, StridedLayoutMapping>))
23.7.3.4.7.4 Observers [mdspan.layout.stride.obs]
constexpr index_type required_span_size() const noexcept;
Returns: REQUIRED-SPAN-SIZE(extents(), strides_).
template<class... Indices> constexpr index_type operator()(Indices... i) const noexcept;
Constraints:
- sizeof...(Indices) == rank_ is true,
- (is_convertible_v<Indices, index_type> && ...) is true, and
- (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
Preconditions: extents_type::index-cast(i) is a multidimensional index in extents_ ([mdspan.overview]).
Effects: Let P be a parameter pack such thatis_same_v<index_sequence_for<Indices...>, index_sequence<P...>> is true.
Equivalent to:return ((static_cast<index_type>(i) * stride(P)) + ... + 0);
static constexpr bool is_always_exhaustive() noexcept;
Returns: true if rank_ is 0 or if there is a rank index r of extents()such that extents_type::static_extent(r) is 0, otherwise false.
constexpr bool is_exhaustive() const noexcept;
Returns:
- true if rank_ or the size of the multidimensional index spacem.extents() is 0.
- Otherwise, true if there is a permutation P of the integers in the range [0, _rank__)such that stride() equals 1, andstride() equals stride() * extents().extent()for i in the range [1, _rank__), where is the element of P.
template<class OtherMapping> friend constexpr bool operator==(const mapping& x, const OtherMapping& y) noexcept;
Constraints:
- layout-mapping-alike<OtherMapping> is satisfied.
- rank_ == OtherMapping::extents_type::rank() is true.
- OtherMapping::is_always_strided() is true.
Preconditions: OtherMapping meets the layout mapping requirements ([mdspan.layout.policy.reqmts]).
Returns: true if x.extents() == y.extents() is true,OFFSET(y) == 0 is true, and each of x.stride(r) == y.stride(r) is truefor r in the range [0, x.extents().rank()).
Otherwise, false.
23.7.3.4.8 Class template layout_left_padded::mapping [mdspan.layout.leftpad]
23.7.3.4.8.1 Overview [mdspan.layout.leftpad.overview]
layout_left_padded provides a layout mapping that behaves like layout_left::mapping, except that the padding stride stride(1)can be greater than or equal to extent(0).
namespace std { template<size_t PaddingValue> template<class Extents> class layout_left_padded<PaddingValue>::mapping { public: static constexpr size_t padding_value = PaddingValue;using extents_type = Extents;using index_type = extents_type::index_type;using size_type = extents_type::size_type;using rank_type = extents_type::rank_type;using layout_type = layout_left_padded<PaddingValue>;private: static constexpr size_t rank_ = extents_type::rank(); static constexpr size_t first-static-extent = extents_type::static_extent(0);static constexpr size_t static-padding-stride = see below; public: constexpr mapping() noexcept : mapping(extents_type{}) {} constexpr mapping(const mapping&) noexcept = default;constexpr mapping(const extents_type&);template<class OtherIndexType> constexpr mapping(const extents_type&, OtherIndexType);template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_left::mapping<OtherExtents>&);template<class OtherExtents> constexpr explicit(see below) mapping(const layout_stride::mapping<OtherExtents>&);template<class LayoutLeftPaddedMapping> constexpr explicit(see below) mapping(const LayoutLeftPaddedMapping&);template<class LayoutRightPaddedMapping> constexpr explicit(see below) mapping(const LayoutRightPaddedMapping&) noexcept;constexpr mapping& operator=(const mapping&) noexcept = default;constexpr const extents_type& extents() const noexcept { return extents_; } constexpr array<index_type, rank_> strides() const noexcept;constexpr index_type required_span_size() const noexcept;template<class... Indices> constexpr index_type operator()(Indices...) const noexcept;static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept;static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } constexpr bool is_exhaustive() const noexcept;static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type) const noexcept;template<class LayoutLeftPaddedMapping> friend constexpr bool operator==(const mapping&, const LayoutLeftPaddedMapping&) noexcept;private: index_type stride-1 = static-padding-stride; extents_type extents_{}; template<class... SliceSpecifiers> constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const -> see below;template<class... SliceSpecifiers> friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) { return src.submdspan-mapping-impl(slices...);} };}
If Extents is not a specialization of extents, then the program is ill-formed.
layout_left_padded::mapping<E> is a trivially copyable type that models regular for each E.
Throughout [mdspan.layout.leftpad], let P_rank be the following size rank_ parameter pack of size_t values:
- the empty parameter pack, if rank_ equals zero;
- otherwise, 0zu, if rank_ equals one;
- otherwise, the parameter pack 0zu, 1zu, …, _rank__- 1.
Mandates:
- If rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents()is representable as a value of type index_type.
- If padding_value is not equal to dynamic_extent, thenpadding_value is representable as a value of type index_type.
- If
- rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- first-static-extent does not equal dynamic_extent,
then LEAST-MULTIPLE-AT-LEAST(padding_value, first-static-extent)is representable as a value of type size_t, and is representable as a value of type index_type.
- If
- rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- extents_type::static_extent(k) does not equal dynamic_extentfor all k in the range [0, extents_type::rank()),
then the product of_LEAST-MULTIPLE-AT-LEAST_(padding_value, ext.static_extent(0)) and all values ext.static_extent(k)with k in the range of [1, _rank__) is representable as a value of type size_t, and is representable as a value of type index_type.
23.7.3.4.8.2 Exposition-only members [mdspan.layout.leftpad.expo]
static constexpr size_t _static-padding-stride_ = _see below_;
The value is
- 0, if rank_ equals zero or one;
- otherwise, dynamic_extent, if padding_value or first-static-extent equalsdynamic_extent;
- otherwise, the size_t value which is_LEAST-MULTIPLE-AT-LEAST_(padding_value, first-static-extent).
index_type _stride-1_ = _static-padding-stride_;
Recommended practice: Implementations should not store this value if static-padding-stride is not dynamic_extent.
[Note 1:
Using extents<index_type, _static-padding-stride_> instead ofindex_type as the type of stride-1 would achieve this.
— _end note_]
23.7.3.4.8.3 Constructors [mdspan.layout.leftpad.cons]
constexpr mapping(const extents_type& ext);
Preconditions:
- The size of the multidimensional index space ext is representable as a value of type index_type.
- If rank_ is greater than one andpadding_value does not equal dynamic_extent, then LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(0))is representable as a value of type index_type.
- If rank_ is greater than one andpadding_value does not equal dynamic_extent, then the product of_LEAST-MULTIPLE-AT-LEAST_(padding_value, ext.extent(0)) and all values ext.extent(k)with k in the range of [1, _rank__) is representable as a value of type index_type.
Effects:
- Direct-non-list-initializes extents_ with ext; and
- if rank_ is greater than one, direct-non-list-initializes stride-1
- with ext.extent(0) if padding_value is dynamic_extent,
- otherwise with_LEAST-MULTIPLE-AT-LEAST_(padding_value, ext.extent(0)).
template<class OtherIndexType> constexpr mapping(const extents_type& ext, OtherIndexType pad);
Constraints:
- is_convertible_v<OtherIndexType, index_type> is true.
- is_nothrow_constructible_v<index_type, OtherIndexType> is true.
Preconditions:
- pad is representable as a value of type index_type.
- extents_type::index-cast(pad) is greater than zero.
- If rank_ is greater than one, then LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(0))is representable as a value of type index_type.
- If rank_ is greater than one, then the product of_LEAST-MULTIPLE-AT-LEAST_(pad, ext.extent(0)) and all values ext.extent(k)with k in the range of [1, _rank__) is representable as a value of type index_type.
- If padding_value is not equal to dynamic_extent,padding_value equals extents_type::index-cast(pad).
Effects: Direct-non-list-initializes extents_ with ext, and if rank_ is greater than one, direct-non-list-initializes stride-1 with_LEAST-MULTIPLE-AT-LEAST_(pad, ext.extent(0)).
template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_left::mapping<OtherExtents>& other);
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Mandates: If OtherExtents::rank() is greater than 1, then(static-padding-stride == dynamic_extent) || (OtherExtents::static_extent(0) == dynamic_extent) || (static-padding-stride == OtherExtents::static_extent(0)) is true.
Preconditions:
- If extents_type::rank() > 1 is true andpadding_value == dynamic_extent is false, then other.stride(1) equals_LEAST-MULTIPLE-AT-LEAST_(padding_value, extents_type::index-cast(other.extents().extent(0))) and
- other.required_span_size() is representable as a value of type index_type.
Effects: Equivalent to mapping(other.extents()).
template<class OtherExtents> constexpr explicit(_see below_) mapping(const layout_stride::mapping<OtherExtents>& other);
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Preconditions:
- If rank_ is greater than 1 andpadding_value does not equal dynamic_extent, then other.stride(1) equals_LEAST-MULTIPLE-AT-LEAST_(padding_value, extents_type::index-cast(other.extents().extent(0)))
- If rank_ is greater than 0, then other.stride(0) equals 1.
- If rank_ is greater than 2, then for all r in the range [2, rank_),other.stride(r) equals(other.extents().fwd-prod-of-extents(r) / other.extents().extent(0)) * other.stride(1)
- other.required_span_size() is representable as a value of type index_type.
Effects:
- Direct-non-list-initializes extents_ with other.extents() and
- if rank_ is greater than one, direct-non-list-initializes stride-1 withother.stride(1).
Remarks: The expression inside explicit is equivalent to:!(rank_ == 0 && is_convertible_v<OtherExtents, extents_type>)
template<class LayoutLeftPaddedMapping> constexpr explicit(_see below_) mapping(const LayoutLeftPaddedMapping& other);
Constraints:
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>is true.
- is_constructible_v<extents_type, typename LayoutLeftPaddedMapping::extents_type>
is true.
Mandates: If rank_ is greater than 1, thenpadding_value == dynamic_extent ||LayoutLeftPaddedMapping::padding_value == dynamic_extent ||padding_value == LayoutLeftPaddedMapping::padding_valueis true.
Preconditions:
- If rank_ is greater than 1 andpadding_value does not equal dynamic_extent, then other.stride(1) equals_LEAST-MULTIPLE-AT-LEAST_(padding_value, extents_type::index-cast(other.extent(0)))
- other.required_span_size() is representable as a value of type index_type.
Effects:
- Direct-non-list-initializes extents_ with other.extents() and
- if rank_ is greater than one, direct-non-list-initializes stride-1 with other.stride(1).
Remarks: The expression inside explicit is equivalent to:!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type, extents_type> ||rank_> 1 && (padding_value != dynamic_extent || LayoutLeftPaddedMapping::padding_value == dynamic_extent)
template<class LayoutRightPaddedMapping> constexpr explicit(_see below_) mapping(const LayoutRightPaddedMapping& other) noexcept;
Constraints:
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>is true or
is-mapping-of<layout_right, LayoutRightPaddedMapping>is true. - rank_ equals zero or one.
- is_constructible_v<extents_type, typename LayoutRightPaddedMapping::extents_-
type>is true.
Preconditions: other.required_span_size() is representable as a value of type index_type.
Effects: Direct-non-list-initializes extents_ with other.extents().
Remarks: The expression inside explicit is equivalent to:!is_convertible_v<typename LayoutRightPaddedMapping::extents_type, extents_type>
[Note 1:
Neither the input mapping nor the mapping to be constructed uses the padding stride in the rank-0 or rank-1 case, so the padding stride does not affect either the constraints or the preconditions.
— _end note_]
23.7.3.4.8.4 Observers [mdspan.layout.leftpad.obs]
constexpr array<index_type, _rank_> strides() const noexcept;
Returns: array<index_type, _rank__>({stride(P_rank)...}).
constexpr index_type required_span_size() const noexcept;
Returns:
- 0 if the multidimensional index space extents_ is empty,
- otherwise, (*this)(extents_.extent(P_rank) - index_type(1)...) + 1.
template<class... Indices> constexpr size_t operator()(Indices... idxs) const noexcept;
Constraints:
- sizeof...(Indices) == rank_ is true.
- (is_convertible_v<Indices, index_type> && ...) is true.
- (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
Preconditions: extents_type::index-cast(idxs) is a multidimensional index in extents() ([mdspan.overview]).
Returns: ((static_cast<index_type>(idxs) * stride(P_rank)) + ... + 0).
static constexpr bool is_always_exhaustive() noexcept;
Returns:
- If rank_ equals zero or one, then true;
- otherwise, if neither static-padding-stride nor _first-static-extent_equal dynamic_extent, then static-padding-stride == first-static-extent;
- otherwise, false.
constexpr bool is_exhaustive() const noexcept;
Returns: true if rank_ equals zero or one; otherwise, extents_.extent(0) == stride(1).
constexpr index_type stride(rank_type r) const noexcept;
Preconditions: r is smaller than rank_.
Returns:
- If r equals zero: 1;
- otherwise, if r equals one: stride-1;
- otherwise, the product of stride-1 and all values extents_.extent(k) with k in the range [1, r).
template<class LayoutLeftPaddedMapping> friend constexpr bool operator==(const mapping& x, const LayoutLeftPaddedMapping& y) noexcept;
Constraints:
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>is true.
- LayoutLeftPaddedMapping::extents_type::rank() == rank_ is true.
Returns: true if x.extents() == y.extents() is true and_rank__ < 2 || x.stride(1) == y.
stride(1) is true.
Otherwise, false.
23.7.3.4.9 Class template layout_right_padded::mapping [mdspan.layout.rightpad]
23.7.3.4.9.1 Overview [mdspan.layout.rightpad.overview]
layout_right_padded provides a layout mapping that behaves like layout_right::mapping, except that the padding stride stride(extents_type::rank() - 2)can be greater than or equal toextents_type::extent(extents_type::rank() - 1).
namespace std { template<size_t PaddingValue> template<class Extents> class layout_right_padded<PaddingValue>::mapping { public: static constexpr size_t padding_value = PaddingValue;using extents_type = Extents;using index_type = extents_type::index_type;using size_type = extents_type::size_type;using rank_type = extents_type::rank_type;using layout_type = layout_right_padded<PaddingValue>;private: static constexpr size_t rank_ = extents_type::rank(); static constexpr size_t last-static-extent = extents_type::static_extent(rank_ - 1);static constexpr size_t static-padding-stride = see below; public: constexpr mapping() noexcept : mapping(extents_type{}) {} constexpr mapping(const mapping&) noexcept = default;constexpr mapping(const extents_type&);template<class OtherIndexType> constexpr mapping(const extents_type&, OtherIndexType);template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_right::mapping<OtherExtents>&);template<class OtherExtents> constexpr explicit(see below) mapping(const layout_stride::mapping<OtherExtents>&);template<class LayoutRightPaddedMapping> constexpr explicit(see below) mapping(const LayoutRightPaddedMapping&);template<class LayoutLeftPaddedMapping> constexpr explicit(see below) mapping(const LayoutLeftPaddedMapping&) noexcept;constexpr mapping& operator=(const mapping&) noexcept = default;constexpr const extents_type& extents() const noexcept { return extents_; } constexpr array<index_type, rank_> strides() const noexcept;constexpr index_type required_span_size() const noexcept;template<class... Indices> constexpr index_type operator()(Indices...) const noexcept;static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept;static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } constexpr bool is_exhaustive() const noexcept;static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type) const noexcept;template<class LayoutRightPaddedMapping> friend constexpr bool operator==(const mapping&, const LayoutRightPaddedMapping&) noexcept;private: index_type stride-rm2 = static-padding-stride; extents_type extents_{}; template<class... SliceSpecifiers> constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const -> see below;template<class... SliceSpecifiers> friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) { return src.submdspan-mapping-impl(slices...);} };}
If Extents is not a specialization of extents, then the program is ill-formed.
layout_right_padded::mapping<E> is a trivially copyable type that models regular for each E.
Throughout [mdspan.layout.rightpad], let P_rank be the following size rank_ parameter pack of size_t values:
- the empty parameter pack, if rank_ equals zero;
- otherwise, 0zu, if rank_ equals one;
- otherwise, the parameter pack 0zu, 1zu, …, _rank__- 1.
Mandates:
- If rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents()is representable as a value of type index_type.
- If padding_value is not equal to dynamic_extent, thenpadding_value is representable as a value of type index_type.
- If
- rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- last-static-extent does not equal dynamic_extent,
then LEAST-MULTIPLE-AT-LEAST(padding_value, last-static-extent)is representable as a value of type size_t, and is representable as a value of type index_type.
- If
- rank_ is greater than one,
- padding_value does not equal dynamic_extent, and
- extents_type::static_extent(k) does not equal dynamic_extentfor all k in the range [0, _rank__),
then the product of_LEAST-MULTIPLE-AT-LEAST_(padding_value, ext.static_extent(_rank__ - 1)) and all values ext.static_extent(k)with k in the range of [0, _rank__ - 1) is representable as a value of type size_t, and is representable as a value of type index_type.
23.7.3.4.9.2 Exposition-only members [mdspan.layout.rightpad.expo]
static constexpr size_t _static-padding-stride_ = _see below_;
The value is
- 0, if rank_ equals zero or one;
- otherwise, dynamic_extent, if padding_value or last-static-extent equalsdynamic_extent;
- otherwise, the size_t value which is_LEAST-MULTIPLE-AT-LEAST_(padding_value, last-static-extent).
index_type _stride-rm2_ = _static-padding-stride_;
Recommended practice: Implementations should not store this value if static-padding-stride is not dynamic_extent.
[Note 1:
Using extents<index_type, _static-padding-stride_>instead of index_type as the type of _stride-rm2_would achieve this.
— _end note_]
23.7.3.4.9.3 Constructors [mdspan.layout.rightpad.cons]
constexpr mapping(const extents_type& ext);
Preconditions:
- The size of the multidimensional index space extis representable as a value of type index_type.
- If rank_ is greater than one andpadding_value does not equal dynamic_extent, then LEAST-MULTIPLE-AT-LEAST(padding_value, ext.extent(rank_ - 1))is representable as a value of type index_type.
- If rank_ is greater than one andpadding_value does not equal dynamic_extent, then the product of_LEAST-MULTIPLE-AT-LEAST_(padding_value, ext.extent(rank_ - 1)) and all values ext.extent(k)with k in the range of [0, _rank__ - 1) is representable as a value of type index_type.
Effects:
- Direct-non-list-initializes extents_ with ext; and
- if rank_ is greater than one, direct-non-list-initializes stride-rm2
- with ext.extent(rank_ - 1)if padding_value is dynamic_extent,
- otherwise with_LEAST-MULTIPLE-AT-LEAST_(padding_value, ext.extent(rank_ - 1)).
template<class OtherIndexType> constexpr mapping(const extents_type& ext, OtherIndexType pad);
Constraints:
- is_convertible_v<OtherIndexType, index_type> is true.
- is_nothrow_constructible_v<index_type, OtherIndexType> is true.
Preconditions:
- pad is representable as a value of type index_type.
- extents_type::index-cast(pad) is greater than zero.
- If rank_ is greater than one, then LEAST-MULTIPLE-AT-LEAST(pad, ext.extent(rank_ - 1))is representable as a value of type index_type.
- If rank_ is greater than one, then the product of_LEAST-MULTIPLE-AT-LEAST_(pad, ext.extent(rank_ - 1)) and all values ext.extent(k)with k in the range of [0, _rank__ - 1) is representable as a value of type index_type.
- If padding_value is not equal to dynamic_extent,padding_value equals extents_type::index-cast(pad).
Effects: Direct-non-list-initializes extents_ with ext, and if rank_ is greater than one, direct-non-list-initializes stride-rm2 with_LEAST-MULTIPLE-AT-LEAST_(pad, ext.extent(rank_ - 1)).
template<class OtherExtents> constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) mapping(const layout_right::mapping<OtherExtents>& other);
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Mandates: If OtherExtents::rank() is greater than 1, then(static-padding-stride == dynamic_extent) || (OtherExtents::static_extent(rank_ - 1) == dynamic_extent) || (static-padding-stride == OtherExtents::static_extent(rank_ - 1)) is true.
Preconditions:
- If rank_ > 1 is true andpadding_value == dynamic_extent is false, thenother.stride(
rank_ - 2) equals_LEAST-MULTIPLE-AT-LEAST_(padding_value, extents_type::index-cast(other.extents().extent(rank_ - 1))) and - other.required_span_size() is representable as a value of type index_type.
Effects: Equivalent to mapping(other.extents()).
template<class OtherExtents> constexpr explicit(_see below_) mapping(const layout_stride::mapping<OtherExtents>& other);
Constraints: is_constructible_v<extents_type, OtherExtents> is true.
Preconditions:
- If rank_ is greater than 1 andpadding_value does not equal dynamic_extent, then other.stride(rank_ - 2) equals_LEAST-MULTIPLE-AT-LEAST_(padding_value, extents_type::index-cast(other.extents().extent(rank_ - 1)))
- If rank_ is greater than 0, then other.stride(rank_ - 1) equals 1.
- If rank_ is greater than 2, then for all r in the range [0, rank_ - 2),other.stride(r) equals(other.extents().rev-prod-of-extents(r) / other.extents().extent(rank_ - 1)) * other.stride(rank_ - 2)
- other.required_span_size() is representable as a value of type index_type.
Effects:
- Direct-non-list-initializes extents_ with other.extents(); and
- if rank_ is greater than one, direct-non-list-initializes _stride-rm2_with other.stride(rank_ - 2).
Remarks: The expression inside explicit is equivalent to:!(rank_ == 0 && is_convertible_v<OtherExtents, extents_type>)
template<class LayoutRightPaddedMapping> constexpr explicit(_see below_) mapping(const LayoutRightPaddedMapping& other);
Constraints:
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>is true.
- is_constructible_v<extents_type, typename LayoutRightPaddedMapping::extents_-
type>is true.
Mandates: If rank_ is greater than 1, thenpadding_value == dynamic_extent ||LayoutRightPaddedMapping::padding_value == dynamic_extent ||padding_value == LayoutRightPaddedMapping::padding_valueis true.
Preconditions:
- If rank_ is greater than 1 andpadding_value does not equal dynamic_extent, then other.stride(rank_ - 2) equals_LEAST-MULTIPLE-AT-LEAST_(padding_value, extents_type::index-cast(other.extent(rank_ - 1)))
- other.required_span_size() is representable as a value of type index_type.
Effects:
- Direct-non-list-initializes extents_ with other.extents(); and
- if rank_ is greater than one, direct-non-list-initializes _stride-rm2_with other.stride(rank_ - 2).
Remarks: The expression inside explicit is equivalent to:!is_convertible_v<typename LayoutRightPaddedMapping::extents_type, extents_type> || rank_ > 1 && (padding_value != dynamic_extent || LayoutRightPaddedMapping::padding_value == dynamic_extent)
template<class LayoutLeftPaddedMapping> constexpr explicit(_see below_) mapping(const LayoutLeftPaddedMapping& other) noexcept;
Constraints:
- is-layout-left-padded-mapping-of<LayoutLeftPaddedMapping>is true or
is-mapping-of<layout_left, LayoutLeftPaddedMapping>is true. - rank_ equals zero or one.
- is_constructible_v<extents_type, typename LayoutLeftPaddedMapping::extents_type>
is true.
Preconditions: other.required_span_size() is representable as a value of type index_type.
Effects: Direct-non-list-initializes extents_ with other.extents().
Remarks: The expression inside explicit is equivalent to:!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type, extents_type>
[Note 1:
Neither the input mapping nor the mapping to be constructed uses the padding stride in the rank-0 or rank-1 case, so the padding stride affects neither the constraints nor the preconditions.
— _end note_]
23.7.3.4.9.4 Observers [mdspan.layout.rightpad.obs]
constexpr array<index_type, _rank_> strides() const noexcept;
Returns: array<index_type, _rank__>(stride(P_rank)...).
constexpr index_type required_span_size() const noexcept;
Returns: 0 if the multidimensional index space extents_ is empty, otherwise (*this)(extents_.extent(P_rank) - index_type(1)...) + 1.
template<class... Indices> constexpr size_t operator()(Indices... idxs) const noexcept;
Constraints:
- sizeof...(Indices) == rank_ is true.
- (is_convertible_v<Indices, index_type> && ...) is true.
- (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
Preconditions: extents_type::index-cast(idxs) is a multidimensional index in extents() ([mdspan.overview]).
Returns: ((static_cast<index_type>(idxs) * stride(P_rank)) + ... + 0).
static constexpr bool is_always_exhaustive() noexcept;
Returns:
- If rank_ equals zero or one, then true;
- otherwise, if neither static-padding-stride nor _last-static-extent_equal dynamic_extent, then static-padding-stride == last-static-extent;
- otherwise, false.
constexpr bool is_exhaustive() const noexcept;
Returns: true if rank_ equals zero or one; otherwise,extents_.extent(rank_ - 1) == stride(rank_ - 2)
constexpr index_type stride(rank_type r) const noexcept;
Preconditions: r is smaller than rank_.
Returns:
- If r equals rank_ - 1: 1;
- otherwise, if r equals rank_ - 2: stride-rm2;
- otherwise, the product of stride-rm2 and all values extents_.extent(k)with k in the range of [r + 1, _rank__ - 1).
template<class LayoutRightPaddedMapping> friend constexpr bool operator==(const mapping& x, const LayoutRightPaddedMapping& y) noexcept;
Constraints:
- is-layout-right-padded-mapping-of<LayoutRightPaddedMapping>is true.
- LayoutRightPaddedMapping::extents_type::rank() == _rank__is true.
Returns: true if x.extents() == y.extents() is true and_rank__ < 2 || x.stride(rank_ - 2) == y.stride(rank_ - 2) is true.
Otherwise, false.
23.7.3.5 Accessor policy [mdspan.accessor]
23.7.3.5.1 General [mdspan.accessor.general]
An accessor policy defines types and operations by which a reference to a single object is created from an abstract data handle to a number of such objects and an index.
A range of indices is an accessible range of a given data handle and an accessor if, for each i in the range, the accessor policy's access function produces a valid reference to an object.
- A denotes an accessor policy.
- a denotes a value of type A or const A.
- p denotes a value of type A::data_handle_type or const A::data_handle_type.
[Note 1:
The type A::data_handle_type need not be dereferenceable.
— _end note_] - n, i, and j each denote values of type size_t.
23.7.3.5.2 Requirements [mdspan.accessor.reqmts]
A type A meets the accessor policy requirements if
- A models copyable,
- is_nothrow_move_constructible_v<A> is true,
- is_nothrow_move_assignable_v<A> is true,
- is_nothrow_swappable_v<A> is true, and
- the following types and expressions are well-formed and have the specified semantics.
Result: A complete object type that is not an abstract class type.
typename A::data_handle_type
Result: A type that models copyable, and for which is_nothrow_move_constructible_v<A::data_handle_type> is true,is_nothrow_move_assignable_v<A::data_handle_type> is true, andis_nothrow_swappable_v<A::data_handle_type> is true.
[Note 1:
The type of data_handle_type need not be element_type*.
— _end note_]
Result: A type that modelscommon_reference_with<A::reference&&, A::element_type&>.
[Note 2:
The type of reference need not be element_type&.
— _end note_]
typename A::offset_policy
Result: A type OP such that:
- OP meets the accessor policy requirements,
- constructible_from<OP, const A&> is modeled, and
- is_same_v<typename OP::element_type, typename A::element_type> is true.
Remarks: The expression is equality preserving.
[Note 3:
Concrete accessor policies can impose preconditions for their access function.
However, they might not.
For example, an accessor wherep is span<A::element_type, dynamic_extent> andaccess(p, i) returns p[i % p.size()]does not need to impose a precondition on i.
— _end note_]
Result: A::offset_policy::data_handle_type
Returns: q such that for b being A::offset_policy(a), and any integer n for which [0, n) is an accessible range of p and a:
- is an accessible range of q and b; and
- b.access(q, j) provides access to the same element as a.access(p, i + j), for every j in the range .
Remarks: The expression is equality-preserving.
23.7.3.5.3 Class template default_accessor [mdspan.accessor.default]
23.7.3.5.3.1 Overview [mdspan.accessor.default.overview]
namespace std { template<class ElementType> struct default_accessor { using offset_policy = default_accessor;using element_type = ElementType;using reference = ElementType&;using data_handle_type = ElementType*;constexpr default_accessor() noexcept = default;template<class OtherElementType> constexpr default_accessor(default_accessor<OtherElementType>) noexcept;constexpr reference access(data_handle_type p, size_t i) const noexcept;constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept;};}
default_accessor meets the accessor policy requirements.
ElementType is required to be a complete object type that is neither an abstract class type nor an array type.
Each specialization of default_accessor is a trivially copyable type that models semiregular.
is an accessible range for an object p of type data_handle_type and an object of type default_accessorif and only if [p, p + n) is a valid range.
23.7.3.5.3.2 Members [mdspan.accessor.default.members]
template<class OtherElementType> constexpr default_accessor(default_accessor<OtherElementType>) noexcept {}
Constraints: is_convertible_v<OtherElementType(*)[], element_type(*)[]>is true.
constexpr reference access(data_handle_type p, size_t i) const noexcept;
Effects: Equivalent to: return p[i];
constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept;
Effects: Equivalent to: return p + i;
23.7.3.5.4 Class template aligned_accessor [mdspan.accessor.aligned]
23.7.3.5.4.1 Overview [mdspan.accessor.aligned.overview]
namespace std { template<class ElementType, size_t ByteAlignment> struct aligned_accessor { using offset_policy = default_accessor<ElementType>;using element_type = ElementType;using reference = ElementType&;using data_handle_type = ElementType*;static constexpr size_t byte_alignment = ByteAlignment;constexpr aligned_accessor() noexcept = default;template<class OtherElementType, size_t OtherByteAlignment> constexpr aligned_accessor( aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;template<class OtherElementType> constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;template<class OtherElementType> constexpr operator default_accessor<OtherElementType>() const noexcept;constexpr reference access(data_handle_type p, size_t i) const noexcept;constexpr typename offset_policy::data_handle_type offset( data_handle_type p, size_t i) const noexcept;};}
Mandates:
- byte_alignment is a power of two, and
- byte_alignment >= alignof(ElementType) is true.
aligned_accessor meets the accessor policy requirements.
ElementType is required to be a complete object type that is neither an abstract class type nor an array type.
Each specialization of aligned_accessor is a trivially copyable type that models semiregular.
[0, n) is an accessible range for an object p of type data_handle_type and an object of type aligned_accessor if and only if
- [p, p + n) is a valid range, and,
- if n is greater than zero, then is_sufficiently_aligned<byte_alignment>(p) is true.
[Example 1:
The following function computeuses is_sufficiently_aligned to check whether a given mdspan with default_accessor has a data handle with sufficient alignment to be used with aligned_accessor<float, 4 * sizeof(float)>.
If so, the function dispatches to a function compute_using_fourfold_overalignmentthat requires fourfold over-alignment of arrays, but can therefore use hardware-specific instructions, such as four-wide SIMD (Single Instruction Multiple Data) instructions.
Otherwise, compute dispatches to a possibly less optimized function compute_without_requiring_overalignmentthat has no over-alignment requirement.
void compute_using_fourfold_overalignment( mdspan<float, dims<1>, layout_right, aligned_accessor<float, 4 * alignof(float)>> x);void compute_without_requiring_overalignment( mdspan<float, dims<1>, layout_right> x);void compute(mdspan<float, dims<1>> x) { constexpr auto byte_alignment = 4 * sizeof(float);auto accessor = aligned_accessor<float, byte_alignment>{};auto x_handle = x.data_handle();if (is_sufficiently_aligned<byte_alignment>(x_handle)) { compute_using_fourfold_overalignment(mdspan{x_handle, x.mapping(), accessor});} else { compute_without_requiring_overalignment(x);} } — _end example_]
23.7.3.5.4.2 Members [mdspan.accessor.aligned.members]
template<class OtherElementType, size_t OtherByteAlignment> constexpr aligned_accessor(aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept;
Constraints:
- is_convertible_v<OtherElementType(*)[], element_type(*)[]>is true.
- OtherByteAlignment >= byte_alignment is true.
template<class OtherElementType> constexpr explicit aligned_accessor(default_accessor<OtherElementType>) noexcept;
Constraints: is_convertible_v<OtherElementType(*)[], element_type(*)[]>is true.
constexpr reference access(data_handle_type p, size_t i) const noexcept;
Preconditions: [0, i + 1) is an accessible range for p and *this.
Effects: Equivalent to: return assume_aligned<byte_alignment>(p)[i];
template<class OtherElementType> constexpr operator default_accessor<OtherElementType>() const noexcept;
Constraints: is_convertible_v<element_type(*)[], OtherElementType(*)[]>is true.
Effects: Equivalent to: return {};
constexpr typename offset_policy::data_handle_type offset(data_handle_type p, size_t i) const noexcept;
Preconditions: [0, i + 1) is an accessible range for p and *this.
Effects: Equivalent to: return assume_aligned<byte_alignment>(p) + i;
23.7.3.6 Class template mdspan [mdspan.mdspan]
23.7.3.6.1 Overview [mdspan.mdspan.overview]
mdspan is a view of a multidimensional array of elements.
namespace std { template<class ElementType, class Extents, class LayoutPolicy = layout_right,class AccessorPolicy = default_accessor<ElementType>> class mdspan { public: using extents_type = Extents;using layout_type = LayoutPolicy;using accessor_type = AccessorPolicy;using mapping_type = layout_type::template mapping<extents_type>;using element_type = ElementType;using value_type = remove_cv_t<element_type>;using index_type = extents_type::index_type;using size_type = extents_type::size_type;using rank_type = extents_type::rank_type;using data_handle_type = accessor_type::data_handle_type;using reference = accessor_type::reference;static constexpr rank_type rank() noexcept { return extents_type::rank(); } static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } static constexpr size_t static_extent(rank_type r) noexcept { return extents_type::static_extent(r); } constexpr index_type extent(rank_type r) const noexcept { return extents().extent(r); } constexpr mdspan();constexpr mdspan(const mdspan& rhs) = default;constexpr mdspan(mdspan&& rhs) = default;template<class... OtherIndexTypes> constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts);template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) mdspan(data_handle_type p, span<OtherIndexType, N> exts);template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) mdspan(data_handle_type p, const array<OtherIndexType, N>& exts);constexpr mdspan(data_handle_type p, const extents_type& ext);constexpr mdspan(data_handle_type p, const mapping_type& m);constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a);template<class OtherElementType, class OtherExtents,class OtherLayoutPolicy, class OtherAccessorPolicy> constexpr explicit(see below) mdspan(const mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorPolicy>& other);constexpr mdspan& operator=(const mdspan& rhs) = default;constexpr mdspan& operator=(mdspan&& rhs) = default;template<class... OtherIndexTypes> constexpr reference operator[](OtherIndexTypes... indices) const;template<class OtherIndexType> constexpr reference operator[](span<OtherIndexType, rank()> indices) const;template<class OtherIndexType> constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const;template<class... OtherIndexTypes> constexpr reference at(OtherIndexTypes... indices) const; template<class OtherIndexType> constexpr reference at(span<OtherIndexType, rank()> indices) const; template<class OtherIndexType> constexpr reference at(const array<OtherIndexType, rank()>& indices) const; constexpr size_type size() const noexcept;constexpr bool empty() const noexcept;friend constexpr void swap(mdspan& x, mdspan& y) noexcept;constexpr const extents_type& extents() const noexcept { return map_.extents(); } constexpr const data_handle_type& data_handle() const noexcept { return ptr_; } constexpr const mapping_type& mapping() const noexcept { return map_; } constexpr const accessor_type& accessor() const noexcept { return acc_; } static constexpr bool is_always_unique() { return mapping_type::is_always_unique(); } static constexpr bool is_always_exhaustive() { return mapping_type::is_always_exhaustive(); } static constexpr bool is_always_strided() { return mapping_type::is_always_strided(); } constexpr bool is_unique() const { return map_.is_unique(); } constexpr bool is_exhaustive() const { return map_.is_exhaustive(); } constexpr bool is_strided() const { return map_.is_strided(); } constexpr index_type stride(rank_type r) const { return map_.stride(r); } private: accessor_type acc_; mapping_type map_; data_handle_type ptr_; };template<class CArray> requires (is_array_v<CArray> && rank_v<CArray> == 1) mdspan(CArray&) -> mdspan<remove_all_extents_t<CArray>, extents<size_t, extent_v<CArray, 0>>>;template<class Pointer> requires (is_pointer_v<remove_reference_t<Pointer>>) mdspan(Pointer&&) -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>;template<class ElementType, class... Integrals> requires ((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) explicit mdspan(ElementType*, Integrals...) -> mdspan<ElementType, extents<size_t, maybe-static-ext<Integrals>...>>;template<class ElementType, class OtherIndexType, size_t N> mdspan(ElementType*, span<OtherIndexType, N>) -> mdspan<ElementType, dextents<size_t, N>>;template<class ElementType, class OtherIndexType, size_t N> mdspan(ElementType*, const array<OtherIndexType, N>&) -> mdspan<ElementType, dextents<size_t, N>>;template<class ElementType, class IndexType, size_t... ExtentsPack> mdspan(ElementType*, const extents<IndexType, ExtentsPack...>&) -> mdspan<ElementType, extents<IndexType, ExtentsPack...>>;template<class ElementType, class MappingType> mdspan(ElementType*, const MappingType&) -> mdspan<ElementType, typename MappingType::extents_type,typename MappingType::layout_type>;template<class MappingType, class AccessorType> mdspan(const typename AccessorType::data_handle_type&, const MappingType&,const AccessorType&) -> mdspan<typename AccessorType::element_type, typename MappingType::extents_type,typename MappingType::layout_type, AccessorType>;}
Mandates:
- ElementType is a complete object type that is neither an abstract class type nor an array type,
- Extents is a specialization of extents, and
- is_same_v<ElementType, typename AccessorPolicy::element_type>is true.
LayoutPolicy shall meet the layout mapping policy requirements ([mdspan.layout.policy.reqmts]), andAccessorPolicy shall meet the accessor policy requirements ([mdspan.accessor.reqmts]).
Each specialization MDS of mdspan models copyable and
- is_nothrow_move_constructible_v<MDS> is true,
- is_nothrow_move_assignable_v<MDS> is true, and
- is_nothrow_swappable_v<MDS> is true.
A specialization of mdspan is a trivially copyable type if its accessor_type, mapping_type, and data_handle_typeare trivially copyable types.
23.7.3.6.2 Constructors [mdspan.mdspan.cons]
Constraints:
- rank_dynamic() > 0 is true.
- is_default_constructible_v<data_handle_type> is true.
- is_default_constructible_v<mapping_type> is true.
- is_default_constructible_v<accessor_type> is true.
Preconditions: [0, _map__.required_span_size()) is an accessible range of _ptr__ and _acc__for the values of _map__ and _acc__after the invocation of this constructor.
Effects: Value-initializes ptr_, map_, and acc_.
template<class... OtherIndexTypes> constexpr explicit mdspan(data_handle_type p, OtherIndexTypes... exts);
Let N be sizeof...(OtherIndexTypes).
Constraints:
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible<index_type, OtherIndexTypes> && ...) is true,
- N == rank() || N == rank_dynamic() is true,
- is_constructible_v<mapping_type, extents_type> is true, and
- is_default_constructible_v<accessor_type> is true.
Preconditions: [0, _map__.required_span_size()) is an accessible range of p and _acc__for the values of _map__ and _acc__after the invocation of this constructor.
Effects:
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ withextents_type(static_cast<index_type>(std::move(exts))...), and
- value-initializes acc_.
template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) mdspan(data_handle_type p, span<OtherIndexType, N> exts);template<class OtherIndexType, size_t N> constexpr explicit(N != rank_dynamic()) mdspan(data_handle_type p, const array<OtherIndexType, N>& exts);
Constraints:
- is_convertible_v<const OtherIndexType&, index_type> is true,
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true,
- N == rank() || N == rank_dynamic() is true,
- is_constructible_v<mapping_type, extents_type> is true, and
- is_default_constructible_v<accessor_type> is true.
Preconditions: [0, _map__.required_span_size()) is an accessible range of p and _acc__for the values of _map__ and _acc__after the invocation of this constructor.
Effects:
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with extents_type(exts), and
- value-initializes acc_.
constexpr mdspan(data_handle_type p, const extents_type& ext);
Constraints:
- is_constructible_v<mapping_type, const extents_type&> is true, and
- is_default_constructible_v<accessor_type> is true.
Preconditions: [0, _map__.required_span_size()) is an accessible range of p and _acc__for the values of _map__ and _acc__after the invocation of this constructor.
Effects:
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with ext, and
- value-initializes acc_.
constexpr mdspan(data_handle_type p, const mapping_type& m);
Constraints: is_default_constructible_v<accessor_type> is true.
Preconditions: [0, m.required_span_size()) is an accessible range of p and _acc__for the value of _acc__ after the invocation of this constructor.
Effects:
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with m, and
- value-initializes acc_.
constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a);
Preconditions: [0, m.required_span_size()) is an accessible range of p and a.
Effects:
- Direct-non-list-initializes ptr_ with std::move(p),
- direct-non-list-initializes map_ with m, and
- direct-non-list-initializes acc_ with a.
template<class OtherElementType, class OtherExtents,class OtherLayoutPolicy, class OtherAccessor> constexpr explicit(_see below_) mdspan(const mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessor>& other);
Constraints:
- is_constructible_v<mapping_type, const OtherLayoutPolicy::template mapping<Oth-
erExtents>&>is true, and - is_constructible_v<accessor_type, const OtherAccessor&> is true.
Mandates:
- is_constructible_v<data_handle_type, const OtherAccessor::data_handle_type&> is
true, and - is_constructible_v<extents_type, OtherExtents> is true.
Preconditions: [0, _map__.required_span_size()) is an accessible range of _ptr__ and _acc__for values of _ptr__, _map__, and _acc__after the invocation of this constructor.
Hardened preconditions: For each rank index r of extents_type,static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r)is true.
Effects:
- Direct-non-list-initializes ptr_ with other.ptr_,
- direct-non-list-initializes map_ with other.map_, and
- direct-non-list-initializes acc_ with other.acc_.
Remarks: The expression inside explicit is equivalent to:!is_convertible_v<const OtherLayoutPolicy::template mapping<OtherExtents>&, mapping_type> || !is_convertible_v<const OtherAccessor&, accessor_type>
23.7.3.6.3 Members [mdspan.mdspan.members]
template<class... OtherIndexTypes> constexpr reference operator[](OtherIndexTypes... indices) const;
Constraints:
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
- sizeof...(OtherIndexTypes) == rank() is true.
Let I be extents_type::index-cast(std::move(indices)).
Hardened preconditions: I is a multidimensional index in extents().
[Note 1:
This implies that_map__(I) < map_.required_span_size()is true.
— _end note_]
Effects: Equivalent to:return acc_.access(ptr_, map_(static_cast<index_type>(std::move(indices))...));
template<class OtherIndexType> constexpr reference operator[](span<OtherIndexType, rank()> indices) const;template<class OtherIndexType> constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const;
Constraints:
- is_convertible_v<const OtherIndexType&, index_type> is true, and
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true.
Effects: Let P be a parameter pack such thatis_same_v<make_index_sequence<rank()>, index_sequence<P...>> is true.
Equivalent to:return operator[](extents_type::_index-cast_(as_const(indices[P]))...);
template<class... OtherIndexTypes> constexpr reference at(OtherIndexTypes... indices) const;
Constraints:
- (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
- (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
- sizeof...(OtherIndexTypes) == rank() is true.
Let I be extents_type::index-cast(std::move(indices)).
Throws: out_of_range if I is not a multidimensional index in extents().
template<class OtherIndexType> constexpr reference at(span<OtherIndexType, rank()> indices) const;template<class OtherIndexType> constexpr reference at(const array<OtherIndexType, rank()>& indices) const;
Constraints:
- is_convertible_v<const OtherIndexType&, index_type> is true, and
- is_nothrow_constructible_v<index_type, const OtherIndexType&> is true.
Effects: Let P be a parameter pack such thatis_same_v<make_index_sequence<rank()>, index_sequence<P...>> is true.
Equivalent to:return at(extents_type::index-cast(as_const(indices[P]))...);
constexpr size_type size() const noexcept;
Preconditions: The size of the multidimensional index space extents()is representable as a value of type size_type ([basic.fundamental]).
Returns: extents().fwd-prod-of-extents(rank()).
constexpr bool empty() const noexcept;
Returns: trueif the size of the multidimensional index space extents() is 0, otherwise false.
friend constexpr void swap(mdspan& x, mdspan& y) noexcept;
Effects: Equivalent to:swap(x.ptr_, y.ptr_); swap(x.map_, y.map_); swap(x.acc_, y.acc_);
23.7.3.7 submdspan [mdspan.sub]
23.7.3.7.1 Overview [mdspan.sub.overview]
The submdspan facilities create a new mdspanviewing a subset of elements of an existing input mdspan.
The subset viewed by the created mdspan is determined by the SliceSpecifier arguments.
Given a signed or unsigned integer type IndexType, a type S is asubmdspan slice type for IndexTypeif at least one of the following holds:
- is_convertible_v<S, full_extent_t> is true;
- is_convertible_v<S, IndexType> is true;
- S is a specialization of strided_slice andis_convertible_v<X, IndexType> is true for X denotingS::offset_type,S::extent_type, andS::stride_type; or
- all of the following hold:
- the declaration auto [...ls] = std::move(s); is well-formed for some object s of type S,
- sizeof...(ls) is equal to 2, and
- (is_convertible_v<decltype(std::move(ls)), IndexType> && ...) is true.
Given a signed or unsigned integer type IndexType, a type S is acanonical submdspan index type for IndexTypeif S is either IndexType or constant_wrapper<v>for some value v of type IndexType, such that v is greater than or equal to zero.
Given a signed or unsigned integer type IndexType, a type S is acanonical submdspan slice type for IndexTypeif exactly one of the following is true:
- S is full_extent_t;
- S is a canonical submdspan index type for IndexType; or
- S is a specialization of strided_slice where all of the following hold:
- S::offset_type, S::extent_type, and S::stride_type are all canonical submdspan index types for IndexType; and
- if S::stride_type and S::extent_type are both specializations of constant_wrapper, then S::stride_type::value is greater than zero.
A type S is a collapsing slice type if it is neither full_extent_t nor a specialization of strided_slice.
[Note 1:
Each collapsing slice type in submdspan_mapping's parameter pack of slice specifier types reduces the rank of the result of submdspan_mapping by one.
— _end note_]
A type S is a unit-stride slice type if
- S is a specialization of strided_slice where S::stride_type is a specialization of constant_wrapper andS::stride_type::value is equal to 1, or
- S denotes full_extent_t.
Given an object e of type E that is a specialization of extents, and an object s of type Sthat is a canonical submdspan slice type for E::index_type, the submdspan slice range of s for the extent of eis:
- [0, e.extent(k)), if S is full_extent_t;
- [E::index_type(s.offset), E::index_type(s.offset + s.extent)), if S is a specialization of strided_slice; otherwise
- [E::index_type(s), )
Given a type E that is a specialization of extents, a type S is avalid submdspan slice type for the extent of Eif S is a canonical slice type for E::index_type, and for x equal to E::static_extent(k), either x is equal to dynamic_extent; or
- if S is a specialization of strided_slice:
- if S::offset_type is a specialization of constant_wrapper, then S::offset_type::value is less than or equal to x;
- if S::offset_type is a specialization of constant_wrapper, then S::extent_type::value is less than or equal to x; and
- if both S::offset_type and S::extent_type are specializations of constant_wrapper, then S::offset_type::value + S::extent_type::value is less than or equal to x; or
- if S is a specialization of constant_wrapper, then S::value is less than x.
Given an object e of type Ethat is a specialization of extents and an object s of type S,s is avalid submdspan slice for the extent of eif
- S is a valid submdspan slice type for the extent of E;
- the interval of e contains the submdspan slice range of s for the extent of e; and
- if S is a specialization of strided_slice, then:
- s.extent is greater than or equal to zero, and
- either s.extent equals zero or s.stride is greater than zero.
23.7.3.7.2 strided_slice [mdspan.sub.strided.slice]
strided_slice represents a set ofextent regularly spaced integer indices.
The indices start at offset, and increase by increments of stride.
namespace std { template<class OffsetType, class ExtentType, class StrideType> struct strided_slice { using offset_type = OffsetType;using extent_type = ExtentType;using stride_type = StrideType;[[no_unique_address]] offset_type offset{};[[no_unique_address]] extent_type extent{};[[no_unique_address]] stride_type stride{};};}
strided_slice has the data members and special members specified above.
It has no base classes or members other than those specified.
Mandates: OffsetType, ExtentType, and StrideTypeare signed or unsigned integer types, or model integral-constant-like.
[Note 1:
strided_slice{.offset = 1, .extent = 10, .stride = 3}indicates the indices 1, 4, 7, and 10.
Indices are selected from the half-open interval [1, 1 + 10).
— _end note_]
23.7.3.7.3 submdspan_mapping_result [mdspan.sub.map.result]
Specializations of submdspan_mapping_resultare returned by overloads of submdspan_mapping.
namespace std { template<class LayoutMapping> struct submdspan_mapping_result { [[no_unique_address]] LayoutMapping mapping = LayoutMapping(); size_t offset{};};}
submdspan_mapping_result has the data members and special members specified above.
It has no base classes or members other than those specified.
LayoutMapping shall meet the layout mapping requirements ([mdspan.layout.policy.reqmts]).
23.7.3.7.4 Exposition-only helpers [mdspan.sub.helpers]
For a pack p and an integer i, let MAP_RANK(p, i) be the number of elements p...[j]for whose types are not collapsing slice types.
template<class T> concept [_is-strided-slice_](#concept:is-strided-slice "23.7.3.7.4 Exposition-only helpers [mdspan.sub.helpers]") = _see below_;
The concept is-strided-slice<T>is satisfied and modeled if and only if T is a specialization of strided_slice.
template<class IndexType, class S> constexpr auto _canonical-index_(S s);
Mandates: If S models integral-constant-like, then extents<IndexType>::index-cast(S::value)is representable as a value of type IndexType.
Preconditions: extents<IndexType>::index-cast(std::move(s))is representable as a value of type IndexType.
Effects: Equivalent to:
- return cw<IndexType(S::value)>;if S models integral-constant-like;
- return IndexType(std::move(s)); otherwise.
template<class IndexType, class S> constexpr auto _canonical-slice_(S s);
Mandates: S is a submdspan slice type for IndexType.
Effects: Equivalent to:if constexpr (is_convertible_v<S, full_extent_t>) { return static_cast<full_extent_t>(std::move(s));} else if constexpr (is_convertible_v<S, IndexType>) { return canonical-index<IndexType>(std::move(s));} else if constexpr (is-strided-slice<S>) { auto c_extent = canonical-index<IndexType>(std::move(s.extent));auto c_offset = canonical-index<IndexType>(std::move(s.offset));if constexpr (is_same_v<decltype(c_extent), constant_wrapper<IndexType(0)>>) { return strided_slice{ .offset = c_offset,.extent = c_extent,.stride = cw<IndexType(1)> };} else { return strided_slice{ .offset = c_offset,.extent = c_extent,.stride = canonical-index<IndexType>(std::move(s.stride)) };} } else { auto [s_first, s_last] = std::move(s);auto c_first = canonical-index<IndexType>(std::move(s_first));auto c_last = canonical-index<IndexType>(std::move(s_last));return strided_slice{ .offset = c_first,.extent = canonical-index<IndexType>(c_last - c_first),.stride = cw<IndexType(1)> };}
23.7.3.7.5 submdspan slice canonicalization [mdspan.sub.canonical]
template<class IndexType, size_t... Extents, class... SliceSpecifiers> constexpr auto submdspan_canonicalize_slices(const extents<IndexType, Extents...>& src, SliceSpecifiers... slices);
Constraints: sizeof...(SliceSpecifiers) equals sizeof...(Extents).
Mandates: For each rank index k of src:
- SliceSpecifiers...[k] is a submdspan slice type for IndexType, and
- decltype(canonical-slice<IndexType>(slices...[k])) is a valid submdspan slice type for the extent ofextents<IndexType, Extents...>.
Preconditions: For each rank index k of src,canonical-slice<IndexType>(slices...[k])is a valid submdspan slice for the extent of src.
Returns: make_tuple(canonical-slice<IndexType>(slices)...).
23.7.3.7.6 submdspan_extents function [mdspan.sub.extents]
template<class IndexType, size_t... Extents, class... SliceSpecifiers> constexpr auto submdspan_extents(const extents<IndexType, Extents...>& src, SliceSpecifiers... raw_slices);
Let slices be the pack introduced by the following declaration:auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...);
Constraints: sizeof...(SliceSpecifiers) equals sizeof...(Extents).
Mandates: For each rank index k of src:
- SliceSpecifiers...[k] is a submdspan slice type for IndexType, and
- decltype(slices...[k]) is a valid submdspan slice type for the extent of extents<IndexType, Extents...>.
Preconditions: For each rank index k of src,slices...[k] is a valid submdspan slice for the extent of src.
Let SubExtents be a specialization of extents such that:
- SubExtents::rank() equals_MAP_RANK_(slices, Extents::rank()); and
- for each rank index k of Extents such that the type of slices...[k] is not a collapsing slice type,SubExtents::static_extent(MAP_RANK(slices, k))equals the following, where denotes the type of slices...[k]:
- Extents::static_extent(k) if denotes the full_extent_t; otherwise
- 0, if is a specialization of strided_slice and::extent_type denotes constant_wrapper<IndexType(0)>; otherwise
- 1 + ((::extent_type::value - 1) / ::stride_type::value), if is a specialization of strided_slice whoseextent_type and stride_type denote specializations of constant_wrapper;
- otherwise,dynamic_extent.
Returns: A value ext of type SubExtents such that for each rank index k of extents<IndexType, Extents...>, where the type of slices...[k] is not a collapsing slice type,ext.extent(MAP_RANK(slices, k))equals the following, where denotes slices...[k]:
- .extent == 0 ? 0 : 1 + (.extent - 1) / .stride if the type of is a specialization of strided_slice,
- otherwise,, where [L, U) is the submdspan slice range of for the extent of src.
23.7.3.7.7 Specializations of submdspan_mapping [mdspan.sub.map]
23.7.3.7.7.1 Sliceable layout mapping requirements [mdspan.sub.map.sliceable]
Let:
- M denote a layout mapping class;
- IT denote M::extent_type::index_type;
- m denote a value of type (possibly const) M;
- M_rank be equal to M::extent_type::rank();
- valid_slices denote a pack of (possibly const) objects for which sizeof...(valid_slices) == M_rank is true and, for each rank index i of m.extents(),valid_slices...[i] is a valid submdspan slice for the extent of m.extents();
- invalid_slices denote a pack of objects for which sizeof...(invalid_slices) == M_rank is true and there exists an integer k such that the cv-unqualified type of invalid_slices...[k] is none of the following:
- IT,
- full_extent_t,
- a specialization of constant_wrapper, or
- a specialization of strided_slice.
For the purpose of this section, the meaning of submdspan_mapping is established as if by performing argument-dependent lookup only ([basic.lookup.argdep]).
A type M meets the sliceable layout mapping requirements if
- M meets the layout mapping requirements ([mdspan.layout.policy.reqmts]),
- the expression submdspan_mapping(m, invalid_slices...) is ill-formed, and
- the following expression is well-formed and has the specified semantics:submdspan_mapping(m, valid_slices...)
Result: A type SMR that is a specialization of type submdspan_mapping_result for some type SM such that
- SM meets the layout mapping requirements ([mdspan.layout.policy.reqmts]),
- SM::extents_type is a specialization of extents,
- SM::extents_type::rank() equals_MAP_RANK_(valid_slices, M_rank), and
- SM::extents_type::index_type denotes IT.
Returns: An object smr of type SMR such that
- smr.mapping.extents() == submdspan_extents(m.extents(), valid_slices...) is true;
and - for each integer pack i which is a multidimensional index in smr.mapping.extents(),
smr.mapping(i...) + smr.offset == m(j) is true, where j is an integer pack such that- sizeof...(j) is equal to M_rank; and
- for each rank index ρ of m.extents(),j...[ρ] is equal to the sum of
* the lower bound of the submdspan slice range of valid_slices...[ρ] for extent ρ of m.extents(), and
* zero if the type of valid_slices...[ρ] is a collapsing slice type,i...[MAP_RANK(valid_slices,ρ)] otherwise.
template<class LayoutMapping> concept [_sliceable-mapping_](#concept:sliceable-mapping "23.7.3.7.7.1 Sliceable layout mapping requirements [mdspan.sub.map.sliceable]") = _see below_;
Let lm be an object of type LayoutMappingand let fe denote a pack of objects of type full_extent_tfor which sizeof...(fe) == LayoutMapping::extents_type::rank() is true.
A type LayoutMapping satisfies sliceable-mapping if
- the expression submdspan_mapping(m, fe...) is well-formed when treated as an unevaluated operand, and
- the type of that expression is a specialization ofsubmdspan_mapping_result.
A type LayoutMapping models sliceable-mappingif LayoutMapping meets the sliceable layout mapping requirements.
23.7.3.7.7.2 Common [mdspan.sub.map.common]
The following elements apply to all functions in [mdspan.sub.map].
Constraints: sizeof...(SpliceSpecifiers) equals extents_type::rank().
Mandates: For each rank index k of extents(),SliceSpecifiers...[k] is a valid submdspan slice type for the extent of Extents.
Preconditions: For each rank index k of extents(),slices...[k] is a valid slice for the extent of extents().
Let sub_ext be the result of submdspan_extents(extents(), slices...) and let SubExtents be decltype(sub_ext).
Let sub_strides be an array<SubExtents::index_type, SubExtents::rank()>such that for each rank index k of extents()for which the type of slices...[k] is not a collapsing slice type,sub_strides[MAP_RANK(slices,k)] equals:
- stride(k) * s.strideif the type of s is a specialization of strided_slice ands.stride < s.extent is true, where s is slices...[k];
- otherwise, stride(k).
Let ls be a pack of values of index_type, where the element equals the lower bound of the submdspan slice range of slices...[ρ]for extent ρ of extents().
If ls...[k]equals extents().extent(k)for any rank index k of extents(), then let offset be a value of type size_t equal torequired_span_size().
Otherwise, let offset be a value of type size_t equal tooperator()(ls...).
23.7.3.7.7.3 layout_left specialization of submdspan_mapping [mdspan.sub.map.left]
template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_left::mapping<Extents>::_submdspan-mapping-impl_( SliceSpecifiers... slices) const -> _see below_;
Returns:
- submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;
- otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if SubExtents::rank() == 0 is true; - otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if
- for each k in the range [0, SubExtents::rank() - 1),SpliceSpecifiers...[k] denotes full_extent_t; and
- for k equal to SubExtents::rank() - 1,SpliceSpecifiers...[k] is a unit-stride slice type;
[Note 1:
If the above conditions are true, all SpliceSpecifiers...[k] with k larger than SubExtents::rank() - 1are convertible to index_type.
— _end note_]
- otherwise,submdspan_mapping_result{layout_left_padded<S_static>::mapping(sub_ext, stride(u + 1)), offset} if for a value u for which is the smallest value p larger than zero for which SliceSpecifiers...[p] is a unit-stride slice type, the following conditions are met:
- SliceSpecifiers...[0] is a unit-stride slice type; and
- for each k in the range [u + 1, u + SubExtents::rank() - 1),SliceSpecifiers...[k] denotes full_extent_t; and
- for k equal to u + SubExtents::rank() - 1,SliceSpecifiers...[k] is a unit-stride slice type;
and where S_static is: - dynamic_extent, if static_extent(k) is dynamic_extentfor any k in the range [0, u + 1),
- otherwise, the product of all valuesstatic_extent(k) for k in the range [0, u + 1);
- otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
23.7.3.7.7.4 layout_right specialization of submdspan_mapping [mdspan.sub.map.right]
template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_right::mapping<Extents>::_submdspan-mapping-impl_( SliceSpecifiers... slices) const -> _see below_;
Returns:
- submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;
- otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if SubExtents::rank() == 0 is true; - otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset}, if
- for each k in the range [rank_ - SubExtents::rank() + 1, rank_),
SliceSpecifiers...[k] denotes full_extent_t; and - for k equal to rank_ - SubExtents::rank(),SliceSpecifiers...[k] is a unit-stride slice type;
[Note 1:
If the above conditions are true, all SliceSpecifiers...[k] with
are convertible to index_type.
— _end note_]
- for each k in the range [rank_ - SubExtents::rank() + 1, rank_),
- otherwise,submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext, stride(rank_ - u - 2)), offset} if for a value u for which is the largest value p smaller than rank_ - 1for which SliceSpecifiers...[p] is a unit-stride slice type, the following conditions are met:
- for k equal to rank_ - 1,SliceSpecifiers...[k] is a unit-stride slice type; and
- for each k in the range [rank_ - SubExtents::rank() - u + 1, rank_ - u - 1),
SliceSpecifiers...[p] denotes full_extent_t; and - for k equal to rank_ - SubExtents::rank() - u,SliceSpecifiers...[k] is a unit-stride slice type;
and where S_static is: - dynamic_extent, if static_extent(k) is dynamic_extentfor any k in the range [rank_ - u - 1, rank_),
- otherwise, the product of all valuesstatic_extent(k)for k in the range [rank_ - u - 1, rank_);
- otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
23.7.3.7.7.5 layout_stride specialization of submdspan_mapping [mdspan.sub.map.stride]
template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_stride::mapping<Extents>::_submdspan-mapping-impl_( SliceSpecifiers... slices) const -> _see below_;
Returns:
- submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;
- otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
23.7.3.7.7.6 layout_left_padded specialization of submdspan_mapping [mdspan.sub.map.leftpad]
template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_left_padded::mapping<Extents>::_submdspan-mapping-impl_( SliceSpecifiers... slices) const -> _see below_;
Returns:
- submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;
- otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if rank_ == 1 is true orSubExtents::rank() == 0 is true;
- otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if
- SubExtents::rank() == 1 is true and
- SliceSpecifiers...[0] is a unit-stride slice type;
- otherwise,submdspan_mapping_result{layout_left_padded<S_static>::mapping(sub_ext, stride(u + 1)), offset} if for a value ufor which u + 1 is the smallest value p larger than zero for which SliceSpecifiers...[p] is a unit-stride slice type, the following conditions are met:
- SliceSpecifiers...[0] is a unit-stride slice type; and
- for each k in the range [u + 1, u + SubExtents::rank() - 1),SliceSpecifiers...[k] denotes full_extent_t; and
- for k equal to u + SubExtents::rank() - 1,SliceSpecifiers...[k] is a unit-stride slice type;
where S_static is: - dynamic_extent, if static-padding-stride is dynamic_extent orstatic_extent(k) is dynamic_extentfor any k in the range [1, u + 1),
- otherwise, the product of static-padding-stride and all values static_extent(k) for k in the range [1, u + 1);
- otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
23.7.3.7.7.7 layout_right_padded specialization of submdspan_mapping [mdspan.sub.map.rightpad]
template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_right_padded::mapping<Extents>::_submdspan-mapping-impl_( SliceSpecifiers... slices) const -> _see below_;
Returns:
- submdspan_mapping_result{*this, 0}, if rank_ == 0 is true;
- otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if rank_ == 1 is true orSubExtents::rank() == 0 is true; - otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset}, if
- SubExtents::rank() == 1 is true and
- for k equal to rank_ - 1,SliceSpecifiers...[k] is a unit-stride slice type;
- otherwise,submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext, stride(rank_ - u - 2)), offset} if for a value ufor which rank_ - u - 2is the largest value p smaller than rank_ - 1for which SliceSpecifiers...[p] is a unit-stride slice type, the following conditions are met:
- for k equal to rank_ - 1,SliceSpecifiers...[k] is a unit-stride slice type; and
- for each k in the range [rank_ - SubExtents::rank() - u + 1, rank_ - u - 1),
SliceSpecifiers...[k] denotes full_extent_t; and - for k equal to rank_ - SubExtents::rank() - u,SliceSpecifiers...[k] is a unit-stride slice type;
and where S_static is: - dynamic_extentif static-padding-stride is dynamic_extent or for any k in the range [rank_ - u - 1, rank_ - 1)static_extent(k) is dynamic_extent,
- otherwise, the product of static-padding-stride and all values static_extent(k)with k in the range [rank_ - u - 1, rank_ - 1);
- otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
23.7.3.7.8 submdspan function template [mdspan.sub.sub]
template<class ElementType, class Extents, class LayoutPolicy,class AccessorPolicy, class... SliceSpecifiers> constexpr auto submdspan( const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src, SliceSpecifiers... slices) -> _see below_;
Let index_type be typename Extents::index_type.
Let slices be the pack introduced by the following declaration:auto [...slices] = submdspan_canonicalize_slices(src, raw_slices...);
Let sub_map_offset be the result ofsubmdspan_mapping(src.mapping(), slices...).
[Note 1:
This invocation of submdspan_mappingselects a function call via overload resolution on a candidate set that includes the lookup set found by argument-dependent lookup ([basic.lookup.argdep]).
— _end note_]
Constraints:
- sizeof...(slices) equals Extents::rank(), and
- LayoutPolicy::mapping<Extents> models sliceable-mapping.
Mandates: For each rank index k of src:
- SliceSpecifiers...[k] is a submdspan slice type for index_type, and
- decltype(slices...[k]) is a valid submdspan slice type for the extent of Extents.
Preconditions: For each rank index k of src.extents(),slices...[k] is a valid submdspan slice for the extent of src.extents().
Effects: Equivalent to:auto sub_map_result = submdspan_mapping(src.mapping(), slices...);return mdspan(src.accessor().offset(src.data_handle(), sub_map_result.offset), sub_map_result.mapping,typename AccessorPolicy::offset_policy(src.accessor()));
[Example 1:
Given a rank-3 mdspan grid3d representing a three-dimensional grid of regularly spaced points in a rectangular prism, the function zero_surface sets all elements on the surface of the 3-dimensional shape to zero.
It does so by reusing a function zero_2dthat takes a rank-2 mdspan.
template<class T, class E, class L, class A> void zero_2d(mdspan<T, E, L, A> a) { static_assert(a.rank() == 2);for (int i = 0; i < a.extent(0); i++) for (int j = 0; j < a.extent(1); j++) a[i, j] = 0;} template<class T, class E, class L, class A> void zero_surface(mdspan<T, E, L, A> grid3d) { static_assert(grid3d.rank() == 3); zero_2d(submdspan(grid3d, 0, full_extent, full_extent)); zero_2d(submdspan(grid3d, full_extent, 0, full_extent)); zero_2d(submdspan(grid3d, full_extent, full_extent, 0)); zero_2d(submdspan(grid3d, grid3d.extent(0) - 1, full_extent, full_extent)); zero_2d(submdspan(grid3d, full_extent, grid3d.extent(1) - 1, full_extent)); zero_2d(submdspan(grid3d, full_extent, full_extent, grid3d.extent(2) - 1));} — _end example_]