# Multidimensional bounds, index and array_view, revision 3

ISO/IEC JTC1 SC22 WG21 N4087 - 2014-07-01

Reply-to:
Łukasz Mendakiewicz <lukaszme@microsoft.com>
Herb Sutter <hsutter@microsoft.com>

## Overview

Revision 3 incorporates the feedback received in Rapperswil from LEWG and some other minor fixes:

1. Fixed specification of `initializer_list` constructors in `index` and `bounds` — the size of the `initializer_list` cannot always be verified at the compile-time, so the check must be expressed as "Requires" instead of SFINAE.

- Note: LEWG suggested to try using constrained variadic constructor template instead of `initializer_list` constructor, as the former might reject the wrong number of arguments in the compile time. We have found that while we can almost fully emulate the behavior of e.g. `index<2>{1,2}` implemented as "`initializer_list` with constrained size", the solution comes with the cost of high complexity in specifying the intended behavior — basically duplicating the language rules in the library. It would probably also be fragile if any of the language rules change. Ultimately we have decided that the added diagnosability benefit is not worth the cost.

2. Improved the wording for `operator-` and `operator-=` in `index` and `bounds` to avoid negating `rhs`.
3. Added `(const_)iterator` type aliases in `bounds`.
4. Slightly improved the wording in the `array_view(bounds_type bounds, pointer ptr)` specification.
5. Slightly improved the wording in the `bounds_iterator::operator++` specification.
6. Tightened the specification of views to prevent derived-to-base conversions.
7. `Made array_view(Viewable&&)` and `array_view(ArrayType&)` constructors not "explicit".
8. Fixed `array_view(bounds_type bounds, pointer ptr)` constructor not to be "noexcept".
9. Provided a definition for "uniformly strided".
10. Renamed "generalized views" to "views".
11. Changed `index` and `bounds` arithmetic operators from accepting any `ArithmeticType` to only `value_type`/`ptrdiff_t`.
12. Improved the overload resolution for `array_view` constructors so that all conversions between related `array_view`s can be `noexcept`.
13. Slightly improved consistency and mistakes between "this constructor" and "this function" wording.

## Acknowledgements

Thanks to Stephan T. Lavavej and the members of LEWG for the suggested improvements. Thanks to the interlocutors at ISO C++ Standard - Future Proposals forum for the valuable feedback. Thanks to all correspondents expressing feedback in private emails.

## Wording changes

The proposed wording changes are relative to the contents of N3936.

### 17.6.1.2 Headers [headers]

Edit within paragraph 2 as follows.

> The C++ standard library provides 5355 C++ library headers, as shown in Table 14.

Add the following items to table 14.

> `<array_view>`
> `<coordinate>`

### Chapter 20 General utilities library [utilities]

Add a row to table 44 as follows.

> Table 44: General utilities library summary
> Subclause | Header(s)
> --- | ---
> 20.2 Utility components | `<utility>`
> 20.3 Pairs | `<utility>`
> 20.4 Tuples | `<tuple>`
> 20.5 Compile-time integer sequences | `<utility>`
> 20.6 Multidimensional coordinates | `<coordinate>`
> 20.67 Fixed-size sequences of bits | `<bitset> <memory>`
> 20.78 Memory | `<cstdlib> <cstring>`
> 20.89 Smart pointers | `<memory>`
> 20.910 Function objects | `<functional>`
> 20.1011 Type traits | `<type_traits>`
> 20.1112 Compile-time rational arithmetic | `<ratio>`
> 20.1213 Time utilities | `<chrono> <ctime>`
> 20.1314 Scoped allocators | `<scoped_allocator>`
> 20.1415 Type indexes | `<typeindex>`

### 20.6 Multidimensional coordinates [coord]

Add a new section after the `intseq` section.

### 20.6.1 In general [coord.general]

Add a new section:

> This subclause describes the multidimensional coordinates library. It provides a class template `index` which represents a mathematical vector in an N-dimensional discrete space, a class template `bounds` which represents axis-aligned rectangular bounds in such a space, and a class template `bounds_iterator` which allows iteration over such a space.

Add a new synopsis:

> Header `<coordinate>` synopsis

>     #include <initializer_list>

>     namespace std {
>       // [coord.index], class template index
>       template <int Rank> class index;

>       // [coord.index.arith], index arithmetic
>       template <int Rank>
>         constexpr index<Rank> operator*(ptrdiff_t v, const index<Rank>& rhs);

>       // [coord.bounds], class template bounds
>       template <int Rank> class bounds;

>       // [coord.bounds.arith], bounds arithmetic
>       template <int Rank>
>         constexpr bounds<Rank> operator+(const index<Rank>& lhs, const bounds<Rank>& rhs);
>       template <int Rank>
>         constexpr bounds<Rank> operator*(ptrdiff_t v, const bounds<Rank>& rhs);

>       // [coord.bounds.iterator], class template bounds_iterator
>       template <int Rank> class bounds_iterator;

>       template <int Rank>
>         bounds_iterator<Rank> operator+(typename bounds_iterator<Rank>::difference_type n,
>                                         const bounds_iterator<Rank>& rhs);
>     }

