Multidimensional bounds, index and array_view, revision 2

ISO/IEC JTC1 SC22 WG21 N3976 - 2014-05-21

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

Overview

The feedback we have received during the Issaquah meeting was to prepare the wording for the proposal as-is. Consequently, only the wording (with minor improvements) is provided in this version. Interested readers should find the rationale, background information and design discussion in the previous revision of the proposal, viz. N3851.

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
SubclauseHeader(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.

Throughout this subclause, if a function template is called with a template argument type ArithmeticType such that is_arithmetic<ArithmeticType>::value is false, then the function shall not participate in overload resolution.

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 <class ArithmeticType, int Rank>
    constexpr index<Rank> operator*(ArithmeticType 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 <class ArithmeticType, int Rank>
    constexpr bounds<Rank> operator*(ArithmeticType 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) noexcept;

    // [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;

    template <class ArithmeticType> constexpr index  operator*(ArithmeticType v) const;
    template <class ArithmeticType> constexpr index  operator/(ArithmeticType v) const;
    template <class ArithmeticType> constexpr index& operator*=(ArithmeticType v);
    template <class ArithmeticType> constexpr index& operator/=(ArithmeticType 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 function shall not participate in overload resolution unless Rank is 1.

constexpr index(initializer_list<value_type> il) noexcept;

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

Remarks: This function shall not participate in overload resolution unless il.size() is Rank.

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 nth 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);

Returns: *this += -rhs.

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.

template <class ArithmeticType> constexpr index operator*(ArithmeticType v) const;

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

template <class ArithmeticType> constexpr index operator/(ArithmeticType v) const;

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

template <class ArithmeticType> constexpr index& operator*=(ArithmeticType 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.

template <class ArithmeticType> constexpr index& operator/=(ArithmeticType 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 <class ArithmeticType, int Rank>
  constexpr index<Rank> operator*(ArithmeticType 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 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
    bounds_iterator<Rank> begin() const noexcept;
    bounds_iterator<Rank> 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);

    template <class ArithmeticType> constexpr bounds  operator*(ArithmeticType v) const;
    template <class ArithmeticType> constexpr bounds  operator/(ArithmeticType v) const;
    template <class ArithmeticType> constexpr bounds& operator*=(ArithmeticType v);
    template <class ArithmeticType> constexpr bounds& operator/=(ArithmeticType 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 function shall not participate in overload resolution unless Rank is 1.

constexpr bounds(initializer_list<value_type> il);

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

Remarks: This function shall not participate in overload resolution unless il.size() is Rank.

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 initial element of the space defined by *this.

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 nth 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);

Returns: *this += -rhs.

template <class ArithmeticType> constexpr bounds operator*(ArithmeticType v) const;

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

template <class ArithmeticType> constexpr bounds operator/(ArithmeticType v) const;

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

template <class ArithmeticType> constexpr bounds& operator*=(ArithmeticType 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.

template <class ArithmeticType> constexpr bounds& operator/=(ArithmeticType 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 <class ArithmeticType, int Rank>
  constexpr bounds<Rank> operator*(ArithmeticType 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_ = implementation-defined 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 generalized views, as summarized in Table 95.

Add a row to table 95 as follows.

Table 95: Containers library summary
SubclauseHeader(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 Generalized views <array_view>

23.7 Generalized views [generalized.views]

Add a new section after the container.adaptors section.

23.7.1 In general [generalized.views.general]

Add a new section:

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

An array_view is a potentially multidimensional view on a sequence of objects of a uniform type contiguous in the least significant dimension and uniformly strided in other dimensions.

A strided_array_view is a potentially multidimensional view on a sequence of objects of a uniform type uniformly strided in all dimensions.

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 Generalized view types requirements [generalized.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 explicit array_view(Viewable&& vw);
    template <class ArrayType>
      constexpr explicit 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) noexcept;

    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
ExpressionReturn typeOperational semantics
v.size() Convertible to ptrdiff_t
v.data() Convertible to U* 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>.

constexpr array_view() noexcept;

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

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

Requires: vw shall satisfy the requirements of Viewable on T.

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

Remarks: This constructor shall not participate in overload resolution unless Rank is 1 and Viewable satisfies the syntactic requirements set in Table 104 for Viewable on T.

template <class ArrayType>
  constexpr explicit 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 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.

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 T.

[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) noexcept;

Requires: The expression ptr[bounds.size() - 1] shall be well formed and shall have well defined behavior.

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 constructor shall not participate in overload resolution unless is_convertible<add_pointer_t<U>, pointer>::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:

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: This constructor shall not participate in overload resolution unless is_convertible<add_pointer_t<U>, pointer>::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):

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 constructor shall not participate in overload resolution unless is_convertible<add_pointer_t<U>, pointer>::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>.