[mdspan.extents]

# 23 Containers library [[containers]](./#containers)

## 23.7 Views [[views]](views#mdspan.extents)

### 23.7.3 Multidimensional access [[views.multidim]](views.multidim#mdspan.extents)

#### 23.7.3.3 Class template extents [mdspan.extents]

#### [23.7.3.3.1](#overview) Overview [[mdspan.extents.overview]](mdspan.extents.overview)

The class template extents represents
a multidimensional index space of rank equal to sizeof...(Extents)[.](#overview-sentence-1)

In [[views]](views "23.7 Views"),extents is used synonymously with multidimensional index space[.](#overview-sentence-2)

namespace std {template<class IndexType, size_t... Extents>class [extents](#lib:extents "23.7.3.3.1 Overview [mdspan.extents.overview]") {public:using index_type = IndexType; using size_type = make_unsigned_t<index_type>; using rank_type = size_t; // [[mdspan.extents.obs]](#obs "23.7.3.3.4 Observers of the multidimensional index space"), observers of the multidimensional index spacestatic 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; // [[mdspan.extents.cons]](#cons "23.7.3.3.3 Constructors"), constructorsconstexpr 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; // [[mdspan.extents.cmp]](#cmp "23.7.3.3.5 Comparison operators"), comparison operatorstemplate<class OtherIndexType, size_t... OtherExtents>friend constexpr bool operator==(const extents&, const extents<OtherIndexType, OtherExtents...>&) noexcept; // [[mdspan.extents.expo]](#expo "23.7.3.3.2 Exposition-only helpers"), exposition-only helpersconstexpr size_t *fwd-prod-of-extents*(rank_type) const noexcept; // *exposition only*constexpr size_t *rev-prod-of-extents*(rank_type) const noexcept; // *exposition only*template<class OtherIndexType>static constexpr auto *index-cast*(OtherIndexType&&) noexcept; // *exposition only*private:static constexpr rank_type *dynamic-index*(rank_type) noexcept; // *exposition only*static constexpr rank_type *dynamic-index-inv*(rank_type) noexcept; // *exposition only* array<index_type, rank_dynamic()> *dynamic-extents*{}; // *exposition only*}; template<class... Integrals>explicit extents(Integrals...)-> *see below*;}

[1](#overview-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21152)

*Mandates*: 

- [(1.1)](#overview-1.1)

IndexType is a signed or unsigned integer type, and

- [(1.2)](#overview-1.2)

each element of Extents is either equal to dynamic_extent, or
is representable as a value of type IndexType[.](#overview-1.sentence-1)

[2](#overview-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21162)

Each specialization of extents models [regular](concepts.object#concept:regular "18.6 Object concepts [concepts.object]") and
is trivially copyable[.](#overview-2.sentence-1)

[3](#overview-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21166)

Let Er be the rth element of Extents[.](#overview-3.sentence-1)

Er is a [*dynamic extent*](#def:extent,dynamic "23.7.3.3.1 Overview [mdspan.extents.overview]") if it is equal to dynamic_extent,
otherwise Er is a [*static extent*](#def:extent,static "23.7.3.3.1 Overview [mdspan.extents.overview]")[.](#overview-3.sentence-2)

Let Dr be the value of *dynamic-extents*[*dynamic-index*(r)] if Er is a dynamic extent,
otherwise Er[.](#overview-3.sentence-3)

[4](#overview-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21174)

The rth interval of the multidimensional index space
represented by an extents object is [0,Dr)[.](#overview-4.sentence-1)

#### [23.7.3.3.2](#expo) Exposition-only helpers [[mdspan.extents.expo]](mdspan.extents.expo)

[ð](#expo-itemdecl:1)

`static constexpr rank_type dynamic-index(rank_type i) noexcept;
`

[1](#expo-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21185)

*Preconditions*: i <= rank() is true[.](#expo-1.sentence-1)

[2](#expo-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21189)

*Returns*: The number of Er with r<i for which Er is a dynamic extent[.](#expo-2.sentence-1)

[ð](#expo-itemdecl:2)

`static constexpr rank_type dynamic-index-inv(rank_type i) noexcept;
`

[3](#expo-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21199)

*Preconditions*: i < rank_dynamic() is true[.](#expo-3.sentence-1)

[4](#expo-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21203)

*Returns*: The minimum value of r such that *dynamic-index*(r + 1) == i + 1 is true[.](#expo-4.sentence-1)

[ð](#expo-itemdecl:3)

`constexpr size_t fwd-prod-of-extents(rank_type i) const noexcept;
`

[5](#expo-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21214)

*Preconditions*: i <= rank() is true[.](#expo-5.sentence-1)

[6](#expo-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21218)

*Returns*: If i > 0 is true,
the product of extent(k) for all k in the range [0, i),
otherwise 1[.](#expo-6.sentence-1)

[ð](#expo-itemdecl:4)

`constexpr size_t rev-prod-of-extents(rank_type i) const noexcept;
`

[7](#expo-7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21230)

*Preconditions*: i < rank() is true[.](#expo-7.sentence-1)

[8](#expo-8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21234)

*Returns*: If i + 1 < rank() is true,
the product of extent(k) for all k in the range [i + 1, rank()),
otherwise 1[.](#expo-8.sentence-1)

[ð](#expo-itemdecl:5)

`template<class OtherIndexType>
  static constexpr auto index-cast(OtherIndexType&& i) noexcept;
`

[9](#expo-9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21248)

*Effects*: 

- [(9.1)](#expo-9.1)

If OtherIndexType is an integral type other than bool,
then equivalent to return i;,

- [(9.2)](#expo-9.2)

otherwise, equivalent to return static_cast<index_type>(i);[.](#expo-9.sentence-1)

[*Note [1](#expo-note-1)*:

This function will always return an integral type other than bool[.](#expo-9.sentence-2)

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[.](#expo-9.sentence-3)

â *end note*]

#### [23.7.3.3.3](#cons) Constructors [[mdspan.extents.cons]](mdspan.extents.cons)

[ð](#lib:extents,constructor)

`template<class OtherIndexType, size_t... OtherExtents>
  constexpr explicit(see below)
    extents(const extents<OtherIndexType, OtherExtents...>& other) noexcept;
`

[1](#cons-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21276)

*Constraints*: 

- [(1.1)](#cons-1.1)

  sizeof...(OtherExtents) == rank() is true[.](#cons-1.1.sentence-1)

- [(1.2)](#cons-1.2)

  ((OtherExtents == dynamic_extent || Extents == dynamic_extent || OtherExtents ==  
Extents) && ...) is true[.](#cons-1.2.sentence-1)

[2](#cons-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21285)

*Preconditions*: 

- [(2.1)](#cons-2.1)

other.extent(r) equals Er for each r for which Er is a static extent, and

- [(2.2)](#cons-2.2)

either
  * [(2.2.1)](#cons-2.2.1)

sizeof...(OtherExtents) is zero, or

  * [(2.2.2)](#cons-2.2.2)

other.extent(r) is representable as
a value of type index_type for every rank index r of other[.](#cons-2.sentence-1)

[3](#cons-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21302)

*Postconditions*: *this == other is true[.](#cons-3.sentence-1)

[4](#cons-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21306)

*Remarks*: The expression inside explicit is equivalent to:(((Extents != dynamic_extent) && (OtherExtents == dynamic_extent)) || ... ) ||(numeric_limits<index_type>::max() < numeric_limits<OtherIndexType>::max())

[ð](#lib:extents,constructor_)

`template<class... OtherIndexTypes>
  constexpr explicit extents(OtherIndexTypes... exts) noexcept;
`

[5](#cons-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21322)

Let N be sizeof...(OtherIndexTypes),
and let exts_arr bearray<index_type, N>{static_cast<  
index_type>(std​::​move(exts))...}[.](#cons-5.sentence-1)

[6](#cons-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21327)

*Constraints*: 

- [(6.1)](#cons-6.1)

(is_convertible_v<OtherIndexTypes, index_type> && ...) is true,

- [(6.2)](#cons-6.2)

(is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and

- [(6.3)](#cons-6.3)

N == rank_dynamic() || N == rank() is true[.](#cons-6.sentence-1)
  [*Note [1](#cons-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[.](#cons-6.3.sentence-2)
 â *end note*]

[7](#cons-7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21343)

*Preconditions*: 

- [(7.1)](#cons-7.1)

If N != rank_dynamic() is true,exts_arr[r] equals Er for each r for which Er is a static extent, and

- [(7.2)](#cons-7.2)

either
  * [(7.2.1)](#cons-7.2.1)

sizeof...(exts) == 0 is true, or

  * [(7.2.2)](#cons-7.2.2)

each element of exts is representable
as a nonnegative value of type index_type[.](#cons-7.sentence-1)

[8](#cons-8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21361)

*Postconditions*: *this == extents(exts_arr) is true[.](#cons-8.sentence-1)

[ð](#lib:extents,constructor__)

`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;
`

[9](#cons-9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21377)

*Constraints*: 

- [(9.1)](#cons-9.1)

is_convertible_v<const OtherIndexType&, index_type> is true,

- [(9.2)](#cons-9.2)

is_nothrow_constructible_v<index_type, const OtherIndexType&> is true, and

- [(9.3)](#cons-9.3)

N == rank_dynamic() || N == rank() is true[.](#cons-9.sentence-1)

[10](#cons-10)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21388)

*Preconditions*: 

- [(10.1)](#cons-10.1)

If N != rank_dynamic() is true,exts[r] equals Er for each r for which Er is a static extent, and

- [(10.2)](#cons-10.2)

either
  * [(10.2.1)](#cons-10.2.1)

N is zero, or

  * [(10.2.2)](#cons-10.2.2)

exts[r] is representable
as a nonnegative value of type index_type for every rank index r[.](#cons-10.sentence-1)

[11](#cons-11)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21405)

*Effects*: 

- [(11.1)](#cons-11.1)

  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])[.](#cons-11.1.sentence-1)

- [(11.2)](#cons-11.2)

  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)])[.](#cons-11.2.sentence-1)

[ð](#lib:extents,constructor___)

`template<class... Integrals>
  explicit extents(Integrals...) -> see below;
`

[12](#cons-12)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21427)

*Constraints*: (is_convertible_v<Integrals, size_t> && ...) is true[.](#cons-12.sentence-1)

[13](#cons-13)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21431)

*Remarks*: The deduced type is extents<size_t, [*maybe-static-ext*](span.syn#concept:maybe-static-ext "23.7.2.1 Header <span> synopsis [span.syn]")<Integrals>...>[.](#cons-13.sentence-1)

#### [23.7.3.3.4](#obs) Observers of the multidimensional index space [[mdspan.extents.obs]](mdspan.extents.obs)

[ð](#lib:static_extent,extents)

`static constexpr size_t static_extent(rank_type i) noexcept;
`

[1](#obs-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21444)

*Preconditions*: i < rank() is true[.](#obs-1.sentence-1)

[2](#obs-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21448)

*Returns*: Ei[.](#obs-2.sentence-1)

[ð](#lib:extent,extents)

`constexpr index_type extent(rank_type i) const noexcept;
`

[3](#obs-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21459)

*Preconditions*: i < rank() is true[.](#obs-3.sentence-1)

[4](#obs-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21463)

*Returns*: Di[.](#obs-4.sentence-1)

#### [23.7.3.3.5](#cmp) Comparison operators [[mdspan.extents.cmp]](mdspan.extents.cmp)

[ð](#lib:operator==,extents)

`template<class OtherIndexType, size_t... OtherExtents>
  friend constexpr bool operator==(const extents& lhs,
                                   const extents<OtherIndexType, OtherExtents...>& rhs) noexcept;
`

[1](#cmp-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21478)

*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[.](#cmp-1.sentence-1)

#### [23.7.3.3.6](#dextents) Alias template dextents [[mdspan.extents.dextents]](mdspan.extents.dextents)

[ð](#lib:dextents)

`template<class IndexType, size_t Rank>
  using dextents = see below;
`

[1](#dextents-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21495)

*Result*: A type E that is a specialization of extents such that E​::​rank() == Rank && E​::​rank() == E​::​rank_dynamic() is true, andE​::​index_type denotes IndexType[.](#dextents-1.sentence-1)

#### [23.7.3.3.7](#dims) Alias template dims [[mdspan.extents.dims]](mdspan.extents.dims)

[ð](#lib:dims)

`template<size_t Rank, class IndexType = size_t>
  using dims = see below;
`

[1](#dims-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L21511)

*Result*: A type E that is a specialization of extents such that E​::​rank() == Rank && E​::​rank() == E​::​rank_dynamic() is true, andE​::​index_type denotes IndexType[.](#dims-1.sentence-1)