### 20.6.2 Class template `index` [coord.index]

Add a new section:

>     namespace std {
>       template <int Rank>
>       class index {
>       public:
>         // constants and types
>         static constexpr int rank = Rank;
>         using reference           = ptrdiff_t&;
>         using const_reference     = const ptrdiff_t&;
>         using size_type           = size_t;
>         using value_type          = ptrdiff_t;

>         // [coord.index.cnstr], index construction
>         constexpr index() noexcept;
>         constexpr index(value_type v) noexcept;
>         constexpr index(initializer_list<value_type> il);

>         // [coord.index.eq], index equality
>         constexpr bool operator==(const index& rhs) const noexcept;
>         constexpr bool operator!=(const index& rhs) const noexcept;

>         // [coord.index.cmpt], index component access
>         constexpr reference       operator[](size_type n);
>         constexpr const_reference operator[](size_type n) const;

>         // [coord.index.arith], index arithmetic
>         constexpr index  operator+(const index& rhs) const;
>         constexpr index  operator-(const index& rhs) const;
>         constexpr index& operator+=(const index& rhs);
>         constexpr index& operator-=(const index& rhs);

>         constexpr index& operator++();
>         constexpr index  operator++(int);
>         constexpr index& operator--();
>         constexpr index  operator--(int);

>         constexpr index  operator+() const noexcept;
>         constexpr index  operator-() const;

>         constexpr index  operator*(value_type v) const;
>         constexpr index  operator/(value_type v) const;
>         constexpr index& operator*=(value_type v);
>         constexpr index& operator/=(value_type v);
>       };
>     }

### 20.6.2.1 General requirements [coord.index.require]

Add a new section:

> If `Rank` is less than 1 the program is ill-formed.

### 20.6.2.2 Construction [coord.index.cnstr]

Add a new section:

> `constexpr index() noexcept;`

> > Effects: Zero-initializes each component.

> `constexpr index(value_type v) noexcept;`

> > Effects: Initializes the 0th component of `*this` with `v`.

> > Remarks: This constructor shall not participate in overload resolution unless `Rank` is 1.

> `constexpr index(initializer_list<value_type> il);`

> > Requires: `il.size() == Rank`.

> > Effects: For all i in the range `[0, Rank)`, initializes the ith component of `*this` with `*(il.begin() + i)`.

### 20.6.2.3 Equality [coord.index.eq]

Add a new section:

> `constexpr bool operator==(const index& rhs) const noexcept;`

> > Returns: `true` if `(*this)[i] == rhs[i]` for all `i` in the range `[0, Rank)`, otherwise `false`.

> `constexpr bool operator!=(const index& rhs) const noexcept;`

> > Returns: `!(*this == rhs)`.

### 20.6.2.4 Component access [coord.index.cmpt]

Add a new section:

> `constexpr reference operator[](size_type n);`
> `constexpr const_reference operator[](size_type n) const;`

> > Requires: `n < Rank`.

> > Returns: A reference to the `n`th component of `*this`.

### 20.6.2.5 Arithmetic [coord.index.arith]

Add a new section:

> `constexpr index operator+(const index& rhs) const;`

> > Returns: `index<Rank>{*this} += rhs`.

> `constexpr index operator-(const index& rhs) const;`

> > Returns: `index<Rank>{*this} -= rhs`.

> `constexpr index& operator+=(const index& rhs);`

> > Effects: For all i in the range `[0, Rank)`, adds the ith component of `rhs` to the ith component of `*this` and stores the sum in the ith component of `*this`.

> > Returns: `*this`.

> `constexpr index& operator-=(const index& rhs);`

> > Effects: For all i in the range `[0, Rank)`, subtracts the ith component of `rhs` from the ith component of `*this` and stores the difference in the ith component of `*this`.

> > Returns: `*this`.

> `constexpr index& operator++();`

> > Requires: `Rank == 1`.

> > Effects: `++(*this)[0]`.

> > Returns: `*this`.

> `constexpr index operator++(int);`

> > Requires: `Rank == 1`.

> > Returns: `index<Rank>{(*this)[0]++}`.

> `constexpr index& operator--();`

> > Requires: `Rank == 1`.

> > Effects: `--(*this)[0]`.

> > Returns: `*this`.

> `constexpr index operator--(int);`

> > Requires: `Rank == 1`.

> > Returns: `index<Rank>{(*this)[0]--}`.

> `constexpr index operator+() const noexcept;`

> > Returns: `*this`.

