ISO/IEC JTC1 SC22 WG21 N4494 - 2015-05-01
Reply-to:
Łukasz Mendakiewicz <lukaszme@microsoft.com>
Herb Sutter <hsutter@microsoft.com>
Revision 6 (N4494) incorporates the changes requested by LWG in Cologne meeting, marked as deletions and insertions.
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 "as-if" phrasing.bounds_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_view
s 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
5355 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. 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>
Add a new section after the intseq
section.
Add a new section:
This subclause describes the multidimensional coordinates library. It provides a class template
which
indexoffsetrepresents a mathematical vector in an N-dimensional discrete spaceis an N-tuple of coordinates representing locations and offsets in N-dimensional data structures, a class templatebounds
whichrepresents axis-aligned rectangular bounds in such a spaceis an N-tuple representing extents of such data structures, and a class templatebounds_iterator
which allows iteration oversuch a spacespace defined by such extents.
Add a new synopsis:
Header
<coordinate>
synopsis#include <initializer_list> namespace std { // [coord.
indexoffset], class templateindexoffset template <intsize_t Rank> classindexoffset; // [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.indexoffset.arith],indexoffset 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 <intsize_t Rank> constexprindexoffset<Rank> operator*(ptrdiff_t v, constindexoffset<Rank>& rhs); template <size_t Rank> constexpr offset<Rank> operator/(const offset<Rank>& lhs, ptrdiff_t v); // [coord.bounds], class template bounds template <intsize_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 <intsize_t Rank> constexpr bounds<Rank> operator+(constindexoffset<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 <intsize_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 <intsize_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 <intsize_t Rank> bounds_iterator<Rank> operator+(typename bounds_iterator<Rank>::difference_type n, const bounds_iterator<Rank>& rhs); }
indexoffset
[coord.Add a new section:
namespace std { template <
intsize_t Rank> classindexoffset { public: // constants and types static constexprintsize_t rank = Rank; using reference = ptrdiff_t&; using const_reference = const ptrdiff_t&; using size_type = size_t; using value_type = ptrdiff_t; // [coord.indexoffset.cnstr],indexoffset construction constexprindexoffset() noexcept; constexprindexoffset(value_type v) noexcept; // only if Rank == 1 constexprindexoffset(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.indexoffset.cmpt],index componentoffset element access constexpr reference operator[](size_type n); constexpr const_reference operator[](size_type n) const; // [coord.indexoffset.arith],indexoffset arithmeticconstexpr index operator+(const index& rhs) const; constexpr index operator-(const index& rhs) const;constexprindexoffset& operator+=(constindexoffset& rhs); constexprindexoffset& operator-=(constindexoffset& rhs); constexprindexoffset& operator++(); // only if Rank == 1 constexprindexoffset operator++(int); // only if Rank == 1 constexprindexoffset& operator--(); // only if Rank == 1 constexprindexoffset operator--(int); // only if Rank == 1 constexprindexoffset operator+() const noexcept; constexprindexoffset operator-() const;constexpr index operator*(value_type v) const; constexpr index operator/(value_type v) const;constexprindexoffset& operator*=(value_type v); constexprindexoffset& operator/=(value_type v); }; }
Add a new section:
If
Rank
is less than 1 the program is ill-formed.
Add a new section:
constexpr
indexoffset() noexcept;Effects: Zero-initializes each
componentelement.
constexpr
indexoffset(value_type v) noexcept;Effects: Initializes the 0th
componentelement of*this
withv
.Remarks: This constructor shall not participate in overload resolution unless
Rank
is 1.
constexpr
indexoffset(initializer_list<value_type> il);Requires:
il.size() == Rank
.Effects: For all i in the range
[0, Rank)
, initializes the ithcomponentelement of*this
with*(il.begin() + i)
.
Add a new section:
template <size_t Rank> constexpr bool operator==(const offset<Rank>& lhs, const
indexoffset<Rank>& rhs)constnoexcept;Returns:
true
iffor all
(*this)lhs[i] == rhs[i]i
in the range[0, Rank)
, otherwisefalse
.
template <size_t Rank> constexpr bool operator!=(const offset<Rank>& lhs, const
indexoffset<Rank>& rhs)constnoexcept;Returns:
!(
.*thislhs == 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
n
thcomponentelement of*this
.
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
indexoffset& operator+=(constindexoffset& rhs);Effects: For all i in the range
[0, Rank)
, adds the ithcomponentelement ofrhs
to the ithcomponentelement of*this
and stores the sum in the ithcomponentelement of*this
.Returns:
*this
.
constexpr
indexoffset& operator-=(constindexoffset& rhs);Effects: For all i in the range
[0, Rank)
, subtracts the ithcomponentelement ofrhs
from the ithcomponentelement of*this
and stores the difference in the ithcomponentelement of*this
.Returns:
*this
.
constexpr
indexoffset& operator++();Effects:
++(*this)[0]
.Returns:
*this
.Remarks: This function shall not participate in overload resolution unless
Rank == 1
.
constexpr
indexoffset operator++(int);Returns:
.
indexoffset<Rank>{(*this)[0]++}Remarks: This function shall not participate in overload resolution unless
Rank == 1
.
constexpr
indexoffset& operator--();Effects:
--(*this)[0]
.Returns:
*this
.Remarks: This function shall not participate in overload resolution unless
Rank == 1
.
constexpr
indexoffset operator--(int);Returns:
.
indexoffset<Rank>{(*this)[0]--}Remarks: This function shall not participate in overload resolution unless
Rank == 1
.
constexpr
indexoffset operator+() const noexcept;Returns:
*this
.
constexpr
indexoffset operator-() const;Returns: A copy of
*this
with eachcomponentelement 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
indexoffset& operator*=(value_type v);Effects: For all i in the range
[0, Rank)
, multiplies the ithcomponentelement of*this
byv
and stores the product in the ithcomponentelement of*this
.Returns:
*this
.
constexpr
indexoffset& operator/=(value_type v);Effects: For all i in the range
[0, Rank)
, divides the ithcomponentelement of*this
byv
and stores the quotient in the ithcomponentelement 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 <
intsize_t Rank> constexprindexoffset<Rank> operator*(ptrdiff_t v, constindexoffset<Rank>& rhs);Returns:
.
indexoffset<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 { template <
intsize_t Rank> class bounds { public: // constants and types static constexprintsize_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.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(constindexoffset<Rank>& idx) const noexcept; // [coord.bounds.iter], bounds iterators const_iterator begin() const noexcept; const_iterator end() const noexcept; // [coord.bounds.cmpt], boundscomponentelement access constexpr reference operator[](size_type n); constexpr const_reference operator[](size_type n) const; // [coord.bounds.arith], bounds arithmeticconstexpr bounds operator+(const index<Rank>& rhs) const; constexpr bounds operator-(const index<Rank>& rhs) const;constexpr bounds& operator+=(constindexoffset<Rank>& rhs); constexpr bounds& operator-=(constindexoffset<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); }; }
Add a new section:
If
Rank
is less than 1 the program is ill-formed.Construction of and every mutating operation on an object
b
of typebounds
shall leave the object in a state that satisfies the following constraints:
b[i] >= 0
for alli
in the range[0, Rank)
.The product ofb[i]
for alli
in the range[0, Rank)
is less than or equal tob[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
componentelement.
constexpr bounds(value_type v);
Effects: Initializes the 0th
componentelement of*this
withv
.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 ithcomponentelement of*this
with*(il.begin() + i)
.
Add a new section:
template <size_t Rank> constexpr bool operator==(const bounds<Rank>& lhs, const bounds<Rank>& rhs)
constnoexcept;Returns:
true
iffor all
(*this)lhs[i] == rhs[i]i
in the range[0, Rank)
, otherwisefalse
.
template <size_t Rank> constexpr bool operator!=(const bounds<Rank>& lhs, const bounds<Rank>& rhs)
constnoexcept;Returns:
!(
.*thislhs == rhs)
Add a new section:
constexpr size_type size() const noexcept;
Returns: The product of all
componentselements of*this
.
constexpr bool contains(const
indexoffset<Rank>& idx) const noexcept;Returns:
true
if0 <= idx[i]
andidx[i] < (*this)[i]
for alli
in the range[0, Rank)
, otherwisefalse
.
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() ==
ifindexoffset<Rank>{}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
.
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
thcomponentelement of*this
.
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
indexoffset<Rank>& rhs);Effects: For all i in the range
[0, Rank)
, adds the ithcomponentelement ofrhs
to the ithcomponentelement of*this
and stores the sum in the ithcomponentelement of*this
.Returns:
*this
.
constexpr bounds& operator-=(const
indexoffset<Rank>& rhs);Effects: For all i in the range
[0, Rank)
, subtracts the ithcomponentelement ofrhs
from the ithcomponentelement of*this
and stores the difference in the ithcomponentelement 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 ithcomponentelement of*this
byv
and stores the product in the ithcomponentelement of*this
.Returns:
*this
.
constexpr bounds& operator/=(value_type v);
Effects: For all i in the range
[0, Rank)
, divides the ithcomponentelement of*this
byv
and stores the quotient in the ithcomponentelement 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 <
intsize_t Rank> constexpr bounds<Rank> operator+(constindexoffset<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 <
intsize_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:
Semantincs ofbounds_iterator
satisfies the requirements of a random access iteratorbounds_iterator
shall follow the semantics of a random access iterator ([random.access.iterators]) unless otherwise specified below.namespace std { template <
intsize_t Rank> class bounds_iterator { public: using iterator_category =random_access_iterator_tag;unspecified; using value_type =indexoffset<Rank>; using difference_type = ptrdiff_t; using pointer = unspecified; // See [coord.bounds.iterator.require] using reference = constindexoffset<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 onlyindexoffset<Rank> idx_; // exposition only }; }
Add a new section:
If
Rank
is less than 1 the program is ill-formed.
pointer
shall be an unspecified type such that for abounds_iterator it
the expressionit->E
is equivalent to(*it).E
and that for an objectp
of typepointer
the expressionp->E
yields the same result irrespective of whether the state of thebounds_iterator
object 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_iterator
iterators 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:
*this
andrhs
are iterators over the samebounds
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;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 points setsidx_
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
.
[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_
.
Edit within paragraph 2 as follows.
The following subclauses describe container requirements,
andcomponents 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
<array_view>
defines the viewsarray_view
andstrided_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
.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>
synopsisnamespace std { // [arrayview], class template array_view template <class T,
intsize_t Rank = 1> class array_view; // [stridedarrayview], class template strided_array_view template <class T,intsize_t Rank = 1> class strided_array_view; }
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]
IfRank
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.
DefineVIEW_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
[arrayview]Add a new section:
namespace std { template <class T,
intsize_t Rank = 1> class array_view { public: // constants and types static constexprintsize_t rank = Rank; usingindexoffset_type =indexoffset<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,intsize_t AnyRank> constexpr array_view(const array_view<U, AnyRank>& rhs) noexcept; // only if Rank == 1 template <class ArrayTypesize_t Extent> constexpr array_view(ArrayType&value_type (&arr)[Extent]) noexcept; // only if Rank ==rank_v<ArrayType>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);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; constexprindexoffset_type stride() const noexcept; constexpr pointer data() const noexcept; // [arrayview.elem], array_view element access constexpr reference operator[](constindexoffset_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(constindexoffset_type& origin, const bounds_type& section_bnd) const; constexpr strided_array_view<T, Rank> section(constindexoffset_type& origin) const; private: pointer data_; // exposition only bounds_type bounds_; // exposition only }; }
array_view
requirements [arrayview.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]
.
array_view
constructors, copy, and assignment [arrayview.cons]Add a new section:
For the purpose of this subclause,
Viewable
onU
is a type satisfying the requirements set out in Table 104. In these definitions, letv
denote an expressionofwhich type isViewable
onU
type.
Table 104: Viewable
onU
requirementsExpression Return type Operational semantics v.size()
Convertible to ptrdiff_t
v.data()
Type T*
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:Viewable
onint
,Viewable
onconst int
,Viewable
onvolatile int
, andViewable
onconst volatile int
. —end example]
constexpr array_view() noexcept;
Postconditions:
data_ == nullptr
andbounds
()_.size() == 0and.data() == nullptr
template <class Viewable> constexpr array_view(Viewable&& vw);
Requires:
vw
shall satisfy the requirements ofViewable
onvalue_type
.Postconditions:
data_ == vw.data()
andbounds
()_.size() == vw.size()and.data() == vw.data()
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
Rank
is 1,Viewable
satisfies the syntactic requirements set in Table 104 forViewable
onvalue_type
, anddecay_t<Viewable>
is nota specialization ofarray_view<U, N>
for anyU
andN
array_view
.noexcept
— will be selected by overload resolution instead. —end note]
template <class U,
intsize_t AnyRank> constexpr array_view(const array_view<U, AnyRank>& rhs) noexcept;Postconditions:
data_ == rhs.data()
andbounds
()_.size() == rhs.size()and.data() == rhs.data()
Remarks: This constructor shall not participate in overload resolution unless:
Rank
is 1,is_convertible_v<add_pointer_t<U>, pointer>
istrue
, andis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>
istrue
.
template <
class ArrayTypesize_t Extent> constexpr array_view(ArrayType&value_type (&arr)[Extent]) noexcept;Postconditions:
data_ == arr
andbounds
()[i]_.size() == Extentextent_v<ArrayType, i>for all.i
in the range[0, Rank)
, anddata()
is equal to the address of the initial element inarr
Remarks: This constructor shall not participate in overload resolution unless
:Rank
is 1.
is_convertible_v<add_pointer_t<remove_all_extents_t<ArrayType>>, pointer>
istrue
,is_same_v<remove_cv_t<remove_all_extents_t<ArrayType>>, remove_cv_t<value_type>>
istrue
, andrank_v<ArrayType> == 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'));3>
—end example]
template <class U> constexpr array_view(const array_view<U, Rank>& rhs) noexcept;
Postconditions:
data_ == rhs.data()
andbounds
()_ == rhs.bounds()and.data() == rhs.data()
Remarks: This constructor shall not participate in overload resolution unless
is_convertible_v<add_pointer_t<U>, pointer>
istrue
andis_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
and()_ == vw.data()bounds
.()_ == boundsRemarks: This constructor shall not participate in overload resolution unless
Viewable
satisfies the syntactic requirements set in Table 104 forViewable
onvalue_type
.[Note: This constructor may be used to create an
array_view
with 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
and()_ == ptrbounds
.()_ == bounds
template <class U> constexpr array_view& operator=(const array_view<U, Rank>& rhs) noexcept;
Postconditions:bounds() == rhs.bounds()
anddata() == rhs.data()
.
Returns:*this
.
Remarks: This function shall not participate in overload resolution unlessis_convertible_v<add_pointer_t<U>, pointer>
istrue
andis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>
istrue
.
array_view
observers [arrayview.obs]Add a new section:
constexpr bounds_type bounds() const noexcept;
Returns:
The bounds of the viewbounds_
.
constexpr size_type size() const noexcept;
Returns:
bounds().size()
.
constexpr
indexoffset_type stride() const noexcept;Returns: A value
s
such that:
s[i] == s[i + 1] * bounds()[i + 1]
, when0 <= i
andi < Rank - 1
.s[i] == 1
, wheni == Rank - 1
.
constexpr pointer data() const noexcept;
Returns:
A pointer to the contiguous sequence on which the view was createddata_
.
array_view
element access [arrayview.elem]Add a new section:
constexpr reference operator[](const
indexoffset_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 <= slice
andslice < bounds()[0]
.Returns: A view
vw
such thatthe initial elementvw.data_
is(*this)[{slice, 0, 0, ..., 0}]
, andthe boundsvw.bounds_
areis{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
indexoffset_type& origin, const bounds_type& section_bnd) const;Requires:
bounds().contains(origin + idx) == true
for anysuch that
indexoffset_type idxsection_bnd.contains(idx) == true
.Returns: A strided view
vw
such thatthe initial elementvw.data_
is(*this)[origin]
,the stridevw.stride_
isstride()
, andthe boundsvw.bounds_
areissection_bnd
.
constexpr strided_array_view<T, Rank> section(const
indexoffset_type& origin) const;Requires:
bounds().contains(origin + idx) == true
for anysuch that
indexoffset_type idx(bounds() - origin).contains(idx) == true
.Returns: A strided view
vw
such thatthe initial elementvw.data_
is(*this)[origin]
,the stridevw.stride_
isstride()
, andthe boundsvw.bounds_
areisbounds() - origin
.
strided_array_view
[stridedarrayview]Add a new section:
namespace std { template <class T,
intsize_t Rank = 1> class strided_array_view { public: // constants and types static constexprintsize_t rank = Rank; usingindexoffset_type =indexoffset<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,indexoffset_type stride);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; constexprindexoffset_type stride() const noexcept; // [stridedarrayview.elem], strided_array_view element access constexpr reference operator[](constindexoffset_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(constindexoffset_type& origin, const bounds_type& section_bnd) const; constexpr strided_array_view<T, Rank> section(constindexoffset_type& origin) const; private: pointer data_; // exposition only bounds_type bounds_; // exposition only offset_type stride_; // exposition only }; }
strided_array_view
requirements [stridedarrayview.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]
.
strided_array_view
constructors, copy, and assignment [stridedarrayview.cons]Add a new section:
constexpr strided_array_view() noexcept;
Postconditions:
data_ == nullptr
,bounds
, and()_.size() == 0stride
()_ ==indexoffset_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: For both constructors,
bounds
and()_ == rhs.bounds()stride
. For the first constructor,()_ == rhs.stride()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>
istrue
andis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>
istrue
.
constexpr strided_array_view(pointer ptr, bounds_type bounds,
indexoffset_type stride);Requires: For any
such that
indexoffset_type idxbounds.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
, and()_ == boundsstride
.()_ == stride
template <class U> constexpr strided_array_view& operator=(const strided_array_view<U, Rank>& rhs) noexcept;
Postconditions:bounds() == rhs.bounds()
,stride() == rhs.stride()
, anddata_ == rhs.data_
.
Returns:*this
.
Remarks: This function shall not participate in overload resolution unlessis_convertible_v<add_pointer_t<U>, pointer>
istrue
andis_same_v<remove_cv_t<U>, remove_cv_t<value_type>>
istrue
.
strided_array_view
observers [stridedarrayview.obs]Add a new section:
constexpr bounds_type bounds() const noexcept;
Returns:
The bounds of the viewbounds_
.
constexpr size_type size() const noexcept;
Returns:
bounds().size()
.
constexpr
indexoffset_type stride() const noexcept;Returns:
The stride of the viewstride_
.
strided_array_view
element access [stridedarrayview.elem]Add a new section:
constexpr reference operator[](const
indexoffset_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 <= slice
andslice < bounds()[0]
.Returns: A strided view
vw
such thatthe initial elementvw.data_
is(*this)[{slice, 0, 0, ..., 0}]
,the boundsvw.bounds_
areis{bounds()[1], bounds()[2], ..., bounds()[Rank - 1]}
, andthe stridevw.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
indexoffset_type& origin, const bounds_type& section_bnd) const;Requires:
bounds().contains(origin + idx) == true
for anysuch that
indexoffset_type idxsection_bnd.contains(idx) == true
.Returns: A strided view
vw
such thatthe initial elementvw.data_
is(*this)[origin]
,the stridevw.stride_
isstride()
, andthe boundsvw.bounds_
areissection_bnd
.
constexpr strided_array_view<T, Rank> section(const
indexoffset_type& origin) const;Requires:
bounds().contains(origin + idx) == true
for anysuch that
indexoffset_type idx(bounds() - origin).contains(idx) == true
.Returns: A strided view
vw
such thatthe initial elementvw.data_
is(*this)[origin]
,the stridevw.stride_
isstride()
, andthe boundsvw.bounds_
areisbounds() - 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>
.