ISO/IEC JTC1 SC22 WG21 N4512 - 2015-05-07
Reply-to:
Łukasz Mendakiewicz <lukaszme@microsoft.com>
Herb Sutter <hsutter@microsoft.com>
Revision 7 (N4512) incorporates additional changes requested by LWG in
Lenexa meeting, marked as deletions and insertions.
Revision 6 (N4494) incorporates the changes requested by LWG in Cologne meeting.
The following suggestions were implemented fully:
index to offset.int Rank template parameter to size_t Rank throughout the document.offset, bounds and bounds_iterator binary operators (apart from @= forms) free functions.offset or bounds.bounds_iterator to represent a random access iterator, replacing with "asbounds_iterator& operator++() replaced the code snippet with equivalent prose.array_view and strided_array_view.array_view and strided_array_view semantics.constexpr array_view(Viewable&& vw) rephrased the third bullet point.The following suggestion was implemented partially:
array_view(ArrayType& arr)
constructor being completely removed, it has been constrained to 1-D
case as the Committee indicated that such case does not exhibit the
undefined behavior. We believe that the request to remove it completely
was a misstatment.The following suggestion was not implemented:
Revision 5 (N4346) incorporates the changes requested by LWG in Urbana-Champaign meeting.
Revision 4 (N4177) contains the following changes:
array_view and strided_array_view constructor parameters have been switched from {size, location} to {location, size} for consistency with the existing practice in STL (vide copy_n).Revision 3 (N4087) incorporates the feedback received in Rapperswil from LEWG and some other minor fixes:
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.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.operator- and operator-= in index and bounds to avoid negating rhs.(const_)iterator type aliases in bounds.array_view(bounds_type bounds, pointer ptr) specification.bounds_iterator::operator++ specification.Made array_view(Viewable&&) and array_view(ArrayType&) constructors not "explicit".array_view(bounds_type bounds, pointer ptr) constructor not to be "noexcept".index and bounds arithmetic operators from accepting any ArithmeticType to only value_type/ptrdiff_t.array_view constructors so that all conversions between related array_views can be noexcept.Thanks to Stephan T. Lavavej, Matthew Fioravante, Robert Kawulak 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.
The proposed wording changes are relative to the contents of N3936.
Edit within paragraph 2 as follows.
The C++ standard library provides 55 C++ library headers, as shown in Table 14.
Add the following items to table 14.
<array_view>
<coordinate>
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.7 Fixed-size sequences of bits <bitset>
<memory>20.8 Memory <cstdlib>
<cstring>20.9 Smart pointers <memory>20.10 Function objects <functional>20.11 Type traits <type_traits>20.12 Compile-time rational arithmetic <ratio>20.13 Time utilities <chrono>
<ctime>20.14 Scoped allocators <scoped_allocator>20.15 Type indexes <typeindex>
Add a new section after the intseq section.
Add a new section:
This subclause describes the multidimensional coordinates library. It provides a class template
offsetwhich is an N-tuple of coordinates representing locations and offsets in N-dimensional data structures, a class templateboundswhich is an N-tuple representing extents of such data structures, and a class templatebounds_iteratorwhich allows iteration over a space defined by such extents.
Add a new synopsis:
Header
<experimental/coordinate>synopsis#include <initializer_list> namespace std { namespace experimental { inline namespace fundamentals_v2 { // [coord.offset], class template offset template <size_t Rank> class offset; // [coord.offset.eq], offset equality template <size_t Rank> constexpr bool operator==(const offset<Rank>& lhs, const offset<Rank>& rhs) noexcept; template <size_t Rank> constexpr bool operator!=(const offset<Rank>& lhs, const offset<Rank>& rhs) noexcept; // [coord.offset.arith], offset arithmetic template <size_t Rank> constexpr offset<Rank> operator+(const offset<Rank>& lhs, const offset<Rank>& rhs); template <size_t Rank> constexpr offset<Rank> operator-(const offset<Rank>& lhs, const offset<Rank>& rhs); template <size_t Rank> constexpr offset<Rank> operator*(const offset<Rank>& lhs, ptrdiff_t v); template <size_t Rank> constexpr offset<Rank> operator*(ptrdiff_t v, const offset<Rank>& rhs); template <size_t Rank> constexpr offset<Rank> operator/(const offset<Rank>& lhs, ptrdiff_t v); // [coord.bounds], class template bounds template <size_t Rank> class bounds; // [coord.bounds.eq], bounds equality template <size_t Rank> constexpr bool operator==(const bounds<Rank>& lhs, const bounds<Rank>& rhs) noexcept; template <size_t Rank> constexpr bool operator!=(const bounds<Rank>& lhs, const bounds<Rank>& rhs) noexcept; // [coord.bounds.arith], bounds arithmetic template <size_t Rank> constexpr bounds<Rank> operator+(const bounds<Rank>& lhs, const offset<Rank>& rhs); template <size_t Rank> constexpr bounds<Rank> operator+(const offset<Rank>& lhs, const bounds<Rank>& rhs); template <size_t Rank> constexpr bounds<Rank> operator-(const bounds<Rank>& lhs, const offset<Rank>& rhs); template <size_t Rank> constexpr bounds<Rank> operator*(const bounds<Rank>& lhs, ptrdiff_t v); template <size_t Rank> constexpr bounds<Rank> operator*(ptrdiff_t v, const bounds<Rank>& rhs); template <size_t Rank> constexpr bounds<Rank> operator/(const bounds<Rank>& lhs, ptrdiff_t v); // [coord.bounds.iterator], class template bounds_iterator template <size_t Rank> class bounds_iterator; template <size_t Rank> bool operator==(const bounds_iterator<Rank>& lhs, const bounds_iterator<Rank>& rhs); template <size_t Rank> bool operator!=(const bounds_iterator<Rank>& lhs, const bounds_iterator<Rank>& rhs); template <size_t Rank> bool operator<(const bounds_iterator<Rank>& lhs, const bounds_iterator<Rank>& rhs); template <size_t Rank> bool operator<=(const bounds_iterator<Rank>& lhs, const bounds_iterator<Rank>& rhs); template <size_t Rank> bool operator>(const bounds_iterator<Rank>& lhs, const bounds_iterator<Rank>& rhs); template <size_t Rank> bool operator>=(const bounds_iterator<Rank>& lhs, const bounds_iterator<Rank>& rhs); template <size_t Rank> bounds_iterator<Rank> operator+(typename bounds_iterator<Rank>::difference_type n, const bounds_iterator<Rank>& rhs); } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
offset [coord.offset]Add a new section:
namespace std { namespace experimental { inline namespace fundamentals_v2 { template <size_t Rank> class offset { public: // constants and types static constexpr size_t rank = Rank; using reference = ptrdiff_t&; using const_reference = const ptrdiff_t&; using size_type = size_t; using value_type = ptrdiff_t; // [coord.offset.cnstr], offset construction constexpr offset() noexcept; constexpr offset(value_type v) noexcept; // only if Rank == 1 constexpr offset(initializer_list<value_type> il); // [coord.offset.cmptelem], offset element access constexpr reference operator[](size_type n); constexpr const_reference operator[](size_type n) const; // [coord.offset.arith], offset arithmetic constexpr offset& operator+=(const offset& rhs); constexpr offset& operator-=(const offset& rhs); constexpr offset& operator++(); // only if Rank == 1 constexpr offset operator++(int); // only if Rank == 1 constexpr offset& operator--(); // only if Rank == 1 constexpr offset operator--(int); // only if Rank == 1 constexpr offset operator+() const noexcept; constexpr offset operator-() const; constexpr offset& operator*=(value_type v); constexpr offset& operator/=(value_type v); }; } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
Add a new section:
If
Rankis less than 1 the program is ill-formed.
Add a new section:
constexpr offset() noexcept;Effects: Zero-initializes each element.
constexpr offset(value_type v) noexcept;Effects: Initializes the 0th element of
*thiswithv.Remarks: This constructor shall not participate in overload resolution unless
Rankis 1.
constexpr offset(initializer_list<value_type> il);Requires:
il.size() == Rank.Effects: For all i in the range
[0, Rank), initializes the ith element of*thiswith*(il.begin() + i).
Add a new section:
template <size_t Rank> constexpr bool operator==(const offset<Rank>& lhs, const offset<Rank>& rhs) noexcept;Returns:
trueiflhs[i] == rhs[i]for alliin the range[0, Rank), otherwisefalse.
template <size_t Rank> constexpr bool operator!=(const offset<Rank>& lhs, const offset<Rank>& rhs) noexcept;Returns:
!(lhs == rhs).
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 element of*this.
Add a new section:
constexpr offset& operator+=(const offset& rhs);Effects: For all i in the range
[0, Rank), adds the ith element ofrhsto the ith element of*thisand stores the sum in the ith element of*this.Returns:
*this.
constexpr offset& operator-=(const offset& rhs);Effects: For all i in the range
[0, Rank), subtracts the ith element ofrhsfrom the ith element of*thisand stores the difference in the ith element of*this.Returns:
*this.
constexpr offset& operator++();Effects:
++(*this)[0].Returns:
*this.Remarks: This function shall not participate in overload resolution unless
Rank == 1.
constexpr offset operator++(int);Returns:
offset.<Rank>{(*this)[0]++}Remarks: This function shall not participate in overload resolution unless
Rank == 1.
constexpr offset& operator--();Effects:
--(*this)[0].Returns:
*this.Remarks: This function shall not participate in overload resolution unless
Rank == 1.
constexpr offset operator--(int);Returns:
offset.<Rank>{(*this)[0]--}Remarks: This function shall not participate in overload resolution unless
Rank == 1.
constexpr offset operator+() const noexcept;Returns:
*this.
constexpr offset operator-() const;Returns: A copy of
*thiswith each element negated.
constexpr offset& operator*=(value_type v);Effects: For all i in the range
[0, Rank), multiplies the ith element of*thisbyvand stores the product in the ith element of*this.Returns:
*this.
constexpr offset& operator/=(value_type v);Effects: For all i in the range
[0, Rank), divides the ith element of*thisbyvand stores the quotient in the ith element of*this.Returns:
*this.
template <size_t Rank> constexpr offset<Rank> operator+(const offset<Rank>& lhs, const offset<Rank>& rhs);Returns:
offset<Rank>{lhs} += rhs.
template <size_t Rank> constexpr offset<Rank> operator-(const offset<Rank>& lhs, const offset<Rank>& rhs);Returns:
offset<Rank>{lhs} -= rhs.
template <size_t Rank> constexpr offset<Rank> operator*(const offset<Rank>& lhs, ptrdiff_t v);Returns:
offset<Rank>{lhs} *= v.
template <size_t Rank> constexpr offset<Rank> operator*(ptrdiff_t v, const offset<Rank>& rhs);Returns:
offset<Rank>{rhs} *= v.
template <size_t Rank> constexpr offset<Rank> operator/(const offset<Rank>& lhs, ptrdiff_t v);Returns:
offset<Rank>{lhs} /= v.
bounds [coord.bounds]Add a new section:
namespace std { namespace experimental { inline namespace fundamentals_v2 { template <size_t Rank> class bounds { public: // constants and types static constexpr size_t 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); // only if Rank == 1 constexpr bounds(initializer_list<value_type> il); // [coord.bounds.obs], bounds observers constexpr size_type size() const noexcept; constexpr bool contains(const offset<Rank>& idx) const noexcept; // [coord.bounds.iter], bounds iterators const_iterator begin() const noexcept; const_iterator end() const noexcept; // [coord.bounds.cmptelem], bounds element access constexpr reference operator[](size_type n); constexpr const_reference operator[](size_type n) const; // [coord.bounds.arith], bounds arithmetic constexpr bounds& operator+=(const offset<Rank>& rhs); constexpr bounds& operator-=(const offset<Rank>& rhs); constexpr bounds& operator*=(value_type v); constexpr bounds& operator/=(value_type v); }; } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
Add a new section:
If
Rankis less than 1 the program is ill-formed.Construction of and every mutating operation on an object
bof typeboundsshall leave the object in a state that satisfies the following constraints:
b[i] >= 0for alliin the range[0, Rank).b[0]×b[1]× ... ×b[Rank - 1] <=numeric_limits<ptrdiff_t>::max().Otherwise, the behavior is undefined.
Add a new section:
constexpr bounds() noexcept;Effects: Zero-initializes each element.
constexpr bounds(value_type v);Effects: Initializes the 0th element of
*thiswithv.Remarks: This constructor shall not participate in overload resolution unless
Rankis 1.
constexpr bounds(initializer_list<value_type> il);Requires:
il.size() == Rank.Effects: For all i in the range
[0, Rank), initializes the ith element of*thiswith*(il.begin() + i).
Add a new section:
template <size_t Rank> constexpr bool operator==(const bounds<Rank>& lhs, const bounds<Rank>& rhs) noexcept;Returns:
trueiflhs[i] == rhs[i]for alliin the range[0, Rank), otherwisefalse.
template <size_t Rank> constexpr bool operator!=(const bounds<Rank>& lhs, const bounds<Rank>& rhs) noexcept;Returns:
!(lhs == rhs).
Add a new section:
constexpr size_type size() const noexcept;Returns: The product of all elements of
*this.
constexpr bool contains(const offset<Rank>& idx) const noexcept;Returns:
trueif0 <= idx[i]andidx[i] < (*this)[i]for alliin the range[0, Rank), otherwisefalse.
Add a new section:
bounds_iterator<Rank>const_iterator begin() const noexcept;Returns: A
bounds_iteratorreferring to the first element of the space defined by*thissuch that*begin() == offset<Rank>{}ifsize() != 0,otherwisebegin() == end()otherwise.
bounds_iterator<Rank>const_iterator end() const noexcept;Returns: A
bounds_iteratorwhich is the past-the-end iterator for the space defined by*this.
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 element of*this.
Add a new section:
constexpr bounds& operator+=(const offset<Rank>& rhs);Effects: For all i in the range
[0, Rank), adds the ith element ofrhsto the ith element of*thisand stores the sum in the ith element of*this.Returns:
*this.
constexpr bounds& operator-=(const offset<Rank>& rhs);Effects: For all i in the range
[0, Rank), subtracts the ith element ofrhsfrom the ith element of*thisand stores the difference in the ith element of*this.Returns:
*this.
constexpr bounds& operator*=(value_type v);Effects: For all i in the range
[0, Rank), multiplies the ith element of*thisbyvand stores the product in the ith element of*this.Returns:
*this.
constexpr bounds& operator/=(value_type v);Effects: For all i in the range
[0, Rank), divides the ith element of*thisbyvand stores the quotient in the ith element of*this.Returns:
*this.
template <size_t Rank> constexpr bounds<Rank> operator+(const bounds<Rank>& lhs, const offset<Rank>& rhs);Returns:
bounds<Rank>{lhs} += rhs.
template <size_t Rank> constexpr bounds<Rank> operator+(const offset<Rank>& lhs, const bounds<Rank>& rhs);Returns:
bounds<Rank>{rhs} += lhs.
template <size_t Rank> constexpr bounds<Rank> operator-(const bounds<Rank>& lhs, const offset<Rank>& rhs);Returns:
bounds<Rank>{lhs} -= rhs.
template <size_t Rank> constexpr bounds<Rank> operator*(const bounds<Rank>& lhs, ptrdiff_t v);Returns:
bounds<Rank>{lhs} *= v.
template <size_t Rank> constexpr bounds<Rank> operator*(ptrdiff_t v, const bounds<Rank>& rhs);Returns:
bounds<Rank>{rhs} *= v.
template <size_t Rank> constexpr bounds<Rank> operator/(const bounds<Rank>& lhs, ptrdiff_t v);Returns:
bounds<Rank>{lhs} /= v.
bounds_iterator [coord.bounds.iterator]Add a new section:
SemantincsSemantics of thebounds_iteratorshall follow the semantics of a random access iterator ([random.access.iterators]) unless otherwise specified below.namespace std { namespace experimental { inline namespace fundamentals_v2 { template <size_t Rank> class bounds_iterator { public: using iterator_category = unspecified; using value_type = offset<Rank>; using difference_type = ptrdiff_t; using pointer = unspecified; // See [coord.bounds.iterator.require] using reference = const offset<Rank>; 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 offset<Rank> idx_; // exposition only }; } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
Add a new section:
If
Rankis less than 1 the program is ill-formed.
pointershall be an unspecified type such that for abounds_iterator itthe expressionit->Eis equivalent to(*it).Eand that for an objectpof typepointerthe expressionp->Eyields the same result irrespective of whether the state of thebounds_iteratorobject has changed or its lifetime has ended.[Note: All functions in the library that take a pair of iterators to denote a range shall treat
bounds_iteratoriterators as-if they were random access iterators, even though the pointer type is not a true pointer and the reference type is not a true reference. —end note]
Add a new section:
bool operator==(const bounds_iterator& rhs) const;Requires:
*thisandrhsare iterators over the sameboundsobject.Returns:
idx_ == rhs.idx_.
bounds_iterator& operator++();Requires:
*thisis not the past-the-end iterator.Effects:
Increments
idx_[Rank - 1]. Ifidx_[Rank - 1]is equal tobnd_[Rank - 1], setsidx_[Rank - 1]to zero and repeats the process withRank - 2, and so on, untilidx_[0]is equal tobnd_[0], at which pointssetsidx_to an unspecified past-the-end value.[Example: Given
bounds_iterator<2>withbnd_ == {3, 2}andidx_ == {0, 0}, subsequent calls tooperator++will result inidx_being equal to:{0, 1},{1, 0},{1, 1},{2, 0},{2, 1}, unspecified past-the-end value. —end example]Returns:
*this.
bounds_iterator& operator--();Requires: There exists a
bounds_iteratorsuch that<Rank>it*this == ++it.Effects:
*this = it.Returns:
*this.
reference operator*() const;Requires:
*thisis not the past-the-end iterator.Returns:
idx_.
Edit within paragraph 2 as follows.
The following subclauses describe container requirements, 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>
Add a new section after the container.adaptors section.
Add a new section:
The header
<experimental/array_view>defines the viewsarray_viewandstrided_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_viewis a potentially multidimensional view on a sequence of uniformly strided objects of a uniform type, contiguous in the least significant dimension.A
strided_array_viewis a potentially multidimensional view on a sequence of uniformly strided objects of a uniform type.
Add a new synopsis:
Header
<experimental/array_view>synopsisnamespace std { namespace experimental { inline namespace fundamentals_v2 { // [arrayview], class template array_view template <class T, size_t Rank = 1> class array_view; // [stridedarrayview], class template strided_array_view template <class T, size_t Rank = 1> class strided_array_view; } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
array_view [arrayview]Add a new section:
namespace std { namespace experimental { inline namespace fundamentals_v2 { template <class T, size_t Rank = 1> class array_view { public: // constants and types static constexpr size_t rank = Rank; using offset_type = offset<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); // only if Rank == 1 template <class U, size_t AnyRank> constexpr array_view(const array_view<U, AnyRank>& rhs) noexcept; // only if Rank == 1 template <size_t Extent> constexpr array_view(value_type (&arr)[Extent]) noexcept; // only if Rank == 1 template <class U> constexpr array_view(const array_view<U, Rank>& rhs) noexcept; template <class Viewable> constexpr array_view(Viewable&& vw, bounds_type bounds); constexpr array_view(pointer ptr, bounds_type bounds); // [arrayview.obs], array_view observers constexpr bounds_type bounds() const noexcept; constexpr size_type size() const noexcept; constexpr offset_type stride() const noexcept; constexpr pointer data() const noexcept; // [arrayview.elem], array_view element access constexpr reference operator[](const offset_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 offset_type& origin, const bounds_type& section_bnd) const; constexpr strided_array_view<T, Rank> section(const offset_type& origin) const; private: pointer data_; // exposition only bounds_type bounds_; // exposition only }; } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
array_view requirements [arrayview.require]Add a new section:
Tshall be an non-array 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
Rankis 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].
array_view constructors, copy, and assignment [arrayview.cons]Add a new section:
For the purpose of this subclause,
ViewableonUis a type satisfying the requirements set out in Table 104. In these definitions, letvdenote an expressionwhich type, type of which isViewableonU.
Table 104: ViewableonUrequirementsExpression Return type Operational semantics v.size()Convertible to ptrdiff_tv.data()TypeT*such thatT*is implicitly convertible toU*, andis_same_v<remove_cv_t<T>, remove_cv_t<U>>istrue.static_cast<U*>(v.data())points to a contiguous sequence of at leastv.size()objects of (possibly cv-qualified) typeremove_cv_t<U>.[Example: The type
vector<int>([vector]) meets the requirements of all of the following:Viewableonint,Viewableonconst int,Viewableonvolatile int, andViewableonconst volatile int. —end example]
constexpr array_view() noexcept;Postconditions:
data_ == nullptrandbounds_.size() == 0.
template <class Viewable> constexpr array_view(Viewable&& vw);Requires:
vwshall satisfy the requirements ofViewableonvalue_type.Postconditions:
data_ == vw.data()andbounds_.size() == vw.size().Remarks: This constructor shall not participate in overload resolution unless:
[Note: This provision ensures that either the following or the implicit copy constructor — both of which are
Rankis 1,Viewablesatisfies the syntactic requirements set in Table 104 forViewableonvalue_type, anddecay_t<Viewable>is not a specialization ofarray_view.noexcept— will be selected by overload resolution instead. —end note]
template <class U, size_t AnyRank> constexpr array_view(const array_view<U, AnyRank>& rhs) noexcept;Postconditions:
data_ == rhs.data()andbounds_.size() == rhs.size().Remarks: This constructor shall not participate in overload resolution unless:
Rankis 1,is_convertible_v<add_pointer_t<U>, pointer>istrue, andis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>istrue.
template <size_t Extent> constexpr array_view(value_type (&arr)[Extent]) noexcept;Postconditions:
data_ == arrandbounds_.size() == Extent.Remarks: This constructor shall not participate in overload resolution unless
Rankis 1.
template <class U> constexpr array_view(const array_view<U, Rank>& rhs) noexcept;Postconditions:
data_ == rhs.data()andbounds_ == rhs.bounds().Remarks: This constructor shall not participate in overload resolution unless
is_convertible_v<add_pointer_t<U>, pointer>istrueandis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>istrue.
template <class Viewable> constexpr array_view(Viewable&& vw, bounds_type bounds);Requires:
bounds.size() <= vw.size().Postconditions:
data_ == vw.data()andbounds_ == bounds.Remarks: This constructor shall not participate in overload resolution unless
Viewablesatisfies the syntactic requirements set in Table 104 forViewableonvalue_type.[Note: This constructor may be used to create an
array_viewwith a different rank and/or bounds than the originalarray_view, i.e. reshape the view. —end note]
constexpr array_view(pointer ptr, bounds_type bounds);Requires:
[ptr, ptr + bounds.size())is a valid range.Postconditions:
data_ == ptrandbounds_ == bounds.
array_view observers [arrayview.obs]Add a new section:
constexpr bounds_type bounds() const noexcept;Returns:
bounds_.
constexpr size_type size() const noexcept;Returns:
bounds().size().
constexpr offset_type stride() const noexcept;Returns: A value
ssuch that:
s[i] == s[i + 1] * bounds()[i + 1], when0 <= iandi < Rank - 1.s[i] == 1, wheni == Rank - 1.
constexpr pointer data() const noexcept;Returns:
data_.
array_view element access [arrayview.elem]Add a new section:
constexpr reference operator[](const offset_type& idx) const;Requires:
bounds().contains(idx) == true.Returns:
VIEW_ACCESS(data(), idx, stride(), Rank).
array_view slicing and sectioning [arrayview.subview]Add a new section:
constexpr array_view<T, Rank - 1> operator[](ptrdiff_t slice) const;Requires:
0 <= sliceandslice < bounds()[0].Returns: A view
vwsuch thatvw.data_is(*this)[{slice, 0, 0, ..., 0}], andvw.bounds_is{bounds()[1], bounds()[2], ..., bounds()[Rank - 1]}.Remarks: This function shall not participate in overload resolution unless
Rank > 1.
constexpr strided_array_view<T, Rank> section(const offset_type& origin, const bounds_type& section_bnd) const;Requires:
bounds().contains(origin + idx) == truefor anyoffset_type idxsuch thatsection_bnd.contains(idx) == true.Returns: A strided view
vwsuch thatvw.data_is(*this)[origin],vw.stride_isstride(), andvw.bounds_issection_bnd.
constexpr strided_array_view<T, Rank> section(const offset_type& origin) const;Requires:
bounds().contains(origin + idx) == truefor anyoffset_type idxsuch that(bounds() - origin).contains(idx) == true.Returns: A strided view
vwsuch thatvw.data_is(*this)[origin],vw.stride_isstride(), andvw.bounds_isbounds() - origin.
strided_array_view [stridedarrayview]Add a new section:
namespace std { namespace experimental { inline namespace fundamentals_v2 { template <class T, size_t Rank = 1> class strided_array_view { public: // constants and types static constexpr size_t rank = Rank; using offset_type = offset<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(pointer ptr, bounds_type bounds, offset_type stride); // [stridedarrayview.obs], strided_array_view observers constexpr bounds_type bounds() const noexcept; constexpr size_type size() const noexcept; constexpr offset_type stride() const noexcept; // [stridedarrayview.elem], strided_array_view element access constexpr reference operator[](const offset_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 offset_type& origin, const bounds_type& section_bnd) const; constexpr strided_array_view<T, Rank> section(const offset_type& origin) const; private: pointer data_; // exposition only bounds_type bounds_; // exposition only offset_type stride_; // exposition only }; } // inline namespace fundamentals_v2 } // namespace experimental } // namespace std
strided_array_view requirements [stridedarrayview.require]Add a new section:
Tshall be an non-array 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
Rankis 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].
strided_array_view constructors, copy, and assignment [stridedarrayview.cons]Add a new section:
constexpr strided_array_view() noexcept;Postconditions:
data_ == nullptr,bounds_.size() == 0, andstride_ == offset_type{}.
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: For both constructors,
bounds_ == rhs.bounds()andstride_ == rhs.stride(). For the first constructor,data_ == rhs.data(). For the second constructor,data_ == rhs.data_.Remarks: These constructors shall not participate in overload resolution unless
is_convertible_v<add_pointer_t<U>, pointer>istrueandis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>istrue.
constexpr strided_array_view(pointer ptr, bounds_type bounds, offset_type stride);Requires: For any
offset_type idxsuch thatbounds.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 typeptrdiff_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:
data_ == ptr,bounds_ == bounds, andstride_ == stride.
strided_array_view observers [stridedarrayview.obs]Add a new section:
constexpr bounds_type bounds() const noexcept;Returns:
bounds_.
constexpr size_type size() const noexcept;Returns:
bounds().size().
constexpr offset_type stride() const noexcept;Returns:
stride_.
strided_array_view element access [stridedarrayview.elem]Add a new section:
constexpr reference operator[](const offset_type& idx) const;Requires:
bounds().contains(idx) == true.Returns:
VIEW_ACCESS(data_, idx, stride(), Rank).
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:
0 <= sliceandslice < bounds()[0].Returns: A strided view
vwsuch thatvw.data_is(*this)[{slice, 0, 0, ..., 0}],vw.bounds_is{bounds()[1], bounds()[2], ..., bounds()[Rank - 1]}, andvw.stride_is{stride()[1], stride()[2], ..., stride()[Rank - 1]}.Remarks: This function shall not participate in overload resolution unless
Rank > 1.
constexpr strided_array_view<T, Rank> section(const offset_type& origin, const bounds_type& section_bnd) const;Requires:
bounds().contains(origin + idx) == truefor anyoffset_type idxsuch thatsection_bnd.contains(idx) == true.Returns: A strided view
vwsuch thatvw.data_is(*this)[origin],vw.stride_isstride(), andvw.bounds_issection_bnd.
constexpr strided_array_view<T, Rank> section(const offset_type& origin) const;Requires:
bounds().contains(origin + idx) == truefor anyoffset_type idxsuch that(bounds() - origin).contains(idx) == true.Returns: A strided view
vwsuch thatvw.data_is(*this)[origin],vw.stride_isstride(), andvw.bounds_isbounds() - origin.
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>.