> `constexpr index operator-() const;`

> > Returns: A copy of `*this` with each component negated.

> `constexpr index operator*(value_type v) const;`

> > Returns: `index<Rank>{*this} *= v`.

> `constexpr index operator/(value_type v) const;`

> > Returns: `index<Rank>{*this} /= v`.

> `constexpr index& operator*=(value_type v);`

> > Effects: For all i in the range `[0, Rank)`, multiplies the ith component of `*this` by `v` and stores the product in the ith component of `*this`.

> > Returns: `*this`.

> `constexpr index& operator/=(value_type v);`

> > Effects: For all i in the range `[0, Rank)`, divides the ith component of `*this` by `v` and stores the quotient in the ith component of `*this`.

> > Returns: `*this`.

>     template <int Rank>
>       constexpr index<Rank> operator*(ptrdiff_t v, const index<Rank>& rhs);

> > Returns: `index<Rank>{rhs} *= v`.

### 20.6.3 Class template `bounds` [coord.bounds]

Add a new section:

>     namespace std {
>       template <int Rank>
>       class bounds {
>       public:
>         // constants and types
>         static constexpr int rank = Rank;
>         using reference           = ptrdiff_t&;
>         using const_reference     = const ptrdiff_t&;
>         using iterator            = bounds_iterator<Rank>;
>         using const_iterator      = bounds_iterator<Rank>;
>         using size_type           = size_t;
>         using value_type          = ptrdiff_t;

>         // [coord.bounds.cnstr], bounds construction
>         constexpr bounds() noexcept;
>         constexpr bounds(value_type v);
>         constexpr bounds(initializer_list<value_type> il);

>         // [coord.bounds.eq], bounds equality
>         constexpr bool operator==(const bounds& rhs) const noexcept;
>         constexpr bool operator!=(const bounds& rhs) const noexcept;

>         // [coord.bounds.obs], bounds observers
>         constexpr size_type size() const noexcept;
>         constexpr bool      contains(const index<Rank>& idx) const noexcept;

>         // [coord.bounds.iter], bounds iterators
>         const_iterator begin() const noexcept;
>         const_iterator end() const noexcept;

>         // [coord.bounds.cmpt], bounds component access
>         constexpr reference       operator[](size_type n);
>         constexpr const_reference operator[](size_type n) const;

>         // [coord.bounds.arith], bounds arithmetic
>         constexpr bounds  operator+(const index<Rank>& rhs) const;
>         constexpr bounds  operator-(const index<Rank>& rhs) const;
>         constexpr bounds& operator+=(const index<Rank>& rhs);
>         constexpr bounds& operator-=(const index<Rank>& rhs);

>         constexpr bounds  operator*(value_type v) const;
>         constexpr bounds  operator/(value_type v) const;
>         constexpr bounds& operator*=(value_type v);
>         constexpr bounds& operator/=(value_type v);
>       };
>     }

### 20.6.3.1 General requirements [coord.bounds.require]

Add a new section:

> If `Rank` is less than 1 the program is ill-formed.

> Every mutating operation on an object `b` of type `bounds` shall leave the object in a state that satisfies the following constraints:

> 1. `b[i] >= 0` for all `i` in the range `[0, Rank)`.
> 2. The product of `b[i]` for all `i` in the range `[0, Rank)` is less than or equal to `numeric_limits<ptrdiff_t>::max()`.

> Otherwise, the behavior is undefined.

### 20.6.3.2 Construction [coord.bounds.cnstr]

Add a new section:

> `constexpr bounds() noexcept;`

> > Effects: Zero-initializes each component.

> `constexpr bounds(value_type v);`

> > Effects: Initializes the 0th component of `*this` with `v`.

> > Remarks: This constructor shall not participate in overload resolution unless `Rank` is 1.

> `constexpr bounds(initializer_list<value_type> il);`

> > Requires: `il.size() == Rank`.

> > Effects: For all i in the range `[0, Rank)`, initializes the ith component of `*this` with `*(il.begin() + i)`.

### 20.6.3.3 Equality [coord.bounds.eq]

Add a new section:

> `constexpr bool operator==(const bounds& rhs) const noexcept;`

> > Returns: `true` if `(*this)[i] == rhs[i]` for all `i` in the range `[0, Rank)`, otherwise `false`.

> `constexpr bool operator!=(const bounds& rhs) const noexcept;`

> > Returns: `!(*this == rhs)`.

### 20.6.3.4 Observers [coord.bounds.obs]

Add a new section:

> `constexpr size_type size() const noexcept;`

> > Returns: The product of all components of `*this`.

> `constexpr bool contains(const index<Rank>& idx) const noexcept;`

> > Returns: `true` if `0 <= idx[i]` and `idx[i] < (*this)[i]` for all `i` in the range `[0, Rank)`, otherwise `false`.

### 20.6.3.5 Iterators [coord.bounds.iter]

Add a new section:

> `bounds_iterator<Rank> begin() const noexcept;`

> > Returns: A `bounds_iterator` referring to the first element of the space defined by `*this` such that `*begin() == index<Rank>{}` if `size() != 0`, `begin() == end()` otherwise.

> `bounds_iterator<Rank> end() const noexcept;`

> > Returns: A `bounds_iterator` which is the past-the-end iterator for the space defined by `*this`.

### 20.6.3.6 Component access [coord.bounds.cmpt]

Add a new section:

> `constexpr reference operator[](size_type n);`
> `constexpr const_reference operator[](size_type n) const;`

> > Requires: `n < Rank`.

> > Returns: A reference to the `n`th component of `*this`.

### 20.6.3.7 Arithmetic [coord.bounds.arith]

Add a new section:

> `constexpr bounds operator+(const index<Rank>& rhs) const;`

> > Returns: `bounds<Rank>{*this} += rhs`.

> `constexpr bounds operator-(const index<Rank>& rhs) const;`

> > Returns: `bounds<Rank>{*this} -= rhs`.

> `constexpr bounds& operator+=(const index<Rank>& rhs);`

> > Effects: For all i in the range `[0, Rank)`, adds the ith component of `rhs` to the ith component of `*this` and stores the sum in the ith component of `*this`.

> > Returns: `*this`.

> `constexpr bounds& operator-=(const index<Rank>& rhs);`

> > Effects: For all i in the range `[0, Rank)`, subtracts the ith component of `rhs` from the ith component of `*this` and stores the difference in the ith component of `*this`.

> > Returns: `*this`.

> `constexpr bounds operator*(value_type v) const;`

> > Returns: `bounds<Rank>{*this} *= v`.

> `constexpr bounds operator/(value_type v) const;`

> > Returns: `bounds<Rank>{*this} /= v`.

> `constexpr bounds& operator*=(value_type v);`

> > Effects: For all i in the range `[0, Rank)`, multiplies the ith component of `*this` by `v` and stores the product in the ith component of `*this`.

> > Returns: `*this`.

> `constexpr bounds& operator/=(value_type v);`

> > Effects: For all i in the range `[0, Rank)`, divides the ith component of `*this` by `v` and stores the quotient in the ith component of `*this`.

> > Returns: `*this`.

>     template <int Rank>
>       constexpr bounds<Rank> operator+(const index<Rank>& lhs, const bounds<Rank>& rhs);

> > Returns: `bounds<Rank>{rhs} += lhs`.

>     template <int Rank>
>       constexpr bounds<Rank> operator*(ptrdiff_t v, const bounds<Rank>& rhs);

> > Returns: `bounds<Rank>{rhs} *= v`.

### 20.6.4 Class template `bounds_iterator` [coord.bounds.iterator]

Add a new section:

>     namespace std {
>       template <int Rank>
>       class bounds_iterator
>       {
>       public:
>         using iterator_category = random_access_iterator_tag;
>         using value_type        = index<Rank>;
>         using difference_type   = ptrdiff_t;
>         using pointer           = unspecified;   // See [coord.bounds.iterator.require]
>         using reference         = const index<Rank>;

>         bool operator==(const bounds_iterator& rhs) const;
>         bool operator!=(const bounds_iterator& rhs) const;
>         bool operator<(const bounds_iterator& rhs) const;
>         bool operator<=(const bounds_iterator& rhs) const;
>         bool operator>(const bounds_iterator& rhs) const;
>         bool operator>=(const bounds_iterator& rhs) const;

>         bounds_iterator& operator++();
>         bounds_iterator  operator++(int);
>         bounds_iterator& operator--();
>         bounds_iterator  operator--(int);

>         bounds_iterator  operator+(difference_type n) const;
>         bounds_iterator& operator+=(difference_type n);
>         bounds_iterator  operator-(difference_type n) const;
>         bounds_iterator& operator-=(difference_type n);

>         difference_type  operator-(const bounds_iterator& rhs) const;

>         reference operator*() const;
>         pointer   operator->() const;
>         reference operator[](difference_type n) const;

>       private:
>         bounds<Rank> bnd_;  // exposition only
>         index<Rank>  idx_;  // exposition only
>       };
>     }

### 20.6.4.1 General requirements [coord.bounds.iterator.require]

Add a new section:

> If `Rank` is less than 1 the program is ill-formed.

> `pointer` shall be an unspecified type such that for a `bounds_iterator it` the expression `it->E` is equivalent to `(*it).E` and that for an object `p` of type `pointer` the expression `p->E` yields the same result irrespective of whether the state of the `bounds_iterator` object has changed or its lifetime has ended.

### 20.6.4.2 Functions [coord.bounds.iterator.func]

Add a new section:

> Unless otherwise specified below, the member functions of `bounds_iterator` adhere to the operational semantics in Tables 107, 109, 110, and 111.

> `bool operator==(const bounds_iterator& rhs) const;`

> > Requires: `*this` and `rhs` are iterators over the same `bounds` object.

> > Returns: `idx_ == rhs.idx_`.

> `bounds_iterator& operator++();`

> > Requires: `*this` is not the past-the-end iterator.

> > Effects: Equivalent to:

> > >     for(auto i = Rank - 1; i >= 0; --i)
> > >     {
> > >       if(++idx_[i] < bnd_[i])
> > >         return;
> > >       idx_[i] = 0;
> > >     }
> > >     idx_ = unspecified past-the-end value;

> > Returns: `*this`.

> > [Note: The effective iteration order is congruent with iterating over a multidimensional array starting with the least significant dimension. —end note]

> `bounds_iterator& operator--();`

> > Requires: There exists a `bounds_iterator<Rank> it` such that `*this == ++it`.

> > Effects: `*this = it`.

> > Returns: `*this`.

> `reference operator*() const;`

> > Returns: `idx_`.

### Chapter 23 Containers library [containers]

Edit within paragraph 2 as follows.

> The following subclauses describe container requirements, and components for sequence containers and associative containers, and views, as summarized in Table 95.

Add a row to table 95 as follows.

> Table 95: Containers library summary
> Subclause | Header(s)
> --- | ---
> 23.2 Requirements |
> 23.3 Sequence containers | `<array> <deque> <forward_list> <list> <vector>`
> 23.4 Associative containers | `<map> <set>`
> 23.5 Unordered associative containers | `<unordered_map> <unordered_set>`
> 23.6 Container adaptors | `<queue> <stack>`
> 23.7 Views | `<array_view>`

### 23.7 Views [views]

Add a new section after the `container.adaptors` section.

### 23.7.1 In general [views.general]

Add a new section:

> The header `<array_view>` defines the views `array_view` and `strided_array_view`.

> The objects in any valid range [ptr, ptr + size) are uniformly strided for a specific N-dimensional logical representation V parameterized by an N-dimensional vector stride if for every element in V the mapping between the location in V expressed as an N-dimensional vector idx and the address of the corresponding object in [ptr, ptr + size) can be computed as: ptr + idx · stride.

> An `array_view` is a potentially multidimensional view on a sequence of uniformly strided objects of a uniform type, contiguous in the least significant dimension.

> A `strided_array_view` is a potentially multidimensional view on a sequence of uniformly strided objects of a uniform type.

Add a new synopsis:

> Header `<array_view>` synopsis

>     namespace std {
>       // [arrayview], class template array_view
>       template <class T, int Rank> class array_view;

>       // [stridedarrayview], class template strided_array_view
>       template <class T, int Rank> class strided_array_view;
>     }

### 23.7.2 View types requirements [views.require]

Add a new section:

> `T` shall be an object type. [Note: The type can be cv-qualified, resulting in semantics similar to the semantics of a pointer to cv-qualified type. —end note]

> If `Rank` is less than 1 the program is ill-formed.

> Any operation that invalidates a pointer in the range on which a view was created invalidates pointers and references returned from the view's functions.

> Define `VIEW_ACCESS(data, idx, stride, rank)` as `*(data + offset)` where [Editorial note: The following expression should be formatted as LaTeX code —end note] `offset = \sum_{i=0}^{rank - 1} idx_i \times stride_i`, idxi = `idx[`i`]`, and stridei = `stride[`i`]`.

### 23.7.3 Class template `array_view` [arrayview]

Add a new section:

>     namespace std {
>       template <class T, int Rank = 1>
>       class array_view {
>       public:
>         // constants and types
>         static constexpr int rank = Rank;
>         using index_type          = index<Rank>;
>         using bounds_type         = bounds<Rank>;
>         using size_type           = size_t;
>         using value_type          = T;
>         using pointer             = T*;
>         using reference           = T&;

>         // [arrayview.cons], array_view constructors, copy, and assignment
>         constexpr array_view() noexcept;

>         template <class Viewable>
>           constexpr array_view(Viewable&& vw);
>         template <class U, int AnyRank>
>           constexpr array_view(const array_view<U, AnyRank>& rhs) noexcept;
>         template <class ArrayType>
>           constexpr array_view(ArrayType& arr) noexcept;

>         template <class U>
>           constexpr array_view(const array_view<U, Rank>& rhs) noexcept;

>         template <class Viewable>
>           constexpr array_view(bounds_type bounds, Viewable&& vw);
>         constexpr array_view(bounds_type bounds, pointer ptr);

>         template <class U>
>           constexpr array_view& operator=(const array_view<U, Rank>& rhs) noexcept;

>         // [arrayview.obs], array_view observers
>         constexpr bounds_type bounds() const noexcept;
>         constexpr size_type   size() const noexcept;
>         constexpr index_type  stride() const noexcept;
>         constexpr pointer     data() const noexcept;

>         // [arrayview.elem], array_view element access
>         constexpr reference operator[](const index_type& idx) const;

>         // [arrayview.subview], array_view slicing and sectioning
>         constexpr array_view<T, Rank - 1>
>           operator[](ptrdiff_t slice) const;      // only if Rank > 1
>         constexpr strided_array_view<T, Rank>
>           section(const index_type& origin, const bounds_type& section_bnd) const;
>         constexpr strided_array_view<T, Rank>
>           section(const index_type& origin) const;
>       };
>     }

### 23.7.3.1 `array_view` constructors, copy, and assignment [arrayview.cons]

Add a new section:

> For the purpose of this subclause, `Viewable` on `U` is a type satisfying the requirements set out in Table 104. In these definitions, let `v` denote an expression of `Viewable` on `U` type.

> Table 104: `Viewable` on `U` requirements
> Expression | Return type | Operational semantics
> --- | --- | ---
> `v.size()` | Convertible to `ptrdiff_t` |
> `v.data()` | Type `T*` such that `T*` is implicitly convertible to `U*`, and `is_same<remove_cv_t<T>, remove_cv_t<U>>::value` is `true`. | `static_cast<U*>(v.data())` points to a contiguous sequence of at least `v.size()` objects of (possibly cv-qualified) type `remove_cv_t<U>`.

> [Example: The type `vector<int>` ([vector]) meets the requirements of all of the following: `Viewable` on `int`, `Viewable` on `const int`, `Viewable` on `volatile int`, and `Viewable` on `const volatile int`. —end example]

> `constexpr array_view() noexcept;`

> > Postconditions: `bounds().size() == 0` and `data() == nullptr`.

>     template <class Viewable>
>       constexpr array_view(Viewable&& vw);

> > Requires: `vw` shall satisfy the requirements of `Viewable` on `value_type`.

> > Postconditions: `bounds().size() == vw.size()` and `data() == vw.data()`.

> > Remarks: This constructor shall not participate in overload resolution unless `Rank` is 1, `Viewable` satisfies the syntactic requirements set in Table 104 for `Viewable` on `value_type`, and `decay_t<Viewable>` is not `array_view<U, N>` for any `U` and `N` [Footnote: This provision ensures that either the following or the implicit copy constructor — both of which are `noexcept(true)` — will be selected by overload resolution instead. —end footnote].

>     template <class U, int AnyRank>
>       constexpr array_view(const array_view<U, AnyRank>& rhs) noexcept;

> > Postconditions: `bounds().size() == rhs.size()` and `data() == rhs.data()`.

> > Remarks: This constructor shall not participate in overload resolution unless `Rank` is 1, `is_convertible<add_pointer_t<U>, pointer>::value` is `true`, and `is_same<remove_cv_t<U>, remove_cv_t<value_type>>::value` is `true`.

>     template <class ArrayType>
>       constexpr array_view(ArrayType& arr) noexcept;

> > Postconditions: `bounds()[i] == extent<ArrayType, i>::value` for all `i` in the range `[0, Rank)`, and `data()` is equal to the address of the initial element in `arr`.

> > Remarks: This constructor shall not participate in overload resolution unless `is_convertible<add_pointer_t<remove_all_extents_t<ArrayType>>, pointer>::value` is `true`, `is_same<remove_cv_t<remove_all_extents_t<ArrayType>>, remove_cv_t<value_type>>::value` is `true`, and `rank<ArrayType>::value == Rank`.

> > [Example:

> >     char a[3][1][4] {{{'H', 'i'}}};
> >     auto av = array_view<char, 3>{a};
> >     // the following assertions hold:
> >     assert((av.bounds() == bounds<3>{3, 1, 4}));
> >     assert((av[{0, 0, 0}] == 'H'));

> > —end example]

>     template <class U>
>       constexpr array_view(const array_view<U, Rank>& rhs) noexcept;

> > Postconditions: `bounds() == rhs.bounds()` and `data() == rhs.data()`.

> > Remarks: This constructor shall not participate in overload resolution unless `is_convertible<add_pointer_t<U>, pointer>::value` is `true` and `is_same<remove_cv_t<U>, remove_cv_t<value_type>>::value` is `true`.

>     template <class Viewable>
>       constexpr array_view(bounds_type bounds, Viewable&& vw);

> > Requires: `bounds.size() <= vw.size()`.

> > Postconditions: `bounds() == bounds` and `data() == vw.data()`.

> > Remarks: This constructor shall not participate in overload resolution unless `Viewable` satisfies the syntactic requirements set in Table 104 for `Viewable` on `value_type`.

> > [Note: This constructor may be used to create an `array_view` with a different rank and/or bounds than the original `array_view`, i.e. reshape the view. —end note]

>     constexpr array_view(bounds_type bounds, pointer ptr);

> > Requires: `[ptr, ptr + bounds.size())` is a valid range.

> > Postconditions: `bounds() == bounds` and `data() == ptr`.

>     template <class U>
>       constexpr array_view& operator=(const array_view<U, Rank>& rhs) noexcept;

> > Postconditions: `bounds() == rhs.bounds` and `data() == rhs.data()`.

> > Returns: `*this`.

> > Remarks: This function shall not participate in overload resolution unless `is_convertible<add_pointer_t<U>, pointer>::value` is `true` and `is_same<remove_cv_t<U>, remove_cv_t<value_type>>::value` is `true`.

### 23.7.3.2 `array_view` observers [arrayview.obs]

Add a new section:

> `constexpr bounds_type bounds() const noexcept;`

> > Returns: The bounds of the view.

> `constexpr size_type size() const noexcept;`

> > Returns: `bounds().size()`.

> `constexpr index_type stride() const noexcept;`

> > Returns: An `index_type` such that:

> > - `stride()[i] == 1`, where `i == Rank - 1`.
> > - `stride()[i] == stride()[i + 1] * bounds()[i + 1]`, where `0 <= i` and `i < Rank - 1`.

> `constexpr pointer data() const noexcept;`

> > Returns: A pointer to the contiguous sequence on which the view was created.

### 23.7.3.3 `array_view` element access [arrayview.elem]

Add a new section:

> `constexpr reference operator[](const index_type& idx) const;`

> > Requires: `bounds().contains(idx) == true`.

> > Returns: `VIEW_ACCESS(data(), idx, stride(), Rank)`.

### 23.7.3.4 `array_view` slicing and sectioning [arrayview.subview]

Add a new section:

>     constexpr array_view<T, Rank - 1>
>       operator[](ptrdiff_t slice) const;

> > Requires: `slice < bounds()[0]`.

> > Returns: A view such that the initial element is `(*this)[{slice, 0, 0, …, 0}]`, and the bounds are `{bounds1, bounds2, …, boundsRank - 1}`, where `boundsi = bounds()[i]`.

> > Remarks: This function shall not participate in overload resolution unless `Rank > 1`.

>     constexpr strided_array_view<T, Rank>
>       section(const index_type& origin, const bounds_type& section_bnd) const;

> > Requires: `bounds().contains(origin + idx) == true` for any `index<Rank> idx` such that `section_bnd.contains(idx) == true`.

> > Returns: A strided view such that the initial element is `(*this)[origin]`, the stride is `stride()`, and the bounds are `section_bnd`.

>     constexpr strided_array_view<T, Rank>
>       section(const index_type& origin) const;

> > Requires: `bounds().contains(origin + idx) == true` for any `index<Rank> idx` such that `(bounds() - origin).contains(idx) == true`.

> > Returns: A strided view such that the initial element is `(*this)[origin]`, the stride is `stride()`, and the bounds are `(bounds() - origin)`.

### 23.7.4 Class template `strided_array_view` [stridedarrayview]

Add a new section:

>     namespace std {
>       template <class T, int Rank = 1>
>       class strided_array_view {
>       public:
>         // constants and types
>         static constexpr int rank = Rank;
>         using index_type          = index<Rank>;
>         using bounds_type         = bounds<Rank>;
>         using size_type           = size_t;
>         using value_type          = T;
>         using pointer             = T*;
>         using reference           = T&;

>         // [stridedarrayview.cons], strided_array_view constructors, copy, and assignment
>         constexpr strided_array_view() noexcept;

>         template <class U>
>           constexpr strided_array_view(const array_view<U, Rank>& rhs) noexcept;
>         template <class U>
>           constexpr strided_array_view(const strided_array_view<U, Rank>& rhs) noexcept;

>         constexpr strided_array_view(bounds_type bounds, index_type stride, pointer ptr);

>         template <class U>
>           constexpr strided_array_view& operator=(const strided_array_view<U, Rank>& rhs) noexcept;

>         // [stridedarrayview.obs], strided_array_view observers
>         constexpr bounds_type bounds() const noexcept;
>         constexpr size_type   size() const noexcept;
>         constexpr index_type  stride() const noexcept;

>         // [stridedarrayview.elem], strided_array_view element access
>         constexpr reference operator[](const index_type& idx) const;

>         // [stridedarrayview.subview], strided_array_view slicing and sectioning
>         constexpr strided_array_view<T, Rank - 1>
>           operator[](ptrdiff_t slice) const;      // only if Rank > 1
>         constexpr strided_array_view<T, Rank>
>           section(const index_type& origin, const bounds_type& section_bnd) const;
>         constexpr strided_array_view<T, Rank>
>           section(const index_type& origin) const;

>       private:
>         pointer data_;  // exposition only
>       };
>     }

### 23.7.4.1 `strided_array_view` constructors, copy, and assignment [stridedarrayview.cons]

Add a new section:

> `constexpr strided_array_view() noexcept;`

> > Postconditions: `bounds().size() == 0`, `stride() == index_type{}`, and `data_ == nullptr`.

>     template <class U>
>       constexpr strided_array_view(const array_view<U, Rank>& rhs) noexcept;
>     template <class U>
>       constexpr strided_array_view(const strided_array_view<U, Rank>& rhs) noexcept;

> > Postconditions: `bounds() == rhs.bounds()`, `stride() == rhs.stride()`, and correspondingly: `data_ == rhs.data()`, `data_ == rhs.data_`.

> > Remarks: These constructors shall not participate in overload resolution unless `is_convertible<add_pointer_t<U>, pointer>::value` is `true` and `is_same<remove_cv_t<U>, remove_cv_t<value_type>>::value` is `true`.

>     constexpr strided_array_view(bounds_type bounds, index_type stride, pointer ptr);

> > Requires: For any `index<Rank> idx` such that `bounds.contains(idx)`:

> > - The expression `idx[i] * stride[i]` shall be well formed and shall have well defined behavior [Note: It follows that the result does not overflow type `ptrdiff_t`. —end note] for all i in the range `[0, Rank)`.
> > - The expression `VIEW_ACCESS(ptr, idx, stride, Rank)` shall be well formed and shall have well defined behavior.

> > Postconditions: `bounds() == bounds`, `stride() == stride`, and `data_ == ptr`.

>     template <class U>
>       constexpr strided_array_view& operator=(const strided_array_view<U, Rank>& rhs) noexcept;

> > Postconditions: `bounds() == rhs.bounds()`, `stride() == rhs.stride()`, and `data_ == rhs.data_`.

> > Returns: `*this`.

> > Remarks: This function shall not participate in overload resolution unless `is_convertible<add_pointer_t<U>, pointer>::value` is `true` and `is_same<remove_cv_t<U>, remove_cv_t<value_type>>::value` is `true`.

### 23.7.4.2 `strided_array_view` observers [stridedarrayview.obs]

Add a new section:

> `constexpr bounds_type bounds() const noexcept;`

> > Returns: The bounds of the view.

> `constexpr size_type size() const noexcept;`

> > Returns: `bounds().size()`.

> `constexpr index_type stride() const noexcept;`

> > Returns: The stride of the view.

### 23.7.4.3 `strided_array_view` element access [stridedarrayview.elem]

Add a new section:

> `constexpr reference operator[](const index_type& idx) const;`

> > Requires: `bounds().contains(idx) == true`.

> > Returns: `VIEW_ACCESS(data_, idx, stride(), Rank)`.

### 23.7.4.4 `strided_array_view` slicing and sectioning [stridedarrayview.subview]

Add a new section:

>     constexpr strided_array_view<T, Rank - 1>
>       operator[](ptrdiff_t slice) const;

> > Requires: `slice < bounds()[0]`.

> > Returns: A strided view such that the initial element is `(*this)[{slice, 0, 0, …, 0}]`, the bounds are `{bounds1, bounds2, …, boundsRank - 1}`, and the stride is `{stride1, stride2, …, strideRank - 1}` ; where `boundsi = bounds()[i]`, and `stridei = stride()[i]`.

> > Remarks: This function shall not participate in overload resolution unless `Rank > 1`.

>     constexpr strided_array_view<T, Rank>
>       section(const index_type& origin, const bounds_type& section_bnd) const;

> > Requires: `bounds().contains(origin + idx) == true` for any `index<Rank> idx` such that `section_bnd.contains(idx) == true`.

> > Returns: A strided view such that the initial element is `(*this)[origin]`, the stride is `stride()`, and the bounds are `section_bnd`.

>     constexpr strided_array_view<T, Rank>
>       section(const index_type& origin) const;

> > Requires: `bounds().contains(origin + idx) == true` for any `index<Rank> idx` such that `(bounds() - origin).contains(idx) == true`.

> > Returns: A strided view such that the initial element is `(*this)[origin]`, the stride is `stride()`, and the bounds are `(bounds() - origin)`.

### 24.7 range access [iterator.range]

Edit within paragraph 1 as follows.

> In addition to being available via inclusion of the `<iterator>` header, the function templates in 24.7 are available when any of the following headers are included: `<array>`, `<coordinate>`, `<deque>`, `<forward_list>`, `<list>`, `<map>`, `<regex>`, `<set>`, `<string>`, `<unordered_map>`, `<unordered_set>`, and `<vector>`.