From be20e45502d97727f114589327705aff11a2f339 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Mon, 26 Sep 2022 17:39:44 -0700 Subject: [PATCH 01/31] structure for range iterators --- docs/standard-library/range-iterators.md | 151 +++++++++++++++++++++++ docs/standard-library/toc.yml | 2 + 2 files changed, 153 insertions(+) create mode 100644 docs/standard-library/range-iterators.md diff --git a/docs/standard-library/range-iterators.md b/docs/standard-library/range-iterators.md new file mode 100644 index 00000000000..05c2ddcad88 --- /dev/null +++ b/docs/standard-library/range-iterators.md @@ -0,0 +1,151 @@ +JTW - stub topic to convert to range-iterators. + + +--- +description: "Learn more about range concepts and range iterator concepts." +title: "Concepts for ranges and range iterators" +ms.date: 09/22/2022 +f1_keywords: ["ranges/std::ranges::range"] +helpviewer_keywords: ["std::ranges [C++], range"] +--- +# Concepts for + +Concepts are are C++20 language feature used to constrain template parameters at compile time. They help prevent incorrect template instantiations, convey template argument requirements in a readable form, and provide more succinct template related compiler errors. + +Consider the following example, which defines a concept to prevent instantiating a template with types that can't be divided: + +```cpp +// requires /std:c++20 or later + +// Definition of the concept "dividable" that requires +// that arguments a & b can be divided +template +concept dividable = requires (T a, T b) +{ + a / b; +}; + +// Apply the concept to a template +// The template will only be instantiated if the argument T can do division +// This prevents the template from being instantiated with types that can't be divided +// This could have been applied to the parameter of a template function, but because +// most of the concepts in the library are applied to classes, this form is used +template requires dividable +class DivideEmUp +{ +public: + T Divide(T x, T y) + { + return x / y; + } +}; + +void main() +{ + DivideEmUp dividerOfInts; + std::cout << dividerOfInts.Divide(6, 3); // outputs: 2 + // The following line will not compile because the template can't be instantiated + // with char* because char* can be divided + DivideEmUp dividerOfCharPtrs; // compiler error: cannot deduce template arguments +} +``` + +The following concepts are defined in `std::ranges` and are declared in the `` header file. They are used in the declarations of [range adaptors](range-adaptors.md), [views](views.md), and so on. + +| **Range concept ** | **Description** | +|--|--| +| [`range`](#range)C++20 | A `range` is a type that can be iterated. | +| [`borrowed_range`](#borrowed_range)C++20 | The validity of the iterators for a `borrowed_range` are not tied to the object's lifetime. | +| [`sized_range`](#sized_range)C++20 | A `range` that can provide the number of its elements in amortized constant time via `ranges::size` | + +## `borrowed_range` + +A type models `borrowed_range` if the validity of iterators you get from the object can outlive the lifetime of the object. + +```cpp +template +concept borrowed_range = + range && + (is_lvalue_reference_v || enable_borrowed_range>); +``` + +### Parameters + +*`T`*\ +The type to test to see if it is a `borrowed_range`. + +## `range` + +Defines the requirements a type must meet to be a `range`. A `range` provides an iterator and a sentinel for iterating over the elements in the `range`. + +```cpp +template +concept range = requires(T& rg) +{ + ranges::begin(rg); + ranges::end(rg); +}; +``` + +### Parameters + +*`T`*\ +The type to test to see if it is a `range`. + +*`rg`*\ +An instance of `R` to test. + +### Remarks + +The requirements of a `range` are: +- it can be iterated using `std::ranges::begin()` and `std::ranges::end()` +- `ranges::begin(rg)` and `ranges::end(rg)` run in amortized constant time and don't modify the `range`. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. +- \[`ranges::begin(rg)`, `ranges::end(rg)`) denotes a valid range. + + +## `sized_range` + +A `sized_range` can provide the number of its elements in amortized constant time via `ranges::size`. + +```cpp +template + concept sized_range = range && + requires(T& t) { ranges::size(t); }; +``` + +### Parameters + +*`T`*\ +The type to test to see if it is a `sized_range`. + +*`t`*\ +An instance of `T` to test. + +### Remarks + +The requirements of a `sized_range` are that calling `ranges::size` on it: +- Doesn't modify the `range`. +- Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. + +### Example `sized_range` + +The following example demonstrates that a vector of ints satisfies the requirements of a `sized_range`: + +```cpp +// requires /std:c++20 or later +#include +#include +#include + +int main() +{ + std::cout << boolalpha << std::ranges::sized_range> << '\n'; // outputs: true +} +``` + + +## See also + +[``](ranges.md)\ +[Range adaptors](range-adaptors.md)\ +[View classes](view-classes.md) \ No newline at end of file diff --git a/docs/standard-library/toc.yml b/docs/standard-library/toc.yml index b53f32031ea..5488c3ddc35 100644 --- a/docs/standard-library/toc.yml +++ b/docs/standard-library/toc.yml @@ -928,6 +928,8 @@ items: href: ranges.md - name: functions href: range-functions.md + - name: iterators + href: range-iterators.md - name: href: ratio.md - name: From 3a59991be93359828e08779dc0e11595925e8882 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 30 Sep 2022 13:14:15 -0700 Subject: [PATCH 02/31] draft --- docs/standard-library/iterator-functions.md | 125 ++++++++++---------- docs/standard-library/iterator.md | 94 +++++++-------- 2 files changed, 109 insertions(+), 110 deletions(-) diff --git a/docs/standard-library/iterator-functions.md b/docs/standard-library/iterator-functions.md index feb86fe2e25..c5664a0365b 100644 --- a/docs/standard-library/iterator-functions.md +++ b/docs/standard-library/iterator-functions.md @@ -1,14 +1,13 @@ --- description: "Learn more about: functions" title: " functions" -ms.date: "11/04/2016" +ms.date: 09/29/2022 f1_keywords: ["xutility/std::advance", "xutility/std::back_inserter", "xutility/std::begin", "xutility/std::cbegin", "xutility/std::cend", "xutility/std::distance", "xutility/std::end", "xutility/std::front_inserter", "xutility/std::inserter", "xutility/std::make_checked_array_iterator", "xutility/std::make_move_iterator", "xutility/std::make_unchecked_array_iterator", "xutility/std::next", "xutility/std::prev"] -ms.assetid: 4a57c9a3-7e36-411f-8655-e0be2eec88e7 helpviewer_keywords: ["std::advance [C++]", "std::back_inserter [C++]", "std::begin [C++]", "std::cbegin [C++]", "std::cend [C++]", "std::distance [C++]", "std::end [C++]", "std::front_inserter [C++]", "std::inserter [C++]", "std::make_checked_array_iterator [C++]", "std::make_move_iterator [C++]", "std::make_unchecked_array_iterator [C++]", "std::next [C++]", "std::prev [C++]"] --- # `` functions -## advance +## ` advance` Increments an iterator by a specified number of positions. @@ -19,17 +18,17 @@ template ### Parameters -*InIt*\ +*`InIt`*\ The iterator that is to be incremented and that must satisfy the requirements for an input iterator. -*Off*\ +*`Off`*\ An integral type that is convertible to the iterator's difference type and that specifies the number of increments the position of the iterator is to be advanced. ### Remarks The range advanced through must be nonsingular, where the iterators must be dereferenceable or past the end. -If the `InputIterator` satisfies the requirements for a bidirectional iterator type, then *Off* may be negative. If `InputIterator` is an input or forward iterator type, *Off* must be nonnegative. +If the `InputIterator` satisfies the requirements for a bidirectional iterator type, then *`Off`* may be negative. If `InputIterator` is an input or forward iterator type, *`Off`* must be nonnegative. The advance function has constant complexity when `InputIterator` satisfies the requirements for a random-access iterator; otherwise, it has linear complexity and so is potentially expensive. @@ -80,23 +79,23 @@ LPOS is advanced 4 steps forward to point to the fifth element: 5. LPOS is moved 3 steps back to point to the 2nd element: 2. ``` -## back_inserter +## `back_inserter` Creates an iterator that can insert elements at the back of a specified container. ```cpp template -back_insert_iterator back_inserter(Container& _Cont); +back_insert_iterator back_inserter(Container& Cont); ``` ### Parameters -*_Cont*\ +*`Cont`*\ The container into which the back insertion is to be executed. ### Return Value -A `back_insert_iterator` associated with the container object *_Cont*. +A `back_insert_iterator` associated with the container object *`Cont`*. ### Remarks @@ -151,7 +150,7 @@ The initial vector vec is: ( 0 1 2 ). After the insertions, the vector vec is: ( 0 1 2 30 40 500 600 ). ``` -## begin +## `begin` Retrieves an iterator to the first element in a specified container. @@ -170,17 +169,17 @@ Ty *begin(Ty (& array)[Size]); ### Parameters -*cont*\ +*`cont`*\ A container. -*array*\ +*`array`*\ An array of objects of type `Ty`. ### Return Value The first two template functions return `cont.begin()`. The first function is non-constant; the second one is constant. -The third template function returns *array*. +The third template function returns *`array`*. ### Example @@ -253,7 +252,7 @@ Then sending an array to it would cause this compiler error: error C2228: left of '.begin' must have class/struct/union ``` -## cbegin +## `cbegin` Retrieves a const iterator to the first element in a specified container. @@ -265,7 +264,7 @@ auto cbegin(const Container& cont) ### Parameters -*cont*\ +*`cont`*\ A container or initializer_list. ### Return Value @@ -286,7 +285,7 @@ auto i2 = Container.cbegin(); // i2 is Container::const_iterator ``` -## cend +## `cend` Retrieves a const iterator to the element that follows the last element in the specified container. @@ -298,7 +297,7 @@ auto cend(const Container& cont) ### Parameters -*cont*\ +*`cont`*\ A container or initializer_list. ### Return Value @@ -319,19 +318,19 @@ auto i2 = Container.cend(); // i2 is Container::const_iterator ``` -## crbegin +## `crbegin` ```cpp template constexpr auto crbegin(const C& c) -> decltype(std::rbegin(c)); ``` -## crend +## `crend` ```cpp template constexpr auto crend(const C& c) -> decltype(std::rend(c)); ``` -## data +## `data` ```cpp template constexpr auto data(C& c) -> decltype(c.data()); @@ -340,7 +339,7 @@ template constexpr T* data(T (&array)[N]) noexcept; template constexpr const E* data(initializer_list il) noexcept; ``` -## distance +## `distance` Determines the number of increments between the positions addressed by two iterators. @@ -351,15 +350,15 @@ typename iterator_traits::difference_type distance(InputIterator ### Parameters -*first*\ +*`first`*\ The first iterator whose distance from the second is to be determined. -*last*\ +*`last`*\ The second iterator whose distance from the first is to be determined. ### Return Value -The number of times that *first* must be incremented until it equal *last*. +The number of times that *`first`* must be incremented until it equal *`last`*. ### Remarks @@ -413,7 +412,7 @@ LPOS is advanced 7 steps forward to point to the eighth element: 12. The distance from L.begin( ) to LPOS is: 7. ``` -## empty +## `empty` ```cpp template constexpr auto empty(const C& c) -> decltype(c.empty()); @@ -421,7 +420,7 @@ template constexpr bool empty(const T (&array)[N]) noexcept; template constexpr bool empty(initializer_list il) noexcept; ``` -## end +## `end` Retrieves an iterator to the element that follows the last element in the specified container. @@ -440,10 +439,10 @@ Ty *end(Ty (& array)[Size]); ### Parameters -*cont*\ +*`cont`*\ A container. -*array*\ +*`array`*\ An array of objects of type `Ty`. ### Return Value @@ -454,25 +453,25 @@ The third template function returns `array + Size`. ### Remarks -For a code example, see [begin](../standard-library/iterator-functions.md#begin). +For a code example, see [`begin`](../standard-library/iterator-functions.md#begin). -## front_inserter +## `front_inserter` Creates an iterator that can insert elements at the front of a specified container. ```cpp template -front_insert_iterator front_inserter(Container& _Cont); +front_insert_iterator front_inserter(Container& Cont); ``` ### Parameters -*_Cont*\ +*`Cont`*\ The container object whose front is having an element inserted. ### Return Value -A `front_insert_iterator` associated with the container object *_Cont*. +A `front_insert_iterator` associated with the container object *`Cont`*. ### Remarks @@ -527,29 +526,29 @@ After the front insertions, the list L is: ( 200 100 -1 0 1 2 3 4 5 6 7 8 ). ``` -## inserter +## `inserter` -A helper template function that lets you use `inserter(_Cont, _Where)` instead of `insert_iterator(_Cont, _Where)`. +A helper template function that lets you use `inserter(Cont, Where)` instead of `insert_iterator(Cont, Where)`. ```cpp template insert_iterator inserter( - Container& _Cont, - typename Container::iterator _Where); + Container& Cont, + typename Container::iterator Where); ``` ### Parameters -*_Cont*\ +*`Cont`*\ The container to which new elements are to be added. -*_Where*\ +*`Where`*\ An iterator locating the point of insertion. ### Remarks -The template function returns [insert_iterator](../standard-library/insert-iterator-class.md#insert_iterator)`(_Cont, _Where)`. +The template function returns [`insert_iterator`](../standard-library/insert-iterator-class.md#insert_iterator)`(Cont, Where)`. ### Example @@ -598,7 +597,7 @@ After the insertions, the list L is: ( 1 20 30 40 500 ). ``` -## make_checked_array_iterator +## `make_checked_array_iterator` Creates a [checked_array_iterator](../standard-library/checked-array-iterator-class.md) that can be used by other algorithms. @@ -616,13 +615,13 @@ Iter Ptr, ### Parameters -*Ptr*\ +*`Ptr`*\ A pointer to the destination array. -*Size*\ +*`Size`*\ The size of the destination array. -*Index*\ +*`Index`*\ Optional index into the array. ### Return Value @@ -692,26 +691,26 @@ int main() } ``` -## make_move_iterator +## `make_move_iterator` Creates a `move iterator` that contains the provided iterator as the `stored` iterator. ```cpp template move_iterator -make_move_iterator(const Iterator& _It); +make_move_iterator(const Iterator& It); ``` ### Parameters -*_It*\ +*`It`*\ The iterator stored in the new move iterator. ### Remarks The template function returns `move_iterator` `(_It)`. -## make_unchecked_array_iterator +## `make_unchecked_array_iterator` Creates an [unchecked_array_iterator](../standard-library/unchecked-array-iterator-class.md) that can be used by other algorithms. @@ -726,7 +725,7 @@ unchecked_array_iterator ### Parameters -*Ptr*\ +*`Ptr`*\ A pointer to the destination array. ### Return Value @@ -790,7 +789,7 @@ int main() } ``` -## next +## `next` Iterates a specified number of times and returns the new iterator position. @@ -798,26 +797,26 @@ Iterates a specified number of times and returns the new iterator position. template InputIterator next( InputIterator first, - typename iterator_traits::difference_type _Off = 1); + typename iterator_traits::difference_type off = 1); ``` ### Parameters -*first*\ +*`first`*\ The current position. -*_Off*\ +*`off`*\ The number of times to iterate. ### Return Value -Returns the new iterator position after iterating *_Off* times. +Returns the new iterator position after iterating *`off`* times. ### Remarks -The template function returns `next` incremented *_Off* times +The template function returns `next` incremented *`off`* times -## prev +## `prev` Iterates in reverse a specified number of times and returns the new iterator position. @@ -825,36 +824,36 @@ Iterates in reverse a specified number of times and returns the new iterator pos template BidirectionalIterator prev( BidirectionalIterator first, - typename iterator_traits::difference_type _Off = 1); + typename iterator_traits::difference_type off = 1); ``` ### Parameters -*first*\ +*`first`*\ The current position. -*_Off*\ +*`off`*\ The number of times to iterate. ### Remarks The template function returns `next` decremented `off` times. -## rbegin +## `rbegin` ```cpp template constexpr auto rbegin(C& c) -> decltype(c.rbegin()); template constexpr auto rbegin(const C& c) -> decltype(c.rbegin()); ``` -## rend +## `rend` ```cpp template constexpr auto rend(C& c) -> decltype(c.rend()); template constexpr auto rend(const C& c) -> decltype(c.rend()); ``` -## size +## `size` ```cpp template constexpr auto size(const C& c) -> decltype(c.size()); diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index 6c368dae392..5f75beb3595 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -40,63 +40,63 @@ Visual Studio has added extensions to C++ Standard Library iterators to support |Name|Description| |-|-| -|[advance](../standard-library/iterator-functions.md#advance)|Increments an iterator by a specified number of positions.| -|[back_inserter](../standard-library/iterator-functions.md#back_inserter)|Creates an iterator that can insert elements at the back of a specified container.| -|[begin](../standard-library/iterator-functions.md#begin)|Retrieves an iterator to the first element in a specified container.| -|[cbegin](../standard-library/iterator-functions.md#cbegin)|Retrieves a constant iterator to the first element in a specified container.| -|[cend](../standard-library/iterator-functions.md#cend)|Retrieves a constant iterator to the element that follows the last element in the specified container.| -|[crbegin](../standard-library/iterator-functions.md#crbegin)|| -|[crend](../standard-library/iterator-functions.md#crend)|| -|[data](../standard-library/iterator-functions.md#data)|| -|[distance](../standard-library/iterator-functions.md#distance)|Determines the number of increments between the positions addressed by two iterators.| -|[end](../standard-library/iterator-functions.md#end)|Retrieves an iterator to the element that follows the last element in the specified container.| -|[empty](../standard-library/iterator-functions.md#empty)|| -|[front_inserter](../standard-library/iterator-functions.md#front_inserter)|Creates an iterator that can insert elements at the front of a specified container.| -|[inserter](../standard-library/iterator-functions.md#inserter)|An iterator adaptor that adds a new element to a container at a specified point of insertion.| -|[make_checked_array_iterator](../standard-library/iterator-functions.md#make_checked_array_iterator)|Creates a [checked_array_iterator](../standard-library/checked-array-iterator-class.md) that can be used by other algorithms. **Note:** This function is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| -|[make_move_iterator](../standard-library/iterator-functions.md#make_move_iterator)|Returns a move iterator containing the provided iterator as its stored base iterator.| -|[make_unchecked_array_iterator](../standard-library/iterator-functions.md#make_unchecked_array_iterator)|Creates an [unchecked_array_iterator](../standard-library/unchecked-array-iterator-class.md) that can be used by other algorithms. **Note:** This function is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| -|[next](../standard-library/iterator-functions.md#next)|Iterates a specified number of times and returns the new iterator position.| -|[prev](../standard-library/iterator-functions.md#prev)|Iterates in reverse a specified number of times and returns the new iterator position.| -|[rbegin](../standard-library/iterator-functions.md#rbegin)|| -|[rend](../standard-library/iterator-functions.md#rend)|| -|[size](../standard-library/iterator-functions.md#size)|| +|[`advance`](../standard-library/iterator-functions.md#advance)|Increments an iterator by a specified number of positions.| +|[`back_inserter`](../standard-library/iterator-functions.md#back_inserter)|Creates an iterator that can insert elements at the back of a specified container.| +|[`begin`](../standard-library/iterator-functions.md#begin)|Retrieves an iterator to the first element in a specified container.| +|[`cbegin`](../standard-library/iterator-functions.md#cbegin)|Retrieves a read-only iterator to the first element in the container.| +|[`cend`](../standard-library/iterator-functions.md#cend)|Retrieves a read-only iterator to the sentinel that follows the last element in the specified container.| +|[`crbegin`](../standard-library/iterator-functions.md#crbegin)| Get a reverse read-only iterator to the beginning of the container.| +|[`crend`](../standard-library/iterator-functions.md#crend)| Get the sentinel at the end of what `crbegin()` returns.| +|[`data`](../standard-library/iterator-functions.md#data)| Get a pointer to the first element in the container.| +|[`distance`](../standard-library/iterator-functions.md#distance)|Determines the number of increments between the positions addressed by two iterators.| +|[`end`](../standard-library/iterator-functions.md#end)|Retrieves an iterator to the element that follows the last element in the specified container.| +|[`empty`](../standard-library/iterator-functions.md#empty)| Test if the container is empty.| +|[`front_inserter`](../standard-library/iterator-functions.md#front_inserter)|Creates an iterator that can insert elements at the front of a specified container.| +|[`inserter`](../standard-library/iterator-functions.md#inserter)|An iterator adaptor that adds a new element to a container at a specified point of insertion.| +|[`make_checked_array_iterator`](../standard-library/iterator-functions.md#make_checked_array_iterator)|Creates a [`checked_array_iterator`](../standard-library/checked-array-iterator-class.md) that can be used by other algorithms. **Note:** This function is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| +|[`make_move_iterator`](../standard-library/iterator-functions.md#make_move_iterator)|Returns a move iterator containing the provided iterator as its stored base iterator.| +|[`make_unchecked_array_iterator`](../standard-library/iterator-functions.md#make_unchecked_array_iterator)|Creates an [`unchecked_array_iterator`](../standard-library/unchecked-array-iterator-class.md) that can be used by other algorithms. **Note:** This function is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| +|[`next`](../standard-library/iterator-functions.md#next)|Iterates a specified number of times and returns the new iterator position.| +|[`prev`](../standard-library/iterator-functions.md#prev)|Iterates in reverse a specified number of times and returns the new iterator position.| +|[`rbegin`](../standard-library/iterator-functions.md#rbegin)|Get a reverse iterator to the beginning of the container. | +|[`rend`](../standard-library/iterator-functions.md#rend)| Get a reverse iterator to the sentinel at the end of the container.| +|[`size`](../standard-library/iterator-functions.md#size)| Get the number of elements.| ### Operators |Name|Description| |-|-| -|[operator!=](../standard-library/iterator-operators.md#op_neq)|Tests if the iterator object on the left side of the operator is not equal to the iterator object on the right side.| -|[operator==](../standard-library/iterator-operators.md#op_eq_eq)|Tests if the iterator object on the left side of the operator is equal to the iterator object on the right side.| -|[operator<](../standard-library/iterator-operators.md#op_lt)|Tests if the iterator object on the left side of the operator is less than the iterator object on the right side.| -|[operator\<=](../standard-library/iterator-operators.md#op_gt_eq)|Tests if the iterator object on the left side of the operator is less than or equal to the iterator object on the right side.| -|[operator>](../standard-library/iterator-operators.md#op_gt)|Tests if the iterator object on the left side of the operator is greater than the iterator object on the right side.| -|[operator>=](../standard-library/iterator-operators.md#op_gt_eq)|Tests if the iterator object on the left side of the operator is greater than or equal to the iterator object on the right side.| -|[operator+](../standard-library/iterator-operators.md#op_add)|Adds an offset to an iterator and returns the new `reverse_iterator` addressing the inserted element at the new offset position.| -|[operator-](../standard-library/iterator-operators.md#operator-)|Subtracts one iterator from another and returns the difference.| +|[`operator!=`](../standard-library/iterator-operators.md#op_neq)|Tests if the iterator object on the left side of the operator is not equal to the iterator object on the right side.| +|[`operator==`](../standard-library/iterator-operators.md#op_eq_eq)|Tests if the iterator object on the left side of the operator is equal to the iterator object on the right side.| +|[`operator<`](../standard-library/iterator-operators.md#op_lt)|Tests if the iterator object on the left side of the operator is less than the iterator object on the right side.| +|[`operator<=`](../standard-library/iterator-operators.md#op_gt_eq)|Tests if the iterator object on the left side of the operator is less than or equal to the iterator object on the right side.| +|[`operator>`](../standard-library/iterator-operators.md#op_gt)|Tests if the iterator object on the left side of the operator is greater than the iterator object on the right side.| +|[`operator>=`](../standard-library/iterator-operators.md#op_gt_eq)|Tests if the iterator object on the left side of the operator is greater than or equal to the iterator object on the right side.| +|[`operator+`](../standard-library/iterator-operators.md#op_add)|Adds an offset to an iterator and returns the new `reverse_iterator` addressing the inserted element at the new offset position.| +|[`operator-`](../standard-library/iterator-operators.md#operator-)|Subtracts one iterator from another and returns the difference.| ### Classes |Name|Description| |-|-| -|[back_insert_iterator](../standard-library/back-insert-iterator-class.md)|The class template describes an output iterator object. It inserts elements into a container of type `Container`, which it accesses through the protected `pointer` object it stores called container.| -|[bidirectional_iterator_tag](../standard-library/bidirectional-iterator-tag-struct.md)|A class that provides a return type for an `iterator_category` function that represents a bidirectional iterator.| -|[checked_array_iterator](../standard-library/checked-array-iterator-class.md)|A class that accesses an array using a random access, checked iterator. **Note:** This class is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| -|[forward_iterator_tag](../standard-library/forward-iterator-tag-struct.md)|A class that provides a return type for an `iterator_category` function that represents a forward iterator.| -|[front_insert_iterator](../standard-library/front-insert-iterator-class.md)|The class template describes an output iterator object. It inserts elements into a container of type `Container`, which it accesses through the protected `pointer` object it stores called container.| -|[input_iterator_tag](../standard-library/input-iterator-tag-struct.md)|A class that provides a return type for an `iterator_category` function that represents an input iterator.| -|[insert_iterator](../standard-library/insert-iterator-class.md)|The class template describes an output iterator object. It inserts elements into a container of type `Container`, which it accesses through the protected `pointer` object it stores called container. It also stores the protected `iterator` object, of class `Container::iterator`, called `iter`.| -|[istream_iterator](../standard-library/istream-iterator-class.md)|The class template describes an input iterator object. It extracts objects of class `Ty` from an input stream, which it accesses through an object it stores, of type pointer to `basic_istream`\<**Elem**, **Tr**>.| -|[istreambuf_iterator](../standard-library/istreambuf-iterator-class.md)|The class template describes an input iterator object. It inserts elements of class `Elem` into an output stream buffer, which it accesses through an object it stores, of type `pointer` to `basic_streambuf`\<**Elem**, **Tr**>.| -|[iterator](../standard-library/iterator-struct.md)|The class template is used as a base type for all iterators.| -|[iterator_traits](../standard-library/iterator-traits-struct.md)|A template helper class providing critical types that are associated with different iterator types so that they can be referred to in the same way.| -|[move_iterator](../standard-library/move-iterator-class.md)|A `move_iterator` object stores a random-access iterator of type `RandomIterator`. It behaves like a random-access iterator, except when dereferenced. The result of `operator*` is implicitly cast to `value_type&&:` to make an `rvalue reference`.| -|[ostream_iterator](../standard-library/ostream-iterator-class.md)|The class template describes an output iterator object. It inserts objects of class `Type` into an output stream, which it accesses through an object it stores, of type `pointer` to `basic_ostream`\<**Elem**, **Tr**>.| -|[ostreambuf_iterator Class](../standard-library/ostreambuf-iterator-class.md)|The class template describes an output iterator object. It inserts elements of class `Elem` into an output stream buffer, which it accesses through an object it stores, of type pointer to `basic_streambuf`\<**Elem**, **Tr**>.| -|[output_iterator_tag](../standard-library/output-iterator-tag-struct.md)|A class that provides a return type for `iterator_category` function that represents an output iterator.| -|[random_access_iterator_tag](../standard-library/random-access-iterator-tag-struct.md)|A class that provides a return type for `iterator_category` function that represents a random-access iterator.| -|[reverse_iterator](../standard-library/reverse-iterator-class.md)|The class template describes an object that behaves like a random-access iterator, only in reverse.| -|[unchecked_array_iterator](../standard-library/unchecked-array-iterator-class.md)|A class that accesses an array using a random access, unchecked iterator. **Note:** This class is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| +|[`back_insert_iterator`](../standard-library/back-insert-iterator-class.md)|The class template describes an output iterator object. It inserts elements into a container of type `Container`, which it accesses through the protected `pointer` object it stores called container.| +|[`bidirectional_iterator_tag`](../standard-library/bidirectional-iterator-tag-struct.md)|A class that provides a return type for an `iterator_category` function that represents a bidirectional iterator.| +|[`checked_array_iterator`](../standard-library/checked-array-iterator-class.md)|A class that accesses an array using a random access, checked iterator. **Note:** This class is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| +|[`forward_iterator_tag`](../standard-library/forward-iterator-tag-struct.md)|A class that provides a return type for an `iterator_category` function that represents a forward iterator.| +|[`front_insert_iterator`](../standard-library/front-insert-iterator-class.md)|The class template describes an output iterator object. It inserts elements into a container of type `Container`, which it accesses through the protected `pointer` object it stores called container.| +|[`input_iterator_tag`](../standard-library/input-iterator-tag-struct.md)|A class that provides a return type for an `iterator_category` function that represents an input iterator.| +|[`insert_iterator`](../standard-library/insert-iterator-class.md)|The class template describes an output iterator object. It inserts elements into a container of type `Container`, which it accesses through the protected `pointer` object it stores called container. It also stores the protected `iterator` object, of class `Container::iterator`, called `iter`.| +|[`istream_iterator`](../standard-library/istream-iterator-class.md)|The class template describes an input iterator object. It extracts objects of class `Ty` from an input stream, which it accesses through an object it stores, of type pointer to `basic_istream`\<**Elem**, **Tr**>.| +|[`istreambuf_iterator`](../standard-library/istreambuf-iterator-class.md)|The class template describes an input iterator object. It inserts elements of class `Elem` into an output stream buffer, which it accesses through an object it stores, of type `pointer` to `basic_streambuf`\<**Elem**, **Tr**>.| +|[`iterator`](../standard-library/iterator-struct.md)|The class template is used as a base type for all iterators.| +|[`iterator_traits`](../standard-library/iterator-traits-struct.md)|A template helper class providing critical types that are associated with different iterator types so that they can be referred to in the same way.| +|[`move_iterator`](../standard-library/move-iterator-class.md)|A `move_iterator` object stores a random-access iterator of type `RandomIterator`. It behaves like a random-access iterator, except when dereferenced. The result of `operator*` is implicitly cast to `value_type&&:` to make an `rvalue reference`.| +|[`ostream_iterator`](../standard-library/ostream-iterator-class.md)|The class template describes an output iterator object. It inserts objects of class `Type` into an output stream, which it accesses through an object it stores, of type `pointer` to `basic_ostream`\<**Elem**, **Tr**>.| +|[`ostreambuf_iterator` class](../standard-library/ostreambuf-iterator-class.md)|The class template describes an output iterator object. It inserts elements of class `Elem` into an output stream buffer, which it accesses through an object it stores, of type pointer to `basic_streambuf`\<**Elem**, **Tr**>.| +|[`output_iterator_tag`](../standard-library/output-iterator-tag-struct.md)|A class that provides a return type for `iterator_category` function that represents an output iterator.| +|[`random_access_iterator_tag`](../standard-library/random-access-iterator-tag-struct.md)|A class that provides a return type for `iterator_category` function that represents a random-access iterator.| +|[`reverse_iterator`](../standard-library/reverse-iterator-class.md)|The class template describes an object that behaves like a random-access iterator, only in reverse.| +|[`unchecked_array_iterator`](../standard-library/unchecked-array-iterator-class.md)|A class that accesses an array using a random access, unchecked iterator. **Note:** This class is a Microsoft extension of the C++ Standard Library. Code implemented by using this function is not portable to C++ Standard build environments that do not support this Microsoft extension.| ## See also From 4c8221e0d2d70d96c117a034c77779b5498d3401 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 2 Dec 2022 14:30:23 -0800 Subject: [PATCH 03/31] match incoming changes --- docs/standard-library/iterator-functions.md | 83 +++++++++++---------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/docs/standard-library/iterator-functions.md b/docs/standard-library/iterator-functions.md index 6ecb7d0a31f..4c94abb0ae8 100644 --- a/docs/standard-library/iterator-functions.md +++ b/docs/standard-library/iterator-functions.md @@ -3,12 +3,11 @@ description: "Learn more about: functions" title: " functions" ms.date: "11/04/2016" f1_keywords: ["xutility/std::advance", "xutility/std::back_inserter", "xutility/std::begin", "xutility/std::cbegin", "xutility/std::cend", "xutility/std::distance", "xutility/std::end", "xutility/std::front_inserter", "xutility/std::inserter", "xutility/std::make_checked_array_iterator", "xutility/std::make_move_iterator", "xutility/std::make_unchecked_array_iterator", "xutility/std::next", "xutility/std::prev"] -ms.assetid: 4a57c9a3-7e36-411f-8655-e0be2eec88e7 helpviewer_keywords: ["std::advance [C++]", "std::back_inserter [C++]", "std::begin [C++]", "std::cbegin [C++]", "std::cend [C++]", "std::distance [C++]", "std::end [C++]", "std::front_inserter [C++]", "std::inserter [C++]", "std::make_checked_array_iterator [C++]", "std::make_move_iterator [C++]", "std::make_unchecked_array_iterator [C++]", "std::next [C++]", "std::prev [C++]"] --- # `` functions -## advance +## `advance` Increments an iterator by a specified number of positions. @@ -19,17 +18,17 @@ void advance(InputIterator& InIt, Distance Off); ### Parameters -*InIt*\ +*`InIt`*\ The iterator that is to be incremented and that must satisfy the requirements for an input iterator. -*Off*\ +*`Off`*\ An integral type that is convertible to the iterator's difference type and that specifies the number of increments the position of the iterator is to be advanced. ### Remarks The range must be nonsingular, where the iterators must be dereferenceable or past the end. -If the `InputIterator` satisfies the requirements for a bidirectional iterator type, then *Off* may be negative. If `InputIterator` is an input or forward iterator type, *Off* must be nonnegative. +If the `InputIterator` satisfies the requirements for a bidirectional iterator type, then *Off* may be negative. If `InputIterator` is an input or forward iterator type, *`Off`* must be nonnegative. The advance function has constant complexity when `InputIterator` satisfies the requirements for a random-access iterator; otherwise, it has linear complexity and so is potentially expensive. @@ -81,27 +80,27 @@ LPOS is advanced 4 steps forward to point to the fifth element: 5. LPOS is moved 3 steps back to point to the 2nd element: 2. ``` -## back_inserter +## `back_inserter` Creates an iterator that can insert elements at the back of a specified container. ```cpp template -back_insert_iterator back_inserter(Container& _Cont); +back_insert_iterator back_inserter(Container& Cont); ``` ### Parameters -*_Cont*\ +*`Cont`*\ The container into which the back insertion is to be executed. ### Return Value -A `back_insert_iterator` associated with the container object *_Cont*. +A `back_insert_iterator` associated with the container object *`Cont`*. ### Remarks -Within the C++ Standard Library, the argument must refer to one of the three sequence containers that have the member function `push_back`: [deque Class](../standard-library/deque-class.md), [list Class](../standard-library/list-class.md), or [vector Class](../standard-library/vector-class.md). +Within the C++ Standard Library, the argument must refer to one of the three sequence containers that have the member function `push_back`: [`deque` Class](../standard-library/deque-class.md), [`list` Class](../standard-library/list-class.md), or [`vector` Class](../standard-library/vector-class.md). ### Example @@ -154,7 +153,7 @@ The initial vector vec is: ( 0 1 2 ). After the insertions, the vector vec is: ( 0 1 2 30 40 500 600 ). ``` -## begin +## `begin` Retrieves an iterator to the first element in a specified container. @@ -173,17 +172,17 @@ Ty *begin(Ty (& array)[Size]); ### Parameters -*cont*\ +*`cont`*\ A container. -*array*\ +*`array`*\ An array of objects of type `Ty`. ### Return Value The first two template functions return `cont.begin()`. The first function is non-constant; the second one is constant. -The third template function returns *array*. +The third template function returns *`array`*. ### Example @@ -256,7 +255,7 @@ Then sending an array to it would cause this compiler error: error C2228: left of '.begin' must have class/struct/union ``` -## cbegin +## `cbegin` Retrieves a const (read-only) iterator to the first element in a specified container. @@ -268,7 +267,7 @@ auto cbegin(const Container& cont) ### Parameters -*cont*\ +*`cont`*\ A container or initializer_list. ### Return Value @@ -289,7 +288,7 @@ auto i2 = Container.cbegin(); // i2 is Container::const_iterator ``` -## cend +## `cend` Retrieves a const (read-only) iterator to the element that follows the last element in the specified container. @@ -301,8 +300,8 @@ auto cend(const Container& cont) ### Parameters -*cont*\ -A container or initializer_list. +*`cont`*\ +A container or `initializer_list`. ### Return Value @@ -322,7 +321,7 @@ auto i2 = Container.cend(); // i2 is Container::const_iterator ``` -## crbegin +## `crbegin` Get a reverse read-only iterator to the elements of the container, starting at the end of the container. @@ -330,7 +329,7 @@ Get a reverse read-only iterator to the elements of the container, starting at t template constexpr auto crbegin(const C& c) -> decltype(std::rbegin(c)); ``` -## crend +## Parameters *`C`*\ The type of the container. @@ -373,7 +372,7 @@ Get the sentinel at the end of a read-only reversed sequence of elements. template constexpr auto crend(const C& c) -> decltype(std::rend(c)); ``` -## data +## Parameters *`C`*\ The type of the container. @@ -403,7 +402,9 @@ int main() } ``` -## distance +```output +10 +``` ## `data` @@ -476,15 +477,15 @@ typename iterator_traits::difference_type distance(InputIterator ### Parameters -*first*\ +*`first`*\ The first iterator whose distance from the second is to be determined. -*last*\ +*`last`*\ The second iterator whose distance from the first is to be determined. ### Return Value -The number of times that *first* must be incremented until it equal *last*. +The number of times that *`first`* must be incremented until it equals *`last`*. ### Remarks @@ -539,7 +540,7 @@ LPOS is advanced 7 steps forward to point to the eighth element: 12. The distance from L.begin( ) to LPOS is: 7. ``` -## empty +## `empty` ```cpp template constexpr auto empty(const C& c) -> decltype(c.empty()); @@ -547,7 +548,7 @@ template constexpr bool empty(const T (&array)[N]) noexcept; template constexpr bool empty(initializer_list il) noexcept; ``` -## end +## Parameters *`C`*\ The type of the container. @@ -610,10 +611,10 @@ Ty *end(Ty (& array)[Size]); ### Parameters -*cont*\ +*`cont`*\ A container. -*array*\ +*`array`*\ An array of objects of type `Ty`. ### Return Value @@ -624,25 +625,25 @@ The third template function returns `array + Size`. ### Remarks -For a code example, see [begin](../standard-library/iterator-functions.md#begin). +For a code example, see [`begin`](../standard-library/iterator-functions.md#begin). -## front_inserter +## `front_inserter` Creates an iterator that can insert elements at the front of a specified container. ```cpp template -front_insert_iterator front_inserter(Container& _Cont); +front_insert_iterator front_inserter(Container& Cont); ``` ### Parameters -*_Cont*\ +*`Cont`*\ The container object whose front is having an element inserted. ### Return Value -A `front_insert_iterator` associated with the container object *_Cont*. +A `front_insert_iterator` associated with the container object *`Cont`*. ### Remarks @@ -701,27 +702,27 @@ After the front insertions, the list L is: ## inserter -A helper template function that lets you use `inserter(_Cont, _Where)` instead of `insert_iterator(_Cont, _Where)`. +A helper template function that lets you use `inserter(Cont, Where)` instead of `insert_iterator(Cont, Where)`. ```cpp template insert_iterator inserter( - Container& _Cont, - typename Container::iterator _Where); + Container& Cont, + typename Container::iterator Where); ``` ### Parameters -*_Cont*\ +*`Cont`*\ The container to which new elements are to be added. -*_Where*\ +*Where*\ An iterator locating the point of insertion. ### Remarks -The template function returns [insert_iterator](../standard-library/insert-iterator-class.md#insert_iterator)`(_Cont, _Where)`. +The template function returns [insert_iterator](../standard-library/insert-iterator-class.md#insert_iterator)`(Cont, Where)`. ### Example From f38bdee998232b2cc37a8715cbbc55d028ca3db2 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 2 Dec 2022 14:34:00 -0800 Subject: [PATCH 04/31] match incoming changes --- docs/standard-library/iterator-functions.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/standard-library/iterator-functions.md b/docs/standard-library/iterator-functions.md index 4c94abb0ae8..8bb9b11f764 100644 --- a/docs/standard-library/iterator-functions.md +++ b/docs/standard-library/iterator-functions.md @@ -28,7 +28,7 @@ An integral type that is convertible to the iterator's difference type and that The range must be nonsingular, where the iterators must be dereferenceable or past the end. -If the `InputIterator` satisfies the requirements for a bidirectional iterator type, then *Off* may be negative. If `InputIterator` is an input or forward iterator type, *`Off`* must be nonnegative. +If the `InputIterator` satisfies the requirements for a bidirectional iterator type, then *`Off`* may be negative. If `InputIterator` is an input or forward iterator type, *`Off`* must be nonnegative. The advance function has constant complexity when `InputIterator` satisfies the requirements for a random-access iterator; otherwise, it has linear complexity and so is potentially expensive. @@ -268,7 +268,7 @@ auto cbegin(const Container& cont) ### Parameters *`cont`*\ -A container or initializer_list. +A container or `initializer_list`. ### Return Value @@ -276,7 +276,7 @@ A constant `cont.begin()`. ### Remarks -This function works with all C++ Standard Library containers and with [initializer_list](../standard-library/initializer-list-class.md). +This function works with all C++ Standard Library containers and with [`initializer_list`](../standard-library/initializer-list-class.md). You can use this member function in place of the `begin()` template function to guarantee that the return value is `const_iterator`. Typically, it's used with the [`auto`](../cpp/auto-cpp.md) type deduction keyword, as shown in the following example. In the example, consider `Container` to be a modifiable (non- **`const`**) container or `initializer_list` of any kind that supports `begin()` and `cbegin()`. @@ -329,7 +329,7 @@ Get a reverse read-only iterator to the elements of the container, starting at t template constexpr auto crbegin(const C& c) -> decltype(std::rbegin(c)); ``` -## Parameters +### Parameters *`C`*\ The type of the container. @@ -372,7 +372,7 @@ Get the sentinel at the end of a read-only reversed sequence of elements. template constexpr auto crend(const C& c) -> decltype(std::rend(c)); ``` -## Parameters +### Parameters *`C`*\ The type of the container. @@ -548,7 +548,7 @@ template constexpr bool empty(const T (&array)[N]) noexcept; template constexpr bool empty(initializer_list il) noexcept; ``` -## Parameters +### Parameters *`C`*\ The type of the container. @@ -700,7 +700,7 @@ After the front insertions, the list L is: ( 200 100 -1 0 1 2 3 4 5 6 7 8 ). ``` -## inserter +## `inserter` A helper template function that lets you use `inserter(Cont, Where)` instead of `insert_iterator(Cont, Where)`. @@ -717,12 +717,12 @@ inserter( *`Cont`*\ The container to which new elements are to be added. -*Where*\ +*`Where`*\ An iterator locating the point of insertion. ### Remarks -The template function returns [insert_iterator](../standard-library/insert-iterator-class.md#insert_iterator)`(Cont, Where)`. +The template function returns [`insert_iterator`](../standard-library/insert-iterator-class.md#insert_iterator)`(Cont, Where)`. ### Example From d19d436ed702fb0fc998ac0a5f32294e8799a197 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 9 Dec 2022 15:08:45 -0800 Subject: [PATCH 05/31] draft --- docs/standard-library/iterator-concepts.md | 418 +++++++++++++++++++++ docs/standard-library/iterator.md | 18 +- docs/standard-library/range-adaptors.md | 6 +- docs/standard-library/range-concepts.md | 65 ++-- docs/standard-library/range-functions.md | 2 +- docs/standard-library/range-iterators.md | 151 -------- docs/standard-library/ranges.md | 24 +- docs/standard-library/toc.yml | 4 +- docs/standard-library/view-classes.md | 23 +- 9 files changed, 504 insertions(+), 207 deletions(-) create mode 100644 docs/standard-library/iterator-concepts.md delete mode 100644 docs/standard-library/range-iterators.md diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md new file mode 100644 index 00000000000..951728ae70d --- /dev/null +++ b/docs/standard-library/iterator-concepts.md @@ -0,0 +1,418 @@ +--- +description: "Learn more about iterator concepts." +title: " concepts" +ms.date: 12/05/2022 +f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_range", "ranges/std::ranges::borrowed_range", "ranges/std::ranges::common_range", "ranges/std::ranges::contiguous_range", "ranges/std::ranges::forward_range", "ranges/std::ranges::input_range", "ranges/std::ranges::output_range", "ranges/std::ranges::random_access_range", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_range", "ranges/std::ranges::view", "ranges/std::ranges::viewable_range"] +helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_range", "std::ranges [C++], ranges::borrowed_range", "std::ranges [C++], ranges::common_range", "std::ranges [C++], ranges::contiguous_range", "std::ranges [C++], ranges::forward_range", "std::ranges [C++], ranges::input_range", "std::ranges [C++], ranges::output_range", "std::ranges [C++], ranges::random_access_range", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_range", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_range"] +--- +# `` concepts + +Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. + +Consider the following example, which defines a concept to prevent instantiating a template with a type that doesn't support division: + +```cpp +// requires /std:c++20 or later +#include + +// Definition of dividable concept which requires +// that arguments a & b of type T support division +template +concept dividable = requires (T a, T b) +{ + a / b; +}; + +// Apply the concept to a template. +// The template will only be instantiated if argument T supports division. +// This prevents the template from being instantiated with types that don't support division. +// This could have been applied to the parameter of a template function, but because +// most of the concepts in the library are applied to classes, this form is demonstrated. +template requires dividable +class DivideEmUp +{ +public: + T Divide(T x, T y) + { + return x / y; + } +}; + +int main() +{ + DivideEmUp dividerOfInts; + std::cout << dividerOfInts.Divide(6, 3); // outputs 2 + // The following line will not compile because the template can't be instantiated + // with char* because char* can be divided + DivideEmUp dividerOfCharPtrs; // compiler error: cannot deduce template arguments +} +``` + +When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 version 17.4p4 or later, the error that concept `dividable` evaluated to false will point directly to the expression requirement `(a / b)` that failed. + +Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. + +There are six categories of ranges. They are directly related to the categories of ranges listed in [`](iterator.md#remarks). + +In order of increasing power, the categories are: + +| Range concept | Description | +|--|--| +| [`output_range`](#output_range) | Specifies a range that you can write to. JTW It supports [output_iterator](iterators.md# JTW) Repeat this pattern for the entries below. | +| [`input_range`](#input_range) | Specifies a range that you can read from at least once. | +| [`forward_range`](#forward_range) | Specifies a range that can read (and possibly write) multiple times. | +| [`bidirectional_range`](#bidirectional_range) | Specifies a range that can read and write both forwards and backwards. | +| [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | +| [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory and can be accessed using pointer arithmetic. | + +In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept for a category generally meets the requirements of all concepts in the categories that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. + +Other range concepts include: + +| Range concept | Description | +|--|--| +| [`range`](#range)C++20 | Specifies a type that provides an iterator and a sentinel. | +| [`borrowed_range`](#borrowed_range)C++20 | Specifies that the lifetime of the range's iterators aren't tied to the range's lifetime. | +| [`common_range`](#common_range)C++20 | Specifies that the type of the range's iterator and the type of the range's sentinel are the same. | +| [`Simple_View`](#simple_view)C++20 | Not an official concept defined as part of the standard library, but used as a helper concept on some interfaces. | +| [`sized_range`](#sized_range)C++20 | Specifies a range that can provide the number of elements in a range efficiently. | +| [`view`](#view)C++20 | Specifies a type that has efficient (constant time) move construction, assignment, and destruction. | +| [`viewable_range`](#viewable_range)C++20 | Specifies a type that either is a view or can be converted to one. | + +For a list of JTW + +## `bidirectional_range` + +A `bidirectional_range` supports reading and writing the range forwards and backwards. + +```cpp +template +concept bidirectional_range = + forward_range && bidirectional_iterator>; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `bidirectional_range`. + +### Remarks + +A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. + +Some examples of a `bidirectional_range` are `std::set`, `std::vector`, and `std::list`. + +## `borrowed_range` + +A type models `borrowed_range` if the validity of iterators you get from the object can outlive the lifetime of the object. That is, the iterators for a range can be used even when the range no longer exists. + +```cpp +template +concept borrowed_range = + range && + (is_lvalue_reference_v || enable_borrowed_range>); +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `borrowed_range`. + +## `common_range` + +The type of the iterator for a `common_range` is the same as the type of the sentinel. That is, `begin()` and `end()` return the same type. + +```cpp +template +concept common_range = + ranges::range && std::same_as, ranges::sentinel_t>; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `common_range`. + +### Remarks + +Getting the type from `std::ranges::begin()` and `std::ranges::end()` is important for algorithms that calculate the distance between two iterators, and for algorithms that accept ranges denoted by iterator pairs. + +The standard containers (for example, `vector`) meet the requirements of `common_range`. + +## `contiguous_range` + +The elements of a `contiguous_range` are stored sequentially in memory and can be accessed using pointer arithmetic. For example, an array is a `contiguous_range`. + +```cpp +template +concept contiguous_range = + random_access_range && contiguous_iterator> && + requires(T& t) {{ ranges::data(t) } -> same_as>>;}; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `contiguous_range`. + +### Remarks + +A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. + +Some examples of a `contiguous_range` are `std::array`, `std::vector`, and `std::string`. + +### Example: `contiguous_range` + +The following example shows using pointer arithmetic to access a `contiguous_range`: + +```cpp +// requires /std:c++20 or later +#include +#include +#include + +int main() +{ + // Show that vector is a contiguous_range + std::vector v = {0,1,2,3,4,5}; + std::cout << std::boolalpha << std::ranges::contiguous_range << '\n'; // outputs true + + // Show that pointer arithmetic can be used to access the elements of a contiguous_range + auto ptr = v.data(); + ptr += 2; + std::cout << *ptr << '\n'; // outputs 2 +} +``` + +```output +true +2 +``` + +## `forward_range` + +A `forward_range` supports reading (and possibly writing) the range multiple times. + +```cpp +template +concept forward_range = input_range && forward_iterator>; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `forward_range`. + +### Remarks + +A `forward_iterator` can iterate over a range multiple times. + +## `input_range` + +An `input_range` is a range that can be read from at least once. + +```cpp +template +concept input_range = range && input_iterator>; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's an `input_range`. + +### Remarks + +When a type meets the requirements of `input_range`: + +- The `ranges::begin()` function returns an `input_iterator`. Calling `begin()` more than once on an `input_range` results in undefined behavior. +- You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_range` isn't multi-pass. Incrementing an iterator invalidates any copies. +- It can be used with `ranges::for_each`. +- It *at least* has an `input_iterator`. It may have a more capable iterator type. + +## `output_range` + +An `output_range` is a range that you can write to. + +```cpp +template +concept output_range = range && output_iterator, T>; +``` + +### Parameters + +*`R`*\ +The type of the range. + +*`T`*\ +The type of the data to write to the range. + +### Remarks + +The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. + +## `random_access_range` + +A `random_access_range` can read or write a range by index. + +```cpp +template +concept random_access_range = +bidirectional_range && random_access_iterator>; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `sized_range`. + +### Remarks + +A `random_access_range` is the most flexible iterator. It has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is also sortable. + +Some examples of a `random_access_range` are `std::vector`, `std::array`, and `std::deque`. + +## `range` + +Defines the requirements a type must meet to be a `range`. A `range` provides an iterator and a sentinel, so that you can iterate over its elements. + +```cpp +template +concept range = requires(T& rg) +{ + ranges::begin(rg); + ranges::end(rg); +}; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `range`. + +### Remarks + +The requirements of a `range` are: +- It can be iterated using `std::ranges::begin()` and `std::ranges::end()` +- `ranges::begin()` and `ranges::end()` run in amortized constant time and don't modify the `range`. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. +- `[ranges::begin(), ranges::end())` denotes a valid range. + +## `Simple_View` + +A `Simple_View` is an exposition-only concept used on some `ranges` interfaces. It isn't defined in the library. It's only used in the specification to help describe the behavior of some range adaptors. + +```cpp +template + concept Simple_View = // exposition only + ranges::view && ranges::range && + std::same_as, std::ranges::iterator_t> && + std::same_as, std::ranges::sentinel_t>; +``` + +### Parameters + +*`V`*\ +The type to test to see if it's a `Simple_View`. + +### Remarks + +A view `V` is a [`Simple_View`](#simple_view) if all of the following are true: +- `V` is a view +- `const V` is a range +- Both `v` and `const V` have the same iterator and sentinel types. + +## `sized_range` + +A `sized_range` provides the number of elements in the range in amortized constant time. + +```cpp +template + concept sized_range = range && + requires(T& t) { ranges::size(t); }; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a `sized_range`. + +### Remarks + +The requirements of a `sized_range` are that calling `ranges::size` on it: + +- Doesn't modify the range. +- Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. + +Some examples of a `sized_range` are `std::list` and `std::vector`. + +### Example: `sized_range` + +The following example shows that a `vector` of `int` is a `sized_range`: + +```cpp +// requires /std:c++20 or later +#include +#include +#include + +int main() +{ + std::cout << std::boolalpha << std::ranges::sized_range> << '\n'; // outputs "true" +} +``` + +## `view` + +A `view` has constant time move construction, assignment, and destruction operations--regardless of the number of elements it has. Views don't need to be copy constructible or copy assignable, but if they are, those operations must also run in constant time. + +Because of the constant time requirement, you can efficiently compose views. For example, given a vector of `int` called `input`, a function that determines if a number is divisible by three, and a function that squares a number, the statement `auto x = input | std::views::filter(divisible_by_three) | std::views::transform(square);` efficiently produces a view that contains the squares of the numbers in input that are divisible by three. Connecting views together with `|` is referred to as composing the views. If a type satisfies the [`view`](range-concepts.md#view) concept, then it can be composed efficiently. + +```cpp +template +concept view = ranges::range && std::movable && ranges::enable_view; +``` + +### Parameters + +*`T`*\ +The type to test to see if it's a view. + +### Remarks + +The essential requirement that makes a view composable is that it's cheap to move/copy. This is because the view is moved/copied when it's composed with another view. It must be a movable range. + +`ranges::enable_view` is a trait used to claim conformance to the semantic requirements of the `view` concept. A type can opt in by: +- publicly and unambiguously deriving from a specialization of `ranges::view_interface` +- publicly and unambiguously deriving from the empty class `ranges::view_base`, or +- specializing `ranges::enable_view` to `true` + +Option 1 is generally preferred because `view_interface` also provides default implementation that saves some boilerplate code you have to write. + +Failing that, option 2 is a little simpler than option 3. + +The advantage of option 3 is that it's possible without changing the definition of the type. + +## `viewable_range` + +A `viewable_range` is a type that either is a view or can be converted to one. + +```cpp +template + concept viewable_range = + range && (borrowed_range || view>); +``` + +### Parameters + +*`T`*\ +The type to test to see if it either is a view or can be converted to one. + +### Remarks + +Use `std::ranges::views::all()` to convert a range to a view. + +## See also + +[``](ranges.md)\ +[Range adaptors](range-adaptors.md)\ +[View classes](view-classes.md) \ No newline at end of file diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index b1e0fd13979..22e875a40ec 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -19,7 +19,19 @@ There are three classes of insert iterator adaptors: front, back, and general. T ## Remarks -Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range specified by a type of iterator. Any data structure that satisfies the requirements of the iterator can be operated upon by the algorithm. There are five types or categories of iterators: +Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range specified by a type of iterator. Any data structure that satisfies the requirements of the iterator can be operated upon by the algorithm. In C++20, there are x categories of iterators: + +JTW fix this table up + +| Kind | Direction | Read/Write| Example types| +|---|---|---|---| +| Output | Forward | Write | `ostream`, `inserter` | +| Input | Forward | Read | `istream`| +| Forward | Forward | Read/Write | | +| Bidirectional | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | +| Random access | Any order | Read/Write | `vector`, `deque`, `string`, and `array`. | + +Until In C++17, there are five types or categories of iterators: | Kind | Direction | Read/Write| Example types| |---|---|---|---| @@ -74,6 +86,10 @@ Visual Studio has added extensions to C++ Standard Library iterators to support |[`operator+`](../standard-library/iterator-operators.md#op_add)|Adds an offset to an iterator and returns the new `reverse_iterator` addressing the inserted element at the new offset position.| |[`operator-`](../standard-library/iterator-operators.md#operator-)|Subtracts one iterator from another and returns the difference.| +### Concepts + + + ### Classes |Name|Description| diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 7e3d1f277ae..3e0051157ce 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -7,7 +7,7 @@ helpviewer_keywords: ["std::ranges [C++], all", "std::ranges [C++], all_t", "std --- # Range adaptors -Range adaptors create a *view* (one of the [View classes](view-classes.md) in the `std::views` namespace) from a range. We recommend that you use an adaptor in `std::ranges::views` instead of creating the view types directly. The adaptors are the intended way to access views. They're easier to use, and in some cases more efficient, than creating instances of the view types directly. +Range adaptors create a *view* (one of the [View classes](view-classes.md) in the `std::views` namespace) from a range. We recommend that you use an adaptor to create views instead of creating the view types directly. The adaptors are the intended way to access views. They're easier to use, and in some cases more efficient, than creating instances of the view types directly. A view is a lightweight object that refers to elements from a range. A view can: @@ -48,9 +48,9 @@ The first range adaptor, [`filter`](filter-view-class.md), provides a view that When a range adaptor produces a view, it doesn't incur the cost of transforming every element in the range to produce that view. The cost to process an element in the view is paid only when you access that element. -Creating a view only prepares to do work in the future. In the previous example, creating the view doesn't result in finding all the elements divisible by three. It also doesn't square the elements that it finds. That work happens only when you access an element in the view. +Creating a view is preparation to do work in the future. In the previous example, creating the view doesn't result in finding all the elements divisible by three or squaring those elements. Work happens only when you access an element in the view. -Elements of a view are usually the actual elements of the range that are used to create the view. The view usually doesn't own the elements ([`owning_view`](owning-view-class.md) is an exception); it just refers to them. Changing an element changes that element in the range that the view was created from. The following example shows this behavior: +Elements of a view are usually the actual elements of the range used to create the view. The view usually doesn't own the elements; it just refers to them. Although ([`owning_view`](owning-view-class.md) is an exception. Changing an element changes that element in the range that the view was created from. The following example shows this behavior: ```cpp #include diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index 5df829a4c64..1c4f2612ea0 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -1,13 +1,13 @@ --- -description: "Learn more about range concepts and range iterator concepts." -title: "Concepts for ranges and range iterators" -ms.date: 11/02/2022 +description: "Learn more about range concepts." +title: " concepts" +ms.date: 12/05/2022 f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_range", "ranges/std::ranges::borrowed_range", "ranges/std::ranges::common_range", "ranges/std::ranges::contiguous_range", "ranges/std::ranges::forward_range", "ranges/std::ranges::input_range", "ranges/std::ranges::output_range", "ranges/std::ranges::random_access_range", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_range", "ranges/std::ranges::view", "ranges/std::ranges::viewable_range"] helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_range", "std::ranges [C++], ranges::borrowed_range", "std::ranges [C++], ranges::common_range", "std::ranges [C++], ranges::contiguous_range", "std::ranges [C++], ranges::forward_range", "std::ranges [C++], ranges::input_range", "std::ranges [C++], ranges::output_range", "std::ranges [C++], ranges::random_access_range", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_range", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_range"] --- # `` concepts -Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, convey template argument requirements in a readable form, and provide more succinct template related compiler errors. +Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. Consider the following example, which defines a concept to prevent instantiating a template with a type that doesn't support division: @@ -50,27 +50,40 @@ int main() When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 version 17.4p4 or later, the error that concept `dividable` evaluated to false will point directly to the expression requirement `(a / b)` that failed. -The following concepts are defined in `std::ranges` and are declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. +Range concepts are defined in the `std::ranges` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. + +There are six categories of ranges. They are related to the categories of iterators listed in [` concepts](iterator-concepts.md). + +In order of increasing capability, the categories are: + +| Range concept | Description | +|--|--| +| [`output_range`](#output_range) | Specifies a range that you can write to. JTW It supports [output_iterator](iterators.md# JTW) Repeat this pattern for the entries below. | +| [`input_range`](#input_range) | Specifies a range that you can read from at least once. | +| [`forward_range`](#forward_range) | Specifies a range that can read (and possibly write) multiple times. | +| [`bidirectional_range`](#bidirectional_range) | Specifies a range that can read and write both forwards and backwards. | +| [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | +| [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory and can be accessed using pointer arithmetic. | + +In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept for a category generally meets the requirements of all concepts in the categories that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. + +Other range concepts include: | Range concept | Description | |--|--| -| [`range`](#range)C++20 | A type that provides an iterator and a sentinel. | -| [`bidirectional_range`](#bidirectional_range)C++20 | Supports reading and writing forwards and backwards. | -| [`borrowed_range`](#borrowed_range)C++20 | The lifetime of the type's iterators aren't tied to the object's lifetime. | -| [`common_range`](#common_range)C++20 | The type of the iterator and the type of the sentinel are the same. | -| [`contiguous_range`](#contiguous_range)C++20 | The elements are sequential in memory and can be accessed by using pointer arithmetic. | -| [`forward_range`](#forward_range)C++20 | Supports reading (and possibly writing) a range multiple times. | -| [`input_range`](#input_range)C++20 | Supports reading at least once. | -| [`output_range`](#output_range)C++20 | Supports writing. | -| [`random_access_range`](#random_access_range)C++20 | Supports reading and writing by index. | +| [`range`](#range)C++20 | Specifies a type that provides an iterator and a sentinel. | +| [`borrowed_range`](#borrowed_range)C++20 | Specifies that the lifetime of the range's iterators aren't tied to the range's lifetime. | +| [`common_range`](#common_range)C++20 | Specifies that the type of the range's iterator and the type of the range's sentinel are the same. | | [`Simple_View`](#simple_view)C++20 | Not an official concept defined as part of the standard library, but used as a helper concept on some interfaces. | -| [`sized_range`](#sized_range)C++20 | Provides the number of elements in a range efficiently. | -| [`view`](#view)C++20 | Has efficient (constant time) move construction, assignment, and destruction. | -| [`viewable_range`](#viewable_range)C++20 | A type that either is a view or can be converted to one. | +| [`sized_range`](#sized_range)C++20 | Specifies a range that can provide the number of elements in a range efficiently. | +| [`view`](#view)C++20 | Specifies a type that has efficient (constant time) move construction, assignment, and destruction. | +| [`viewable_range`](#viewable_range)C++20 | Specifies a type that either is a view or can be converted to one. | + +For a list of JTW ## `bidirectional_range` -A `bidirectional_range` supports reading and writing forwards and backwards. +A `bidirectional_range` supports reading and writing the range forwards and backwards. ```cpp template @@ -178,7 +191,7 @@ true ## `forward_range` -A `forward_range` supports reading (and possibly writing) a `range` multiple times. +A `forward_range` supports reading (and possibly writing) the range multiple times. ```cpp template @@ -196,7 +209,7 @@ A `forward_iterator` can iterate over a range multiple times. ## `input_range` -An `input_range` is a `range` that can be read from at least once. +An `input_range` is a range that can be read from at least once. ```cpp template @@ -219,7 +232,7 @@ When a type meets the requirements of `input_range`: ## `output_range` -An `output_range` is a `range` that you can write to. +An `output_range` is a range that you can write to. ```cpp template @@ -232,15 +245,15 @@ concept output_range = range && output_iterator, T>; The type of the range. *`T`*\ -The type of the data to write to the `range`. +The type of the data to write to the range. ### Remarks -The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a `range` of type `R`. +The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. ## `random_access_range` -A `random_access_range` can read or write a `range` by index. +A `random_access_range` can read or write a range by index. ```cpp template @@ -327,7 +340,7 @@ The type to test to see if it's a `sized_range`. The requirements of a `sized_range` are that calling `ranges::size` on it: -- Doesn't modify the `range`. +- Doesn't modify the range. - Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. Some examples of a `sized_range` are `std::list` and `std::vector`. @@ -366,7 +379,7 @@ The type to test to see if it's a view. ### Remarks -The essential requirement that makes a view composable is that it's cheap to move/copy. This is because the view is moved/copied when it's composed with another view. It must be a movable `range`. +The essential requirement that makes a view composable is that it's cheap to move/copy. This is because the view is moved/copied when it's composed with another view. It must be a movable range. `ranges::enable_view` is a trait used to claim conformance to the semantic requirements of the `view` concept. A type can opt in by: - publicly and unambiguously deriving from a specialization of `ranges::view_interface` diff --git a/docs/standard-library/range-functions.md b/docs/standard-library/range-functions.md index feb651b9b45..b242415843f 100644 --- a/docs/standard-library/range-functions.md +++ b/docs/standard-library/range-functions.md @@ -130,7 +130,7 @@ Get a `const` pointer to the first element in the contiguous range. ```cpp template -constexpr std::add_pointer_t> cdata(T&& rg); +constexpr std::add_pointer_t> cdata(T&& rg); ``` ### Parameters diff --git a/docs/standard-library/range-iterators.md b/docs/standard-library/range-iterators.md deleted file mode 100644 index 05c2ddcad88..00000000000 --- a/docs/standard-library/range-iterators.md +++ /dev/null @@ -1,151 +0,0 @@ -JTW - stub topic to convert to range-iterators. - - ---- -description: "Learn more about range concepts and range iterator concepts." -title: "Concepts for ranges and range iterators" -ms.date: 09/22/2022 -f1_keywords: ["ranges/std::ranges::range"] -helpviewer_keywords: ["std::ranges [C++], range"] ---- -# Concepts for - -Concepts are are C++20 language feature used to constrain template parameters at compile time. They help prevent incorrect template instantiations, convey template argument requirements in a readable form, and provide more succinct template related compiler errors. - -Consider the following example, which defines a concept to prevent instantiating a template with types that can't be divided: - -```cpp -// requires /std:c++20 or later - -// Definition of the concept "dividable" that requires -// that arguments a & b can be divided -template -concept dividable = requires (T a, T b) -{ - a / b; -}; - -// Apply the concept to a template -// The template will only be instantiated if the argument T can do division -// This prevents the template from being instantiated with types that can't be divided -// This could have been applied to the parameter of a template function, but because -// most of the concepts in the library are applied to classes, this form is used -template requires dividable -class DivideEmUp -{ -public: - T Divide(T x, T y) - { - return x / y; - } -}; - -void main() -{ - DivideEmUp dividerOfInts; - std::cout << dividerOfInts.Divide(6, 3); // outputs: 2 - // The following line will not compile because the template can't be instantiated - // with char* because char* can be divided - DivideEmUp dividerOfCharPtrs; // compiler error: cannot deduce template arguments -} -``` - -The following concepts are defined in `std::ranges` and are declared in the `` header file. They are used in the declarations of [range adaptors](range-adaptors.md), [views](views.md), and so on. - -| **Range concept ** | **Description** | -|--|--| -| [`range`](#range)C++20 | A `range` is a type that can be iterated. | -| [`borrowed_range`](#borrowed_range)C++20 | The validity of the iterators for a `borrowed_range` are not tied to the object's lifetime. | -| [`sized_range`](#sized_range)C++20 | A `range` that can provide the number of its elements in amortized constant time via `ranges::size` | - -## `borrowed_range` - -A type models `borrowed_range` if the validity of iterators you get from the object can outlive the lifetime of the object. - -```cpp -template -concept borrowed_range = - range && - (is_lvalue_reference_v || enable_borrowed_range>); -``` - -### Parameters - -*`T`*\ -The type to test to see if it is a `borrowed_range`. - -## `range` - -Defines the requirements a type must meet to be a `range`. A `range` provides an iterator and a sentinel for iterating over the elements in the `range`. - -```cpp -template -concept range = requires(T& rg) -{ - ranges::begin(rg); - ranges::end(rg); -}; -``` - -### Parameters - -*`T`*\ -The type to test to see if it is a `range`. - -*`rg`*\ -An instance of `R` to test. - -### Remarks - -The requirements of a `range` are: -- it can be iterated using `std::ranges::begin()` and `std::ranges::end()` -- `ranges::begin(rg)` and `ranges::end(rg)` run in amortized constant time and don't modify the `range`. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. -- \[`ranges::begin(rg)`, `ranges::end(rg)`) denotes a valid range. - - -## `sized_range` - -A `sized_range` can provide the number of its elements in amortized constant time via `ranges::size`. - -```cpp -template - concept sized_range = range && - requires(T& t) { ranges::size(t); }; -``` - -### Parameters - -*`T`*\ -The type to test to see if it is a `sized_range`. - -*`t`*\ -An instance of `T` to test. - -### Remarks - -The requirements of a `sized_range` are that calling `ranges::size` on it: -- Doesn't modify the `range`. -- Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. - -### Example `sized_range` - -The following example demonstrates that a vector of ints satisfies the requirements of a `sized_range`: - -```cpp -// requires /std:c++20 or later -#include -#include -#include - -int main() -{ - std::cout << boolalpha << std::ranges::sized_range> << '\n'; // outputs: true -} -``` - - -## See also - -[``](ranges.md)\ -[Range adaptors](range-adaptors.md)\ -[View classes](view-classes.md) \ No newline at end of file diff --git a/docs/standard-library/ranges.md b/docs/standard-library/ranges.md index 9e116824d39..d101e222e60 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -1,14 +1,14 @@ --- title: "" description: "Get an overview of the Standard Template Library (STL) ranges." -ms.date: 11/02/2022 +ms.date: 12/06/2022 f1_keywords: [""] helpviewer_keywords: ["ranges"] --- # `` -At a high level, a *range* is something that you can iterate over. The containers, such as `vector` and `list`, in the C++ Standard Library are ranges. A range abstracts iterators in a way that simplifies and amplifies your ability to use the Standard Template Library (STL). +At a high level, a *range* is something that you can iterate over. A range is represented by an iterator that marks the beginning of the range, and a sentinel that marks the end of the range. The sentinel may be the same type as the begin iterator, or it may be different. The containers, such as `vector` and `list`, in the C++ Standard Library are ranges. A range abstracts iterators in a way that simplifies and amplifies your ability to use the Standard Template Library (STL). STL algorithms usually take iterators that point to the portion of the collection that they should operate on. For example, consider how you sort a `vector` by using `std::sort()`. You pass two iterators that mark the beginning and end of the `vector`. That provides flexibility, but passing the iterators to the algorithm is extra work because you probably just want to sort the whole thing. @@ -31,10 +31,12 @@ std::transform(intermediate.begin(), intermediate.end(), std::back_inserter(outp With ranges, you can accomplish the same thing without needing the `intermediate` vector: ```cpp -// requires /std:c++latest -std::vector input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; +// requires /std:c++20 +std::vector input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; -auto output = input | std::views::filter([](const int n) {return n % 3 == 0; }) | std::views::transform([](const int n) {return n * n; }); +auto output = input + | std::views::filter([](const int n) {return n % 3 == 0; }) + | std::views::transform([](const int n) {return n * n; }); ``` Besides being easier to read, this code avoids the memory allocation that's required for the `intermediate` vector and its contents. It also allows you to compose two operations. @@ -43,9 +45,6 @@ In the preceding code, each element that's divisible by three is combined with a The result, `output`, is itself a kind of range called a *view*. -> [!NOTE] -> This example of ranges requires the [`/std:c++latest`](../build/reference/std-specify-language-standard-version.md) compiler option. Because post-release updates to `` in the C++20 standard are a work in progress, the features that require `std::views` aren't enabled yet under `/std:c++20`. - ## Views A view is a lightweight range. View operations--such as default construction, move construction/assignment, copy construction/assignment (if present), destruction, begin, and end--all happen in constant time regardless of the number of elements in the view. @@ -59,7 +58,7 @@ Views are composable, which is powerful. In the previous example, the view of ve The elements of a view are evaluated lazily. That is, the transformations that you apply to each element in a view aren't evaluated until you ask for the element. For example, if you run the following code in a debugger and put a breakpoint on the lines `auto divisible_by_three = ...` and `auto square = ...`, you'll see that you hit the `divisible_by_three` lambda breakpoint as each element in `input` is tested for divisibility by three. The `square` lambda breakpoint will be hit as the elements that are divisible by three are squared. ```cpp -// requires /std:c++latest +// requires /std:c++20 #include #include #include @@ -115,16 +114,17 @@ The range algorithms are almost identical to the corresponding iterator-pair alg | [`size`](range-functions.md#size)C++20 | Get the size of the range as an unsigned value. | | [`ssize`](range-functions.md#ssize)C++20 | Get the size of the range as a signed value. | -### Types of ranges +### Kinds of ranges -How you view the elements of a range depends on its underlying iterator type. The iterator types are specified as C++20 concepts. +How you can iterate over the elements of a range depends on its underlying iterator type. The iterator type a range requires is specified as a C++20 concept. In C++20, to say that concept *X* refines concept *Y* means that everything that satisfies concept *Y* also satisfies concept *X*. For example: *car*, *bus*, and *truck* all refine *vehicle*. -The range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the types of containers that they can be applied to: +Some of the range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the types of containers that they can be applied to. The order | Range concept | Description | Supported containers | |--|--|--| +| `std::ranges::output_range` | Can iterate forward. JTW | | `std::ranges::input_range` | Can iterate from beginning to end at least once. | `std::forward_list`
`std::unordered_map`
`std::unordered_multimap`
`std::unordered_set`
`std::unordered_multiset`
`basic_istream_view` | | `std::ranges::forward_range` | Can iterate from beginning to end more than once. | `std::forward_list`
`std::unordered_map`
`std::unordered_multimap`
`std::unordered_set`
`std::unordered_multiset` | | `std::ranges::bidirectional_range` | Can iterate forward and backward more than once. | `std::list`
`std::map`
`std::multimap`
`std::multiset`
`std::set`| diff --git a/docs/standard-library/toc.yml b/docs/standard-library/toc.yml index 04573b87c55..30544a93602 100644 --- a/docs/standard-library/toc.yml +++ b/docs/standard-library/toc.yml @@ -592,6 +592,8 @@ items: items: - name: href: iterator.md + - name: concepts + href: iterator-concepts.md - name: functions href: iterator-functions.md - name: operators @@ -930,8 +932,6 @@ items: href: range-concepts.md - name: functions href: range-functions.md - - name: iterators - href: range-iterators.md - name: view classes href: view-classes.md expanded: false diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index e5fe0ff24d4..4fdd0d059ba 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -1,7 +1,7 @@ --- description: "Learn more about view classes, which allow you to inexpensively refer to and transform ranges." title: "View classes" -ms.date: 11/04/2022 +ms.date: 12/06/2022 f1_keywords: ["RANGES/std::ranges::views", "RANGES/std::views"] helpviewer_keywords: ["RANGES/VIEWS/std", "VIEWS/std"] --- @@ -31,8 +31,9 @@ int main() auto divisible_by_three = [](const int n) {return n % 3 == 0;}; auto square = [](const int n) {return n * n;}; - auto x = input | std::views::filter(divisible_by_three) - | std::views::transform(square); + auto x = input + | std::views::filter(divisible_by_three) + | std::views::transform(square); for (int i : x) { @@ -47,7 +48,7 @@ int main() Using a view after the range that it's based on is modified can lead to undefined behavior. For example, a [`reverse_view`](reverse-view-class.md) based on a vector shouldn't be reused if you add or remove elements from the underlying vector. Modifying the underlying vector invalidates the container's `end` iterator--including the copy of the iterator that the view might have made. -Because views are cheap to create, you should generally re-create a view if you modify the underlying range. The following example demonstrates this. It also shows how to store a view pipeline in a variable so that you can reuse it. +Because views are cheap to create, you should generally re-create a view if you modify the underlying range. The following example demonstrates how to store a view pipeline in a variable so that you can reuse it. ```cpp // requires / std:c++20 or later @@ -122,7 +123,7 @@ The following view classes are defined in the `std::ranges` namespace. | [`transform_view`](transform-view-class.md)C++20 | A view of an underlying sequence after a transformation function is applied to each element. | | [`values_view`](values-view-class.md)C++20 | A view over the second index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of the `int` elements from each tuple. | -Many of these classes have corresponding [range adaptors](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adaptors in `std::views` to creating view classes directly. The range adaptors are the intended access points, are easier to use, and in some cases are more efficient. +Many of these classes have corresponding [range adaptors](range-adaptors.md) in the `std:views` namespace that creates instances of them. Prefer the adaptors in `std::views` to creating view classes directly. The range adaptors are the intended access points, are easier to use, and in some cases are more efficient. ## View classes characteristics @@ -130,7 +131,7 @@ Each view class topic has a **Characteristics** section after the syntax section * **Range adaptor**: A link to the range adaptor that creates the view. You typically use a range adaptor to create a view rather than create a view class directly, so it's listed here for convenience. * **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See the following table for the hierarchy of iterators. -* **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a `bidirectional_iterator` category, even if the underlying range has a `random_access_iterator` category. +* **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a `bidirectional_iterator`, even if the underlying range has a `random_access_iterator`. * **Element type**: The type of the elements that the view's iterator returns. * **Sized**: Whether the view can return the number of elements that it refers to. Not all views can. * **Common range**: Specifies whether the view is a [`common_range`](range-concepts.md#common_range), which means that the begin iterator and sentinel types are the same. Common ranges are useful for pre-range code that works with iterator pairs. An example is iterator pair constructors for a sequence container, like `vector(ranges::begin(x), ranges::end(x))`. @@ -153,14 +154,14 @@ That hierarchy, in increasing order of capability, is: |--|--| | [`output_range`](range-concepts.md#output_range) | Write-only, only moves forward; single-pass. | | [`input_range`](range-concepts.md#input_range) | Only moves forward; single-pass. | -| `forward_range` | Only moves forward; multi-pass. | +| [`forward_range`](range-concepts.md#forward_range) | Only moves forward; multi-pass. | | [`bidirectional_range`](range-concepts.md#bidirectional_range) | Can move forward and backward; multi-pass. | -| `random_access_range` | Can access the collection with an index; multi-pass. | -| `contiguous_range` | Can access the collection with an index, and elements are stored contiguously in memory. | +| [`random_access_range`](range-concepts.md#random_access_range) | Can access the collection with an index; multi-pass. | +| [`contiguous_range`](range-concepts.md#contiguous_range) | Can access the collection with an index, and elements are stored contiguously in memory. | -An iterator also has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) can be used with a [`forward_range`](range-concepts.md#forward_range) iterator, but not vice versa. +An iterator has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) has the capabilities of [`forward_range`](range-concepts.md#forward_range), but not vice versa. -The statement "requires [`input_range`](range-concepts.md#input_range) or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, [`random_access_range`](range-concepts.md#random_access_range), or `contiguous_range` iterator, because any of those categories is as capable as `input_range`. +The statement "requires `input_range` or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because they are all as capable as `input_range`. ## See also From 1b9f5d9530621ba5aefac776b0f02b142311c2a4 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 9 Dec 2022 18:35:56 -0800 Subject: [PATCH 06/31] draft --- docs/standard-library/iterator-concepts.md | 219 +++++++++------------ docs/standard-library/range-concepts.md | 4 +- 2 files changed, 97 insertions(+), 126 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index 951728ae70d..4836d7651e8 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -2,8 +2,8 @@ description: "Learn more about iterator concepts." title: " concepts" ms.date: 12/05/2022 -f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_range", "ranges/std::ranges::borrowed_range", "ranges/std::ranges::common_range", "ranges/std::ranges::contiguous_range", "ranges/std::ranges::forward_range", "ranges/std::ranges::input_range", "ranges/std::ranges::output_range", "ranges/std::ranges::random_access_range", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_range", "ranges/std::ranges::view", "ranges/std::ranges::viewable_range"] -helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_range", "std::ranges [C++], ranges::borrowed_range", "std::ranges [C++], ranges::common_range", "std::ranges [C++], ranges::contiguous_range", "std::ranges [C++], ranges::forward_range", "std::ranges [C++], ranges::input_range", "std::ranges [C++], ranges::output_range", "std::ranges [C++], ranges::random_access_range", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_range", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_range"] +f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_iterator", "ranges/std::ranges::borrowed_iterator", "ranges/std::ranges::common_iterator", "ranges/std::ranges::contiguous_iterator", "ranges/std::ranges::forward_iterator", "ranges/std::ranges::input_iterator", "ranges/std::ranges::output_iterator", "ranges/std::ranges::random_access_iterator", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_iterator", "ranges/std::ranges::view", "ranges/std::ranges::viewable_iterator"] +helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_iterator", "std::ranges [C++], ranges::borrowed_iterator", "std::ranges [C++], ranges::common_iterator", "std::ranges [C++], ranges::contiguous_iterator", "std::ranges [C++], ranges::forward_iterator", "std::ranges [C++], ranges::input_iterator", "std::ranges [C++], ranges::output_iterator", "std::ranges [C++], ranges::random_access_iterator", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_iterator", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_iterator"] --- # `` concepts @@ -52,118 +52,87 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of ranges. They are directly related to the categories of ranges listed in [`](iterator.md#remarks). +There are six categories of iterators. They are directly related to the categories of ranges listed in [`](ranges.md#remarks). In order of increasing power, the categories are: -| Range concept | Description | +| Iterator concept | Description | |--|--| -| [`output_range`](#output_range) | Specifies a range that you can write to. JTW It supports [output_iterator](iterators.md# JTW) Repeat this pattern for the entries below. | -| [`input_range`](#input_range) | Specifies a range that you can read from at least once. | -| [`forward_range`](#forward_range) | Specifies a range that can read (and possibly write) multiple times. | -| [`bidirectional_range`](#bidirectional_range) | Specifies a range that can read and write both forwards and backwards. | -| [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | -| [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory and can be accessed using pointer arithmetic. | +| [`input_or_output_iterator`](#input_or_output_iterator) | The basis of the iterator concept taxonomy. | +| [`output_iterator`](#output_iterator) | Specifies an iterator that you can write to. JTW It supports [output_iterator](iterators.md# JTW) Repeat this pattern for the entries below. | +| [`input_iterator`](#input_iterator) | Specifies an iterator that you can read from at least once. | +DONE | [`forward_iterator`](#forward_iterator) | Specifies an iterator that can read (and possibly write) multiple times. | +DONE | [`bidirectional_iterator`](#bidirectional_iterator) | Specifies an iterator that can read and write both forwards and backwards. | +| [`random_access_iterator`](#random_access_iterator) | Specifies an iterator that can read and write by index. | +DONE| [`contiguous_iterator`](#contiguous_iterator) | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | -In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept for a category generally meets the requirements of all concepts in the categories that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. +In the preceding table, concepts are listed in order of increasing capability. An iterator that meets the requirements of a concept for a category generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. However, an exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. -Other range concepts include: +Other iterator concepts include: | Range concept | Description | |--|--| -| [`range`](#range)C++20 | Specifies a type that provides an iterator and a sentinel. | -| [`borrowed_range`](#borrowed_range)C++20 | Specifies that the lifetime of the range's iterators aren't tied to the range's lifetime. | -| [`common_range`](#common_range)C++20 | Specifies that the type of the range's iterator and the type of the range's sentinel are the same. | -| [`Simple_View`](#simple_view)C++20 | Not an official concept defined as part of the standard library, but used as a helper concept on some interfaces. | -| [`sized_range`](#sized_range)C++20 | Specifies a range that can provide the number of elements in a range efficiently. | -| [`view`](#view)C++20 | Specifies a type that has efficient (constant time) move construction, assignment, and destruction. | -| [`viewable_range`](#viewable_range)C++20 | Specifies a type that either is a view or can be converted to one. | - -For a list of JTW +| [`sentinel_for`](#sentinel_for)C++20 | JTW | +| [``sized_sentinel_for``](#sized_sentinel_for)C++20 | JTW | -## `bidirectional_range` +## `bidirectional_iterator` -A `bidirectional_range` supports reading and writing the range forwards and backwards. +A `bidirectional_iterator` supports reading and writing forwards and backwards. ```cpp -template -concept bidirectional_range = - forward_range && bidirectional_iterator>; +template +concept bidirectional_iterator = + forward_iterator && + derived_from && + requires(I i) { + {--i} -> same_as; + {i--} -> same_as; +}; ``` ### Parameters -*`T`*\ -The type to test to see if it's a `bidirectional_range`. +*`I`*\ +The iterator to test to see if it's a `bidirectional_iterator`. ### Remarks A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. -Some examples of a `bidirectional_range` are `std::set`, `std::vector`, and `std::list`. +Some examples of containers that can be used with a `bidirectional_iterator` are `std::set`, `std::vector`, and `std::list`. -## `borrowed_range` +## `contiguous_iterator` -A type models `borrowed_range` if the validity of iterators you get from the object can outlive the lifetime of the object. That is, the iterators for a range can be used even when the range no longer exists. +Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. ```cpp -template -concept borrowed_range = - range && - (is_lvalue_reference_v || enable_borrowed_range>); +template + concept contiguous_iterator = + random_access_iterator && + derived_from && + is_lvalue_reference_v> && + same_as, remove_cvref_t>> && + requires(const I& i) { + { to_address(i) } -> same_as>>; + }; ``` ### Parameters -*`T`*\ -The type to test to see if it's a `borrowed_range`. - -## `common_range` +*`I`*\ +The type to test to see if it's a `contiguous_iterator`. -The type of the iterator for a `common_range` is the same as the type of the sentinel. That is, `begin()` and `end()` return the same type. - -```cpp -template -concept common_range = - ranges::range && std::same_as, ranges::sentinel_t>; -``` - -### Parameters - -*`T`*\ -The type to test to see if it's a `common_range`. +The elements of a `contiguous_iterator` are stored sequentially in memory and can be accessed using pointer arithmetic. For example, an array can be traversed using a `contiguous_iterator`. ### Remarks -Getting the type from `std::ranges::begin()` and `std::ranges::end()` is important for algorithms that calculate the distance between two iterators, and for algorithms that accept ranges denoted by iterator pairs. +A `contiguous_iterator` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. -The standard containers (for example, `vector`) meet the requirements of `common_range`. +Some examples of a `contiguous_iterator` are `std::array`, `std::vector`, and `std::string`. -## `contiguous_range` +### Example: `contiguous_iterator` -The elements of a `contiguous_range` are stored sequentially in memory and can be accessed using pointer arithmetic. For example, an array is a `contiguous_range`. - -```cpp -template -concept contiguous_range = - random_access_range && contiguous_iterator> && - requires(T& t) {{ ranges::data(t) } -> same_as>>;}; -``` - -### Parameters - -*`T`*\ -The type to test to see if it's a `contiguous_range`. - -### Remarks - -A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. - -Some examples of a `contiguous_range` are `std::array`, `std::vector`, and `std::string`. - -### Example: `contiguous_range` - -The following example shows using pointer arithmetic to access a `contiguous_range`: +The following example shows using pointer arithmetic to access a `contiguous_iterator`: ```cpp // requires /std:c++20 or later @@ -173,11 +142,11 @@ The following example shows using pointer arithmetic to access a `contiguous_ran int main() { - // Show that vector is a contiguous_range + // Show that vector is a contiguous_iterator std::vector v = {0,1,2,3,4,5}; - std::cout << std::boolalpha << std::ranges::contiguous_range << '\n'; // outputs true + std::cout << std::boolalpha << std::ranges::contiguous_iterator << '\n'; // outputs true - // Show that pointer arithmetic can be used to access the elements of a contiguous_range + // Show that pointer arithmetic can be used to access the elements of a contiguous_iterator auto ptr = v.data(); ptr += 2; std::cout << *ptr << '\n'; // outputs 2 @@ -189,54 +158,58 @@ true 2 ``` -## `forward_range` +## `forward_iterator` -A `forward_range` supports reading (and possibly writing) the range multiple times. +Has the capabilities of an `input_iterator` and an `output_iterator`, but can read and write the same element multiple times. ```cpp -template -concept forward_range = input_range && forward_iterator>; +template + concept forward_iterator = + input_iterator && + derived_from && + incrementable && + sentinel_for; ``` ### Parameters -*`T`*\ -The type to test to see if it's a `forward_range`. +*`I`*\ +The iterator to test to see if it's a `forward_iterator`. -### Remarks +## `input_iterator` -A `forward_iterator` can iterate over a range multiple times. - -## `input_range` - -An `input_range` is a range that can be read from at least once. +An `input_iterator` is an iterator that can be read from at least once. ```cpp -template -concept input_range = range && input_iterator>; +template +concept input_iterator = + input_or_output_iterator && + indirectly_readable && + requires { typename ITER_CONCEPT(I); } && + derived_from; ``` ### Parameters -*`T`*\ -The type to test to see if it's an `input_range`. +*`I`*\ +The type to test to see if it's an `input_iterator`. ### Remarks -When a type meets the requirements of `input_range`: +When a type meets the requirements of `input_iterator`: -- The `ranges::begin()` function returns an `input_iterator`. Calling `begin()` more than once on an `input_range` results in undefined behavior. -- You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_range` isn't multi-pass. Incrementing an iterator invalidates any copies. +- Calling `begin()` more than once on an `input_iterator` results in undefined behavior. +- You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_iterator` isn't multi-pass. Incrementing an iterator invalidates any copies. - It can be used with `ranges::for_each`. -- It *at least* has an `input_iterator`. It may have a more capable iterator type. +- It *at least* has an `input_iterator`. It may be a more capable iterator type. -## `output_range` +## `output_iterator` -An `output_range` is a range that you can write to. +An `output_iterator` is a range that you can write to. ```cpp template -concept output_range = range && output_iterator, T>; +concept output_iterator = range && output_iterator, T>; ``` ### Parameters @@ -251,26 +224,26 @@ The type of the data to write to the range. The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. -## `random_access_range` +## `random_access_iterator` -A `random_access_range` can read or write a range by index. +A `random_access_iterator` can read or write a range by index. ```cpp template -concept random_access_range = -bidirectional_range && random_access_iterator>; +concept random_access_iterator = +bidirectional_iterator && random_access_iterator>; ``` ### Parameters *`T`*\ -The type to test to see if it's a `sized_range`. +The type to test to see if it's a `sized_iterator`. ### Remarks -A `random_access_range` is the most flexible iterator. It has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is also sortable. +A `random_access_iterator` is the most flexible iterator. It has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. A `random_access_iterator` is also sortable. -Some examples of a `random_access_range` are `std::vector`, `std::array`, and `std::deque`. +Some examples of a `random_access_iterator` are `std::vector`, `std::array`, and `std::deque`. ## `range` @@ -321,33 +294,33 @@ A view `V` is a [`Simple_View`](#simple_view) if all of the following are true: - `const V` is a range - Both `v` and `const V` have the same iterator and sentinel types. -## `sized_range` +## `sized_iterator` -A `sized_range` provides the number of elements in the range in amortized constant time. +A `sized_iterator` provides the number of elements in the range in amortized constant time. ```cpp template - concept sized_range = range && + concept sized_iterator = range && requires(T& t) { ranges::size(t); }; ``` ### Parameters *`T`*\ -The type to test to see if it's a `sized_range`. +The type to test to see if it's a `sized_iterator`. ### Remarks -The requirements of a `sized_range` are that calling `ranges::size` on it: +The requirements of a `sized_iterator` are that calling `ranges::size` on it: - Doesn't modify the range. - Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. -Some examples of a `sized_range` are `std::list` and `std::vector`. +Some examples of a `sized_iterator` are `std::list` and `std::vector`. -### Example: `sized_range` +### Example: `sized_iterator` -The following example shows that a `vector` of `int` is a `sized_range`: +The following example shows that a `vector` of `int` is a `sized_iterator`: ```cpp // requires /std:c++20 or later @@ -357,7 +330,7 @@ The following example shows that a `vector` of `int` is a `sized_range`: int main() { - std::cout << std::boolalpha << std::ranges::sized_range> << '\n'; // outputs "true" + std::cout << std::boolalpha << std::ranges::sized_iterator> << '\n'; // outputs "true" } ``` @@ -392,14 +365,14 @@ Failing that, option 2 is a little simpler than option 3. The advantage of option 3 is that it's possible without changing the definition of the type. -## `viewable_range` +## `viewable_iterator` -A `viewable_range` is a type that either is a view or can be converted to one. +A `viewable_iterator` is a type that either is a view or can be converted to one. ```cpp template - concept viewable_range = - range && (borrowed_range || view>); + concept viewable_iterator = + range && (borrowed_iterator || view>); ``` ### Parameters diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index 1c4f2612ea0..7d3e9fc9493 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -65,7 +65,7 @@ In order of increasing capability, the categories are: | [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | | [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory and can be accessed using pointer arithmetic. | -In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept for a category generally meets the requirements of all concepts in the categories that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. +In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept for a category generally meets the requirements of the concepts in rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. Other range concepts include: @@ -79,8 +79,6 @@ Other range concepts include: | [`view`](#view)C++20 | Specifies a type that has efficient (constant time) move construction, assignment, and destruction. | | [`viewable_range`](#viewable_range)C++20 | Specifies a type that either is a view or can be converted to one. | -For a list of JTW - ## `bidirectional_range` A `bidirectional_range` supports reading and writing the range forwards and backwards. From 26907b57c855f9c29413f91733682f8e12d22ef4 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Tue, 13 Dec 2022 16:55:36 -0800 Subject: [PATCH 07/31] draft --- docs/standard-library/iterator-concepts.md | 279 +++++++++------------ docs/standard-library/iterator.md | 36 ++- docs/standard-library/range-concepts.md | 2 +- 3 files changed, 140 insertions(+), 177 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index 4836d7651e8..44cf7db6642 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -52,28 +52,28 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of iterators. They are directly related to the categories of ranges listed in [`](ranges.md#remarks). - -In order of increasing power, the categories are: +There are six categories of iterators. They are directly related to the categories of ranges listed in [``](ranges.md#kinds-of-ranges). In order of increasing power, the categories are: | Iterator concept | Description | |--|--| -| [`input_or_output_iterator`](#input_or_output_iterator) | The basis of the iterator concept taxonomy. | -| [`output_iterator`](#output_iterator) | Specifies an iterator that you can write to. JTW It supports [output_iterator](iterators.md# JTW) Repeat this pattern for the entries below. | -| [`input_iterator`](#input_iterator) | Specifies an iterator that you can read from at least once. | -DONE | [`forward_iterator`](#forward_iterator) | Specifies an iterator that can read (and possibly write) multiple times. | -DONE | [`bidirectional_iterator`](#bidirectional_iterator) | Specifies an iterator that can read and write both forwards and backwards. | -| [`random_access_iterator`](#random_access_iterator) | Specifies an iterator that can read and write by index. | -DONE| [`contiguous_iterator`](#contiguous_iterator) | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +DONE | [`input_or_output_iterator`](#input_or_output_iterator) | The basis of the iterator concept taxonomy. | +DONE | [`output_iterator`](#output_iterator) | Test for an iterator that you can write to. | +DONE | [`input_iterator`](#input_iterator) | Test for an iterator that you can read from at least once. | +DONE | [`forward_iterator`](#forward_iterator) | Test for an iterator that can read (and possibly write) multiple times. | +DONE | [`bidirectional_iterator`](#bidirectional_iterator) | Test for an iterator that can read and write both forwards and backwards. | +DONE | [`random_access_iterator`](#random_access_iterator) | Test for an iterator that can read and write by index. | +DONE | [`contiguous_iterator`](#contiguous_iterator) | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | + +An iterator that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. An exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. -In the preceding table, concepts are listed in order of increasing capability. An iterator that meets the requirements of a concept for a category generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. However, an exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. +Here's a general summary of the capabilities of the iterators Other iterator concepts include: | Range concept | Description | |--|--| | [`sentinel_for`](#sentinel_for)C++20 | JTW | -| [``sized_sentinel_for``](#sized_sentinel_for)C++20 | JTW | +| [`sized_sentinel_for`](#sized_sentinel_for)C++20 | JTW | ## `bidirectional_iterator` @@ -101,6 +101,21 @@ A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can Some examples of containers that can be used with a `bidirectional_iterator` are `std::set`, `std::vector`, and `std::list`. +### Example: `bidirectional_iterator` + +The following example shows that a `vector` of `int` has a `bidirectional_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + std::cout << std::boolalpha << std::bidirectional_iterator::iterator> << '\n'; // outputs "true" +} +``` + ## `contiguous_iterator` Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. @@ -122,7 +137,7 @@ template *`I`*\ The type to test to see if it's a `contiguous_iterator`. -The elements of a `contiguous_iterator` are stored sequentially in memory and can be accessed using pointer arithmetic. For example, an array can be traversed using a `contiguous_iterator`. +The elements of a `contiguous_iterator` are stored sequentially in memory and can be accessed using pointer arithmetic. For example, an array iterator is a `contiguous_iterator`. ### Remarks @@ -132,35 +147,24 @@ Some examples of a `contiguous_iterator` are `std::array`, `std::vector`, and `s ### Example: `contiguous_iterator` -The following example shows using pointer arithmetic to access a `contiguous_iterator`: +The following example shows that a vector is a `contiguous_iterator`: ```cpp // requires /std:c++20 or later -#include #include #include int main() { - // Show that vector is a contiguous_iterator + // Show that vector has a contiguous_iterator std::vector v = {0,1,2,3,4,5}; - std::cout << std::boolalpha << std::ranges::contiguous_iterator << '\n'; // outputs true - - // Show that pointer arithmetic can be used to access the elements of a contiguous_iterator - auto ptr = v.data(); - ptr += 2; - std::cout << *ptr << '\n'; // outputs 2 + std::cout << std::boolalpha << std::contiguous_iterator; // outputs true } ``` -```output -true -2 -``` - ## `forward_iterator` -Has the capabilities of an `input_iterator` and an `output_iterator`, but can read and write the same element multiple times. +Has the capabilities of an `input_iterator` and an `output_iterator`. Also supports iterating over a collection multiple times. ```cpp template @@ -176,9 +180,32 @@ template *`I`*\ The iterator to test to see if it's a `forward_iterator`. +### Remarks + +A `forward_iterator` can only move forward. + +Some examples of containers that can be used with a `forward_iterator` are `std::unordered_set`, `std::unordered_multiset`, `std::unordered_map`, and `std::unordered_multimap`. + +### Example: `forward_iterator` + +The following example shows that an `unordered_set` has a `forward_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + // Show that vector has a forward_iterator + std::vector v = {0,1,2,3,4,5}; + std::cout << std::boolalpha << std::forward_iterator; // outputs true +} +``` + ## `input_iterator` -An `input_iterator` is an iterator that can be read from at least once. +An `input_iterator` is an iterator that you can read from at least once. ```cpp template @@ -198,194 +225,120 @@ The type to test to see if it's an `input_iterator`. When a type meets the requirements of `input_iterator`: -- Calling `begin()` more than once on an `input_iterator` results in undefined behavior. -- You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_iterator` isn't multi-pass. Incrementing an iterator invalidates any copies. -- It can be used with `ranges::for_each`. -- It *at least* has an `input_iterator`. It may be a more capable iterator type. +- Calling `begin()` more than once on an `input_iterator` results in undefined behavior. This implies that if a type only models `input_iterator`, it isn't multi-pass and can read an element only once. Consider reading from standard input (`cin`) for example. In this case, you can only read the current element once and you can't re-read characters you've already read. You can only read an `input_iterator` forward, not backwards. -## `output_iterator` +### Example: `input_iterator` -An `output_iterator` is a range that you can write to. +The following example shows that an `istream_iterator` is an `input_iterator`: ```cpp -template -concept output_iterator = range && output_iterator, T>; -``` - -### Parameters - -*`R`*\ -The type of the range. - -*`T`*\ -The type of the data to write to the range. - -### Remarks - -The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. - -## `random_access_iterator` - -A `random_access_iterator` can read or write a range by index. +// requires /std:c++20 or later +#include +#include -```cpp -template -concept random_access_iterator = -bidirectional_iterator && random_access_iterator>; +int main() +{ + std::cout << std::boolalpha << std::input_iterator>; // outputs true +} ``` -### Parameters - -*`T`*\ -The type to test to see if it's a `sized_iterator`. - -### Remarks - -A `random_access_iterator` is the most flexible iterator. It has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. A `random_access_iterator` is also sortable. - -Some examples of a `random_access_iterator` are `std::vector`, `std::array`, and `std::deque`. - -## `range` +## `input_or_output_iterator` -Defines the requirements a type must meet to be a `range`. A `range` provides an iterator and a sentinel, so that you can iterate over its elements. +An `input_or_output_iterator` is the basis of the iterator concept taxonomy and supports dereferencing and incrementing +an iterator. Every iterator models `input_or_output_iterator`, at a minimum. ```cpp -template -concept range = requires(T& rg) -{ - ranges::begin(rg); - ranges::end(rg); -}; +template +concept input_or_output_iterator = + requires(I i) { + { *i } -> can-reference; + } && + weakly_incrementable; ``` ### Parameters -*`T`*\ -The type to test to see if it's a `range`. +*`I`*\ +The type to test to see if it's an `input_iterator`. ### Remarks -The requirements of a `range` are: -- It can be iterated using `std::ranges::begin()` and `std::ranges::end()` -- `ranges::begin()` and `ranges::end()` run in amortized constant time and don't modify the `range`. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. -- `[ranges::begin(), ranges::end())` denotes a valid range. +The concept `can-reference` means that the type `I` is a reference, a pointer, or a type that can be implicitly converted to a reference. -## `Simple_View` +## `output_iterator` -A `Simple_View` is an exposition-only concept used on some `ranges` interfaces. It isn't defined in the library. It's only used in the specification to help describe the behavior of some range adaptors. +An `output_iterator` is a type that you can write to. ```cpp -template - concept Simple_View = // exposition only - ranges::view && ranges::range && - std::same_as, std::ranges::iterator_t> && - std::same_as, std::ranges::sentinel_t>; +template +concept output_iterator = + input_or_output_iterator && + indirectly_writable && + requires(I i, T&& t) { + *i++ = std::forward(t); + }; ``` ### Parameters -*`V`*\ -The type to test to see if it's a `Simple_View`. +*`I`*\ +The type to test to see if it's an `output_iterator`. + +*`T`*\ +The type of the values to write. ### Remarks -A view `V` is a [`Simple_View`](#simple_view) if all of the following are true: -- `V` is a view -- `const V` is a range -- Both `v` and `const V` have the same iterator and sentinel types. +An `output_iterator` is single pass. That is, it can only write to the same element once. -## `sized_iterator` +## `random_access_iterator` -A `sized_iterator` provides the number of elements in the range in amortized constant time. +A `random_access_iterator` can read or write by index. ```cpp -template - concept sized_iterator = range && - requires(T& t) { ranges::size(t); }; +template +concept random_access_iterator = + bidirectional_iterator && + derived_from && + totally_ordered && + sized_sentinel_for && + requires(I i, const I j, const iter_difference_t n) { + { i += n } -> same_as; + { j + n } -> same_as; + { n + j } -> same_as; + { i -= n } -> same_as; + { j - n } -> same_as; + { j[n] } -> same_as>; + }; ``` ### Parameters -*`T`*\ -The type to test to see if it's a `sized_iterator`. +*`I`*\ +The type to test to see if it's a `random_access_iterator`. ### Remarks -The requirements of a `sized_iterator` are that calling `ranges::size` on it: +A `random_access_iterator` is the most flexible iterator. It has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. -- Doesn't modify the range. -- Returns the number of elements in amortized constant time. Amortized constant time doesn't mean O(1), but that the average cost over a series of calls, even in the worst case, is O(n) rather than O(n^2) or worse. - -Some examples of a `sized_iterator` are `std::list` and `std::vector`. +Some examples of a `random_access_iterator` are `std::vector`, `std::array`, and `std::deque`. -### Example: `sized_iterator` +### Example: `random_access_iterator` -The following example shows that a `vector` of `int` is a `sized_iterator`: +The following example shows that a `vector` of `int` is a `random_access_iterator`: ```cpp // requires /std:c++20 or later -#include #include #include int main() { - std::cout << std::boolalpha << std::ranges::sized_iterator> << '\n'; // outputs "true" + std::cout << std::boolalpha << std::random_access_iterator::iterator> << '\n'; // outputs "true" } ``` -## `view` - -A `view` has constant time move construction, assignment, and destruction operations--regardless of the number of elements it has. Views don't need to be copy constructible or copy assignable, but if they are, those operations must also run in constant time. - -Because of the constant time requirement, you can efficiently compose views. For example, given a vector of `int` called `input`, a function that determines if a number is divisible by three, and a function that squares a number, the statement `auto x = input | std::views::filter(divisible_by_three) | std::views::transform(square);` efficiently produces a view that contains the squares of the numbers in input that are divisible by three. Connecting views together with `|` is referred to as composing the views. If a type satisfies the [`view`](range-concepts.md#view) concept, then it can be composed efficiently. - -```cpp -template -concept view = ranges::range && std::movable && ranges::enable_view; -``` - -### Parameters - -*`T`*\ -The type to test to see if it's a view. - -### Remarks - -The essential requirement that makes a view composable is that it's cheap to move/copy. This is because the view is moved/copied when it's composed with another view. It must be a movable range. - -`ranges::enable_view` is a trait used to claim conformance to the semantic requirements of the `view` concept. A type can opt in by: -- publicly and unambiguously deriving from a specialization of `ranges::view_interface` -- publicly and unambiguously deriving from the empty class `ranges::view_base`, or -- specializing `ranges::enable_view` to `true` - -Option 1 is generally preferred because `view_interface` also provides default implementation that saves some boilerplate code you have to write. - -Failing that, option 2 is a little simpler than option 3. - -The advantage of option 3 is that it's possible without changing the definition of the type. - -## `viewable_iterator` - -A `viewable_iterator` is a type that either is a view or can be converted to one. - -```cpp -template - concept viewable_iterator = - range && (borrowed_iterator || view>); -``` - -### Parameters - -*`T`*\ -The type to test to see if it either is a view or can be converted to one. - -### Remarks - -Use `std::ranges::views::all()` to convert a range to a view. - ## See also -[``](ranges.md)\ [Range adaptors](range-adaptors.md)\ [View classes](view-classes.md) \ No newline at end of file diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index 22e875a40ec..e86f6d5ae8d 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -25,23 +25,23 @@ JTW fix this table up | Kind | Direction | Read/Write| Example types| |---|---|---|---| -| Output | Forward | Write | `ostream`, `inserter` | -| Input | Forward | Read | `istream`| -| Forward | Forward | Read/Write | | -| Bidirectional | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | -| Random access | Any order | Read/Write | `vector`, `deque`, `string`, and `array`. | +| `bidirectional_iterator` | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | +| `forward_iterator` | Forward | Read/Write | `vector` | +| `input_iterator` | Forward | Read | `istream`| +| `output_iterator` | Forward | Write | `ostream`, `inserter` | +| `random_access_iterator` | Any order | Read/Write | `vector`, `deque`, `string`, and `array`. | Until In C++17, there are five types or categories of iterators: -| Kind | Direction | Read/Write| Example types| +| Kind | Direction | Read/Write| Multipass | Some example types| |---|---|---|---| -| Output | Forward | Write | `ostream`, `inserter` | -| Input | Forward | Read | `istream`| -| Forward | Forward | Read/Write | | -| Bidirectional | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | -| Random access | Any order | Read/Write | `vector`, `deque`, `string`, and `array`. | +| Output | Forward | Write | No | `ostream`, `inserter` | +| Input | Forward | Read | No | `istream`| +| Forward | Forward | Read/Write | Yes | `vector`, `unordered_set`, `unordered_multiset`, `unordered_map`, and `unordered_multimap`. | +| Bidirectional | Forward and backward | Read/Write | Yes | `list`, `set`, `multiset`, `map`, and `multimap`. | +| Random access | Any order | Read/Write | Yes | `vector`, `deque`, `string`, and `array`. | -Iterators are arranged in a hierarchy of capability. In the table above, output iterators are at the low end of the hierarchy, and random-access iterators are at the high end. Iterators higher in the hierarchy can be used in place of those that are lower, but not vice-versa. For example, a random-access iterator can be used in place of a forward iterator, but not the other way around. +Iterators are arranged in a hierarchy of capability. In the table above, output iterators are at the low end of the capability hierarchy, and random-access iterators are at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a random-access iterator can be used in place of a forward iterator, but not the other way around. Visual Studio has added extensions to C++ Standard Library iterators to support debugging for checked and unchecked iterators. For more information, see [Safe Libraries: C++ Standard Library](../standard-library/safe-libraries-cpp-standard-library.md). @@ -88,7 +88,17 @@ Visual Studio has added extensions to C++ Standard Library iterators to support ### Concepts - +| Iterator concept | Description | +|--|--| +| [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) | Specifies an iterator that can read and write both forwards and backwards. | +| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator) | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +| [`forward_iterator`](iterator-concepts.md#forward_iterator) | Specifies an iterator that can read (and possibly write) multiple times. | +| [`input_iterator`](iterator-concepts.md#input_iterator) | Specifies an iterator that you can read from at least once. | +| [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator) | The basis of the iterator concept taxonomy. | +| [`output_iterator`](iterator-concepts.md#output_iterator) | Specifies an iterator that you can write to. | +| [`random_access_iterator`]iterator-concepts.md(#random_access_iterator) | Specifies an iterator that can read and write by index. | +| [`sentinel_for`](iterator-concepts.md#sentinel_for)C++20 | JTW | +| [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for)C++20 | JTW | ### Classes diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index 7d3e9fc9493..776525b9570 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -65,7 +65,7 @@ In order of increasing capability, the categories are: | [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | | [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory and can be accessed using pointer arithmetic. | -In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept for a category generally meets the requirements of the concepts in rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. +In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. Other range concepts include: From 6be8d4bcfd5d8b84af516edec0d5dc33be4aaea3 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Tue, 13 Dec 2022 17:25:22 -0800 Subject: [PATCH 08/31] add sentinel_for and sized_sentinel_for --- docs/standard-library/iterator-concepts.md | 111 ++++++++++++++++++--- 1 file changed, 98 insertions(+), 13 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index 44cf7db6642..ee09c6394b0 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -52,28 +52,26 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of iterators. They are directly related to the categories of ranges listed in [``](ranges.md#kinds-of-ranges). In order of increasing power, the categories are: +There are six categories of iterators. They are directly related to the categories of ranges listed in [``](ranges.md#kinds-of-ranges). In order of increasing capability, the categories are: | Iterator concept | Description | |--|--| -DONE | [`input_or_output_iterator`](#input_or_output_iterator) | The basis of the iterator concept taxonomy. | -DONE | [`output_iterator`](#output_iterator) | Test for an iterator that you can write to. | -DONE | [`input_iterator`](#input_iterator) | Test for an iterator that you can read from at least once. | -DONE | [`forward_iterator`](#forward_iterator) | Test for an iterator that can read (and possibly write) multiple times. | -DONE | [`bidirectional_iterator`](#bidirectional_iterator) | Test for an iterator that can read and write both forwards and backwards. | -DONE | [`random_access_iterator`](#random_access_iterator) | Test for an iterator that can read and write by index. | -DONE | [`contiguous_iterator`](#contiguous_iterator) | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +DONE | [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | +DONE | [`output_iterator`](#output_iterator)C++20 | Test for an iterator that you can write to. | +DONE | [`input_iterator`](#input_iterator)C++20 | Test for an iterator that you can read from at least once. | +DONE | [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | +DONE | [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Test for an iterator that can read and write both forwards and backwards. | +DONE | [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | +DONE | [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | An iterator that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. An exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. -Here's a general summary of the capabilities of the iterators - Other iterator concepts include: -| Range concept | Description | +| Iterator concept | Description | |--|--| -| [`sentinel_for`](#sentinel_for)C++20 | JTW | -| [`sized_sentinel_for`](#sized_sentinel_for)C++20 | JTW | +| [`sentinel_for`](#sentinel_for)C++20 | Test that a type is a sentinel for an iterator type. | +| [`sized_sentinel_for`](#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | ## `bidirectional_iterator` @@ -338,6 +336,93 @@ int main() } ``` +## `sentinel_for` + +Test that a type is a sentinel for an iterator. + +```cpp +template +concept sentinel_for = + semiregular && + input_or_output_iterator && + weakly-equality-comparable-with ; +``` + +### Parameters + +*`I`*\ +The iterator type. + +*`S`*\ +The sentinel type to test to see if it's a sentinel for `I`. + +### Remarks + +A sentinel is a type that can be compared to an iterator to determine if the iterator has reached the end. This concept determines if a type is a sentinel for one of the `input_or_output_iterator` types which includes `input_iterator`, `output_iterator`, `forward_iterator`, `bidirectional_iterator`, `random_access_iterator`, and `contiguous_iterator`. + +### Example: `sentinel_for` + +The following example shows that a `vector` of `int` is a `random_access_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + std::vector v = { 1, 2, 3, 4, 5 }; + std::vector::iterator i = v.begin(); + // test if std::vector::iterator is a sentinel for i + std::cout << std::boolalpha << std::sentinel_for::iterator, decltype(i)>; // outputs true +} +``` + +## `sized_sentinel_for` + +Test that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. + +```cpp +template +concept sized_sentinel_for = + sentinel_for && + !disable_sized_sentinel_for, remove_cv_t> && + requires(const I& i, const S& s) { + {s - i} -> same_as>; + {i - s} -> same_as>; + }; +``` + +### Parameters + +*`I`*\ +The iterator type. + +*`S`*\ +The sentinel type to test. + +### Remarks + +### Example: `sized_sentinel_for` + +The following example shows that a the sentinel for a `vector` can be subtracted from a vector iterator in constant time: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + std::vector v = { 1, 2, 3, 4, 5 }; + std::vector::iterator i = v.begin(); + std::vector::iterator end = v.end(); + // test if i can be subtracted from end in constant time + std::cout << std::boolalpha << std::sized_sentinel_for; << "\n"; // outputs true + std::cout << end - i; // output 5 +} +``` + ## See also [Range adaptors](range-adaptors.md)\ From d4f5dadbc08d81b574e1b3f68623e266c1c553d0 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Wed, 14 Dec 2022 13:04:20 -0800 Subject: [PATCH 09/31] draft --- docs/standard-library/common-view-class.md | 2 +- docs/standard-library/empty-view-class.md | 2 +- docs/standard-library/filter-view-class.md | 2 +- docs/standard-library/iterator-concepts.md | 6 +-- docs/standard-library/iterator.md | 37 ++++++++++--------- docs/standard-library/join-view-class.md | 2 +- docs/standard-library/single-view-class.md | 2 +- docs/standard-library/transform-view-class.md | 4 +- docs/standard-library/view-classes.md | 22 +++++------ 9 files changed, 40 insertions(+), 39 deletions(-) diff --git a/docs/standard-library/common-view-class.md b/docs/standard-library/common-view-class.md index a1d17edbf8c..68d3377c8cb 100644 --- a/docs/standard-library/common-view-class.md +++ b/docs/standard-library/common-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::common`](range-adaptors.md#common) | | **Underlying range** | Must satisfy [`forward_range`](range-concepts.md#forward_range) or higher | | **Element type** | Same as the underlying range | -| **View iterator category** | Supports `forward_range` or [`random_access_range`](range-concepts.md#random_access_range) when the underlying range satisfies `random_access_range` and [`sized_range`](range-concepts.md#sized_range) | +| **View iterator category** | `forward_range` or [`random_access_range`](range-concepts.md#random_access_range) when the underlying range satisfies `random_access_range` and [`sized_range`](range-concepts.md#sized_range) | | **Sized** | Only if the underlying range satisfies [`sized_range`](range-concepts.md#sized_range) | | **Is `const`-iterable** | Only if the underlying range is `const` iterable | | **Common range** | Yes | diff --git a/docs/standard-library/empty-view-class.md b/docs/standard-library/empty-view-class.md index 46d162d6b1c..b449412e6b5 100644 --- a/docs/standard-library/empty-view-class.md +++ b/docs/standard-library/empty-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::empty`](range-adaptors.md#empty) | | **Underlying range** | None | | **Element type** | As specified when the `empty_view` is created | -| **View iterator category** | Supports `contiguous_range` | +| **View iterator category** | `contiguous_range` | | **Sized** | Yes. Always returns 0 | | **Is `const`-iterable** | Yes | | **Common range** | Yes | diff --git a/docs/standard-library/filter-view-class.md b/docs/standard-library/filter-view-class.md index 91c5a0842aa..23cbc042677 100644 --- a/docs/standard-library/filter-view-class.md +++ b/docs/standard-library/filter-view-class.md @@ -35,7 +35,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::filter`](range-adaptors.md#filter) | | **Underlying range** | Must satisfy [`input_range`](range-concepts.md#input_range) or higher | | **Element type** | Same as the underlying range | -| **View iterator category** | Supports `input_range`, [`forward_range`](range-concepts.md#forward_range), or [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range | +| **View iterator category** | `input_range`, [`forward_range`](range-concepts.md#forward_range), or [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range | | **Sized** | No | | **Is `const`-iterable** | No | | **Common range** | Only if the underlying range satisfies [`common_range`](range-concepts.md#common_range) | diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index ee09c6394b0..bf9fd8ae99c 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -64,14 +64,14 @@ DONE | [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Tes DONE | [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | DONE | [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | -An iterator that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. An exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. +An iterator that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it in the previous table. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. An exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. Other iterator concepts include: | Iterator concept | Description | |--|--| -| [`sentinel_for`](#sentinel_for)C++20 | Test that a type is a sentinel for an iterator type. | -| [`sized_sentinel_for`](#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | +DONE | [`sentinel_for`](#sentinel_for)C++20 | Test that a type is a sentinel for an iterator type. | +DONE | [`sized_sentinel_for`](#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | ## `bidirectional_iterator` diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index e86f6d5ae8d..30f781c7a01 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -1,13 +1,15 @@ --- description: "Learn more about: " title: "" -ms.date: 09/29/2022 +ms.date: 12/14/2022 f1_keywords: [""] helpviewer_keywords: ["iterator header"] --- # `` -Defines iterator primitives, predefined iterators and stream iterators, and several supporting templates. The predefined iterators include insert and reverse adaptors. +Defines predefined iterators and stream iterators, iterator primitives, and supporting templates. + +The predefined iterators include insert and reverse adaptors. There are three classes of insert iterator adaptors: front, back, and general. They provide insert semantics rather than overwrite semantics that the container member function iterators provide. @@ -19,13 +21,14 @@ There are three classes of insert iterator adaptors: front, back, and general. T ## Remarks -Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range specified by a type of iterator. Any data structure that satisfies the requirements of the iterator can be operated upon by the algorithm. In C++20, there are x categories of iterators: +Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range specified by a type of iterator. Any data structure that satisfies the requirements of the iterator can be operated upon by the algorithm. In C++20, there are 6 categories of iterators: JTW fix this table up | Kind | Direction | Read/Write| Example types| |---|---|---|---| | `bidirectional_iterator` | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | +| `contiguous_iterator` | Forward and backward | Read/Write | JTW | | `forward_iterator` | Forward | Read/Write | `vector` | | `input_iterator` | Forward | Read | `istream`| | `output_iterator` | Forward | Write | `ostream`, `inserter` | @@ -86,20 +89,6 @@ Visual Studio has added extensions to C++ Standard Library iterators to support |[`operator+`](../standard-library/iterator-operators.md#op_add)|Adds an offset to an iterator and returns the new `reverse_iterator` addressing the inserted element at the new offset position.| |[`operator-`](../standard-library/iterator-operators.md#operator-)|Subtracts one iterator from another and returns the difference.| -### Concepts - -| Iterator concept | Description | -|--|--| -| [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) | Specifies an iterator that can read and write both forwards and backwards. | -| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator) | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | -| [`forward_iterator`](iterator-concepts.md#forward_iterator) | Specifies an iterator that can read (and possibly write) multiple times. | -| [`input_iterator`](iterator-concepts.md#input_iterator) | Specifies an iterator that you can read from at least once. | -| [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator) | The basis of the iterator concept taxonomy. | -| [`output_iterator`](iterator-concepts.md#output_iterator) | Specifies an iterator that you can write to. | -| [`random_access_iterator`]iterator-concepts.md(#random_access_iterator) | Specifies an iterator that can read and write by index. | -| [`sentinel_for`](iterator-concepts.md#sentinel_for)C++20 | JTW | -| [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for)C++20 | JTW | - ### Classes |Name|Description| @@ -123,6 +112,20 @@ Visual Studio has added extensions to C++ Standard Library iterators to support |[`reverse_iterator`](../standard-library/reverse-iterator-class.md)|The class template describes an object that behaves like a random-access iterator, only in reverse.| |[`unchecked_array_iterator`](../standard-library/unchecked-array-iterator-class.md)|A class that accesses an array using a random access, unchecked iterator. **Note:** This class is a Microsoft extension of the C++ Standard Library. Code implemented by using this function isn't portable to C++ Standard build environments that don't support this Microsoft extension.| +## Concepts + +| Iterator concept | Description | +|--|--| +| [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) | Specifies an iterator that can read and write both forwards and backwards. | +| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator) | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +| [`forward_iterator`](iterator-concepts.md#forward_iterator) | Specifies an iterator that can read (and possibly write) multiple times. | +| [`input_iterator`](iterator-concepts.md#input_iterator) | Specifies an iterator that you can read from at least once. | +| [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator) | The basis of the iterator concept taxonomy. | +| [`output_iterator`](iterator-concepts.md#output_iterator) | Specifies an iterator that you can write to. | +| [`random_access_iterator`](iterator-concepts.md#random_access_iterator) | Specifies an iterator that can read and write by index. | +| [`sentinel_for`](iterator-concepts.md#sentinel_for)C++20 | JTW | +| [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for)C++20 | JTW | + ## See also [Header Files Reference](../standard-library/cpp-standard-library-header-files.md)\ diff --git a/docs/standard-library/join-view-class.md b/docs/standard-library/join-view-class.md index fbd23b5a24a..e9decfce05c 100644 --- a/docs/standard-library/join-view-class.md +++ b/docs/standard-library/join-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::join`](range-adaptors.md#join) | | **Underlying range** | Must satisfy [`input_range`](range-concepts.md#input_range) or higher | | **Element type** | Same as the underlying range | -| **View iterator category** | Supports `input_range` up to [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range being iterated | +| **View iterator category** | `input_range` up to [`bidirectional_range`](range-concepts.md#bidirectional_range) depending on the underlying range being iterated | | **Sized** | No | | **Is `const`-iterable** | Only if the underlying range is `const` iterable | | **Common range** | Only if the underlying range satisfies [`common_range`](range-concepts.md#common_range) | diff --git a/docs/standard-library/single-view-class.md b/docs/standard-library/single-view-class.md index ba71f2e2b08..775d0531a49 100644 --- a/docs/standard-library/single-view-class.md +++ b/docs/standard-library/single-view-class.md @@ -32,7 +32,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::single`](range-adaptors.md#single) | | **Underlying range** | None | | **Element type** | Specified when the `single_view` is created | -| **View iterator category** | Supports `contiguous_range` | +| **View iterator category** | `contiguous_range` | | **Sized** | Always returns 1 | | **Is `const`-iterable** | Yes | | **Common range** | Yes | diff --git a/docs/standard-library/transform-view-class.md b/docs/standard-library/transform-view-class.md index 21c1eeabaa6..e80c25dc5be 100644 --- a/docs/standard-library/transform-view-class.md +++ b/docs/standard-library/transform-view-class.md @@ -1,7 +1,7 @@ --- title: "transform_view class (C++ Standard Library)| Microsoft Docs" description: "API reference for the Standard Template Library (STL) transform_view class, which is a view of an underlying sequence after applying a transformation function to each element." -ms.date: 10/07/2022 +ms.date: 12/14/2022 f1_keywords: ["ranges/std::transform_view", "ranges/std::transform_view::base", "ranges/std::transform_view::begin", "ranges/std::transform_view::empty", "ranges/std::transform_view::end", "ranges/std::transform_view::operator bool", "ranges/std::transform_view::back", "ranges/std::transform_view::front", "ranges/std::transform_view::operator[]"] helpviewer_keywords: ["std::ranges::transform_view [C++]", "std::ranges::transform_view::base [C++]", "std::ranges::transform_view::begin [C++]", "std::ranges::transform_view::empty [C++]", "std::ranges::transform_view::end [C++]", "std::ranges::transform_view::back [C++]", "std::ranges::transform_view::front [C++]", "std::ranges::transform_view::operator bool [C++]", "std::ranges::transform_view::operator[] [C++]"] dev_langs: ["C++"] @@ -37,7 +37,7 @@ For a description of the following entries, see [View class characteristics](vie | **Range adaptor** | [`views::transform`](range-adaptors.md#transform) | | **Underlying range** | Must satisfy [`input_range`](range-concepts.md#input_range) or higher | | **Element type** | Same as the transformation function's return type. | -| **View iterator category** | Supports [`input_range`](range-concepts.md#input_range) up to `random_access`, depending on the underlying range | +| **View iterator category** | Supports [`input_range`](range-concepts.md#input_range) up to [`random_access_range`](range-concepts.md#random_access_range), depending on the underlying range | | **Sized** | Only if the underlying range satisfies [`sized_range`](range-concepts.md#sized_range) | | **Is `const`-iterable** | Only if the underlying range is `const` iterable and the transformation works on `const` references. | | **Common range** | Only if the underlying range satisfies [`common_range`](range-concepts.md#common_range) | diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 4fdd0d059ba..472ea487784 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -7,13 +7,13 @@ helpviewer_keywords: ["RANGES/VIEWS/std", "VIEWS/std"] --- # View classes -A *view* is a lightweight range that refers to elements that it doesn't own (except for [`owning_view`](owning-view-class.md)). A view is typically based on another range and provides a different way of looking at it, whether by transforming or filtering it. For example, [`std::views::filter`](filter-view-class.md) is a view that uses the criteria that you specify to select elements from another range. +A *view* is a lightweight range that refers to elements that it doesn't own (with the exception of [`owning_view`](owning-view-class.md)). A view is typically based on another range and provides a different way of looking at it, whether by transforming or filtering it. For example, [`std::views::filter`](filter-view-class.md) is a view that uses the criteria that you specify to select elements from another range. -When you access the elements in a view, it's done "lazily" so that work is done only when you get an element. This also makes it possible to combine, or *compose*, views without a performance penalty. +When you access the elements in a view, it's done "lazily" so that work is done only when you get an element. This makes it possible to combine, or *compose*, views without a performance penalty. For example, you could create a view that provides only the even elements from a range and then transform them by squaring them. The work to do the filtering and transformation is done only for the elements that you access, and only when you access them. -A view can be copied, assigned, and destroyed in constant time no matter how many elements it contains. This is because a view doesn't own the elements that it refers to, so it doesn't need to make a copy. This is also why you can compose views without a performance penalty. +A view can be copied, assigned, and destroyed in constant time no matter how many elements it contains. This is because a view doesn't own the elements that it refers to, so it doesn't need to make a copy. This is why you can compose views without a performance penalty. You typically create a view by using a [range adaptor](range-adaptors.md). Range adaptors are the intended way to create a view, are easier to use than instantiating the view classes directly, and are sometimes more efficient than instantiating the view classes directly. The view classes are exposed directly in case you need to create your own custom view type based on an existing view type. @@ -123,14 +123,14 @@ The following view classes are defined in the `std::ranges` namespace. | [`transform_view`](transform-view-class.md)C++20 | A view of an underlying sequence after a transformation function is applied to each element. | | [`values_view`](values-view-class.md)C++20 | A view over the second index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of the `int` elements from each tuple. | -Many of these classes have corresponding [range adaptors](range-adaptors.md) in the `std:views` namespace that creates instances of them. Prefer the adaptors in `std::views` to creating view classes directly. The range adaptors are the intended access points, are easier to use, and in some cases are more efficient. +Many of these classes have corresponding [range adaptors](range-adaptors.md) in the `std:views` namespace that creates instances of them. Prefer using an adaptor to create a view instead of creating view classes directly. The range adaptors are the intended way to create views, are easier to use, and in some cases are more efficient. ## View classes characteristics Each view class topic has a **Characteristics** section after the syntax section. The **Characteristics** section has the following entries: * **Range adaptor**: A link to the range adaptor that creates the view. You typically use a range adaptor to create a view rather than create a view class directly, so it's listed here for convenience. -* **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See the following table for the hierarchy of iterators. +* **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See [ranges iterator hierarchy](#ranges_iterator_hierarchy) for more information about the kinds of iterators. * **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a `bidirectional_iterator`, even if the underlying range has a `random_access_iterator`. * **Element type**: The type of the elements that the view's iterator returns. * **Sized**: Whether the view can return the number of elements that it refers to. Not all views can. @@ -144,22 +144,20 @@ Each view class topic has a **Characteristics** section after the syntax section Range algorithms that return iterators (or subranges) do so only when their arguments are lvalues (non-temporaries) or borrowed ranges. Otherwise, they return a `std::dangling` object, which provides a hint in error messages about what went wrong if you tried to use it like an iterator. * **Is `const` iterable**: Indicates whether you can iterate over a `const` instance of the view. Not all `const` views can be iterated. If a view isn't `const` iterable, you can't iterate with `for (const auto& element : as_const(theView))` or pass it to a function that takes a `const` reference to the view and then tries to iterate over it. -### Iterator hierarchy +### Ranges iterator hierarchy -The iterator category that **Range adaptor** and **View iterator category** mention in the **Characteristics** section refers to the hierarchy of iterators that ranges and views support. +In the **Characteristics** section of each view class topic, the iterator category in **Underlying range** and **View iterator category** refers to the kind of iterators that ranges and views support. Ranges iterators are categorized into six levels of capability, which are identified by C++20 concepts. That hierarchy, in increasing order of capability, is: -That hierarchy, in increasing order of capability, is: - -| Range iterator category | Description | +| Range iterator concept | Description | |--|--| | [`output_range`](range-concepts.md#output_range) | Write-only, only moves forward; single-pass. | -| [`input_range`](range-concepts.md#input_range) | Only moves forward; single-pass. | +| [`input_range`](range-concepts.md#input_range) | Read-only, only moves forward; single-pass. | | [`forward_range`](range-concepts.md#forward_range) | Only moves forward; multi-pass. | | [`bidirectional_range`](range-concepts.md#bidirectional_range) | Can move forward and backward; multi-pass. | | [`random_access_range`](range-concepts.md#random_access_range) | Can access the collection with an index; multi-pass. | | [`contiguous_range`](range-concepts.md#contiguous_range) | Can access the collection with an index, and elements are stored contiguously in memory. | -An iterator has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) has the capabilities of [`forward_range`](range-concepts.md#forward_range), but not vice versa. +Generally speaking, an iterator has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) has the capabilities of [`forward_range`](range-concepts.md#forward_range), but not vice versa. An exception is `input_range` which doesn't have the capability of `output_range` because you can't write to an `input_range`. The statement "requires `input_range` or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because they are all as capable as `input_range`. From d52872929485da2ffc74cfefa33854fe83ad7ca7 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Thu, 15 Dec 2022 09:43:54 -0800 Subject: [PATCH 10/31] draft --- docs/standard-library/iterator-concepts.md | 26 ++++++------ docs/standard-library/iterator.md | 49 ++++++---------------- docs/standard-library/ranges.md | 2 +- docs/standard-library/view-classes.md | 2 +- 4 files changed, 29 insertions(+), 50 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index bf9fd8ae99c..26aca264b9c 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -1,11 +1,11 @@ --- description: "Learn more about iterator concepts." -title: " concepts" +title: "Iterator concepts" ms.date: 12/05/2022 f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_iterator", "ranges/std::ranges::borrowed_iterator", "ranges/std::ranges::common_iterator", "ranges/std::ranges::contiguous_iterator", "ranges/std::ranges::forward_iterator", "ranges/std::ranges::input_iterator", "ranges/std::ranges::output_iterator", "ranges/std::ranges::random_access_iterator", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_iterator", "ranges/std::ranges::view", "ranges/std::ranges::viewable_iterator"] helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_iterator", "std::ranges [C++], ranges::borrowed_iterator", "std::ranges [C++], ranges::common_iterator", "std::ranges [C++], ranges::contiguous_iterator", "std::ranges [C++], ranges::forward_iterator", "std::ranges [C++], ranges::input_iterator", "std::ranges [C++], ranges::output_iterator", "std::ranges [C++], ranges::random_access_iterator", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_iterator", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_iterator"] --- -# `` concepts +# Iterator concepts Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. @@ -52,17 +52,19 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of iterators. They are directly related to the categories of ranges listed in [``](ranges.md#kinds-of-ranges). In order of increasing capability, the categories are: +There are six categories of iterators. They are directly related to the categories of ranges listed in [``](ranges.md#kinds-of-ranges). -| Iterator concept | Description | -|--|--| -DONE | [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | -DONE | [`output_iterator`](#output_iterator)C++20 | Test for an iterator that you can write to. | -DONE | [`input_iterator`](#input_iterator)C++20 | Test for an iterator that you can read from at least once. | -DONE | [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | -DONE | [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Test for an iterator that can read and write both forwards and backwards. | -DONE | [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | -DONE | [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception to the rule that iterators higher in the hierarchy can generally be used in place of those that are lower is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. + +| Iterator concept | Description | Direction | Read/write | Multi-pass | Example types that use this iterator | +|--|--|--|--|--|--| +| [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | Forward | Read or write | Single-pass | `std::istream_iterator`, `std::ostream_iterator` | +| [`output_iterator`](#output_iterator)C++20 | Test for an iterator that you can write to. | Forward | Write | Single-pass | `ostream`, `inserter` | +| [`input_iterator`](#input_iterator)C++20 | Test for an iterator that you can read from at least once. | Forward | Read | Single-pass | `istream`, `istreambuf_iterator` | +| [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | Forward | Read/write | Multi-pass | `vector::iterator`, `list::iterator` | +| [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Test for an iterator that can read and write both forwards and backwards. | Forward/Backward | Read/write | Multi-pass | `list`, `set`, `multiset`, `map`, and `multimap`. | +| [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | Read/write | Multi-pass | `vector::iterator`, `array::iterator` | +| [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | Read/write | Multi-pass | `array`, `vector` | An iterator that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it in the previous table. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. An exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index 30f781c7a01..da8d3769537 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -1,6 +1,6 @@ --- -description: "Learn more about: " title: "" +description: "Learn more about: " ms.date: 12/14/2022 f1_keywords: [""] helpviewer_keywords: ["iterator header"] @@ -9,10 +9,6 @@ helpviewer_keywords: ["iterator header"] Defines predefined iterators and stream iterators, iterator primitives, and supporting templates. -The predefined iterators include insert and reverse adaptors. - -There are three classes of insert iterator adaptors: front, back, and general. They provide insert semantics rather than overwrite semantics that the container member function iterators provide. - ## Requirements **Header:** `` @@ -21,30 +17,9 @@ There are three classes of insert iterator adaptors: front, back, and general. T ## Remarks -Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range specified by a type of iterator. Any data structure that satisfies the requirements of the iterator can be operated upon by the algorithm. In C++20, there are 6 categories of iterators: - -JTW fix this table up +Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range of values as specified by a kind of iterator. Algorithms can operate on any data structure that satisfies the requirements of the iterator. -| Kind | Direction | Read/Write| Example types| -|---|---|---|---| -| `bidirectional_iterator` | Forward and backward | Read/Write | `list`, `set`, `multiset`, `map`, and `multimap`. | -| `contiguous_iterator` | Forward and backward | Read/Write | JTW | -| `forward_iterator` | Forward | Read/Write | `vector` | -| `input_iterator` | Forward | Read | `istream`| -| `output_iterator` | Forward | Write | `ostream`, `inserter` | -| `random_access_iterator` | Any order | Read/Write | `vector`, `deque`, `string`, and `array`. | - -Until In C++17, there are five types or categories of iterators: - -| Kind | Direction | Read/Write| Multipass | Some example types| -|---|---|---|---| -| Output | Forward | Write | No | `ostream`, `inserter` | -| Input | Forward | Read | No | `istream`| -| Forward | Forward | Read/Write | Yes | `vector`, `unordered_set`, `unordered_multiset`, `unordered_map`, and `unordered_multimap`. | -| Bidirectional | Forward and backward | Read/Write | Yes | `list`, `set`, `multiset`, `map`, and `multimap`. | -| Random access | Any order | Read/Write | Yes | `vector`, `deque`, `string`, and `array`. | - -Iterators are arranged in a hierarchy of capability. In the table above, output iterators are at the low end of the capability hierarchy, and random-access iterators are at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a random-access iterator can be used in place of a forward iterator, but not the other way around. +In C++20, there are 6 categories of iterators. Iterators are arranged in a hierarchy of capability. Their capabilities are specified by C++20 concepts. For a description of the various iterators and their capabilities, see [Iterator concepts](iterator-concepts.md) Visual Studio has added extensions to C++ Standard Library iterators to support debugging for checked and unchecked iterators. For more information, see [Safe Libraries: C++ Standard Library](../standard-library/safe-libraries-cpp-standard-library.md). @@ -114,17 +89,19 @@ Visual Studio has added extensions to C++ Standard Library iterators to support ## Concepts +The following concepts are defined in the `std` namespace. They apply to iterators, and are related to the iterator categories for ranges described in [`` concepts](range-concepts.md). + | Iterator concept | Description | |--|--| -| [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) | Specifies an iterator that can read and write both forwards and backwards. | -| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator) | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | -| [`forward_iterator`](iterator-concepts.md#forward_iterator) | Specifies an iterator that can read (and possibly write) multiple times. | -| [`input_iterator`](iterator-concepts.md#input_iterator) | Specifies an iterator that you can read from at least once. | -| [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator) | The basis of the iterator concept taxonomy. | +| [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator)C++20 | Specifies an iterator that can read and write both forwards and backwards. | +| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator)C++20 | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +| [`forward_iterator`](iterator-concepts.md#forward_iterator)C++20 | Specifies an iterator that can read (and possibly write) multiple times. | +| [`input_iterator`](iterator-concepts.md#input_iterator)C++20 | Specifies an iterator that you can read from at least once. | +| [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | | [`output_iterator`](iterator-concepts.md#output_iterator) | Specifies an iterator that you can write to. | -| [`random_access_iterator`](iterator-concepts.md#random_access_iterator) | Specifies an iterator that can read and write by index. | -| [`sentinel_for`](iterator-concepts.md#sentinel_for)C++20 | JTW | -| [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for)C++20 | JTW | +| [`random_access_iterator`](iterator-concepts.md#random_access_iterator)C++20 | Specifies an iterator that can read and write by index. | +| [`sentinel_for`](iterator-concepts.md#sentinel_for)C++20 | Test that a type is a sentinel for an iterator type. | +| [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | ## See also diff --git a/docs/standard-library/ranges.md b/docs/standard-library/ranges.md index d101e222e60..49e96c06901 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -116,7 +116,7 @@ The range algorithms are almost identical to the corresponding iterator-pair alg ### Kinds of ranges -How you can iterate over the elements of a range depends on its underlying iterator type. The iterator type a range requires is specified as a C++20 concept. +How you can iterate over the elements of a range depends on its underlying iterator type. Ranges use C++ concepts to specify the iterator they support. In C++20, to say that concept *X* refines concept *Y* means that everything that satisfies concept *Y* also satisfies concept *X*. For example: *car*, *bus*, and *truck* all refine *vehicle*. diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 472ea487784..9679f8cfe4f 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -146,7 +146,7 @@ Each view class topic has a **Characteristics** section after the syntax section ### Ranges iterator hierarchy -In the **Characteristics** section of each view class topic, the iterator category in **Underlying range** and **View iterator category** refers to the kind of iterators that ranges and views support. Ranges iterators are categorized into six levels of capability, which are identified by C++20 concepts. That hierarchy, in increasing order of capability, is: +In the **Characteristics** section of each view class topic, the iterator category in **Underlying range** and **View iterator category** refers to the kind of iterator that the range/view supports. Ranges iterators are categorized into six levels of capability, which are identified by C++20 concepts. That hierarchy, in increasing order of capability, is: | Range iterator concept | Description | |--|--| From 6dd32c24a69ce31da524299dac4139d29b92de9f Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Thu, 15 Dec 2022 11:12:31 -0800 Subject: [PATCH 11/31] draft --- docs/standard-library/iterator-concepts.md | 127 +++++++++++++++------ docs/standard-library/range-concepts.md | 19 ++- docs/standard-library/ranges.md | 8 +- docs/standard-library/view-classes.md | 2 + 4 files changed, 104 insertions(+), 52 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index 26aca264b9c..a70302a47d2 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -1,7 +1,7 @@ --- description: "Learn more about iterator concepts." title: "Iterator concepts" -ms.date: 12/05/2022 +ms.date: 12/15/2022 f1_keywords: ["ranges/std::ranges::range", "ranges/std::ranges::bidirectional_iterator", "ranges/std::ranges::borrowed_iterator", "ranges/std::ranges::common_iterator", "ranges/std::ranges::contiguous_iterator", "ranges/std::ranges::forward_iterator", "ranges/std::ranges::input_iterator", "ranges/std::ranges::output_iterator", "ranges/std::ranges::random_access_iterator", "ranges/std::ranges::simple_view", "ranges/std::ranges::sized_iterator", "ranges/std::ranges::view", "ranges/std::ranges::viewable_iterator"] helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ranges::bidirectional_iterator", "std::ranges [C++], ranges::borrowed_iterator", "std::ranges [C++], ranges::common_iterator", "std::ranges [C++], ranges::contiguous_iterator", "std::ranges [C++], ranges::forward_iterator", "std::ranges [C++], ranges::input_iterator", "std::ranges [C++], ranges::output_iterator", "std::ranges [C++], ranges::random_access_iterator", "std::ranges [C++], ranges::simple_view", "std::ranges [C++], ranges::sized_iterator", "std::ranges [C++], ranges::view", "std::ranges [C++], ranges::viewable_iterator"] --- @@ -52,28 +52,26 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of iterators. They are directly related to the categories of ranges listed in [``](ranges.md#kinds-of-ranges). +There are six categories of iterators. They are directly related to the categories of ranges listed under [Range concepts](ranges.md#range-concepts). -The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception to the rule that iterators higher in the hierarchy can generally be used in place of those that are lower is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. +The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. | Iterator concept | Description | Direction | Read/write | Multi-pass | Example types that use this iterator | |--|--|--|--|--|--| -| [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | Forward | Read or write | Single-pass | `std::istream_iterator`, `std::ostream_iterator` | -| [`output_iterator`](#output_iterator)C++20 | Test for an iterator that you can write to. | Forward | Write | Single-pass | `ostream`, `inserter` | -| [`input_iterator`](#input_iterator)C++20 | Test for an iterator that you can read from at least once. | Forward | Read | Single-pass | `istream`, `istreambuf_iterator` | -| [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | Forward | Read/write | Multi-pass | `vector::iterator`, `list::iterator` | -| [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Test for an iterator that can read and write both forwards and backwards. | Forward/Backward | Read/write | Multi-pass | `list`, `set`, `multiset`, `map`, and `multimap`. | -| [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | Read/write | Multi-pass | `vector::iterator`, `array::iterator` | -| [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | Read/write | Multi-pass | `array`, `vector` | - -An iterator that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it in the previous table. For example, a `random_access_iterator` has the capability of a `bidirectional_iterator`, `forward_iterator`, `input_iterator`, and `output_iterator`. An exception is `input_iterator` which doesn't have the capability of an `output_iterator` because it can't be written to. +| [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | Forward | Read or write | no | `std::istream_iterator`, `std::ostream_iterator` | +| [`output_iterator`](#output_iterator)C++20 | Test for an iterator that you can write to. | Forward | Write | no | `ostream`, `inserter` | +| [`input_iterator`](#input_iterator)C++20 | Test for an iterator that you can read from at least once. | Forward | Read | no | `istream`, `istreambuf_iterator` | +| [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | Forward | Read/write | yes | `vector::iterator`, `list::iterator` | +| [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Test for an iterator that can read and write both forwards and backwards. | Forward/backward | Read/write | yes | `list`, `set`, `multiset`, `map`, and `multimap`. | +| [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | Forward/Backward | Read/write | yes | `vector::iterator`, `array::iterator`, `deque::iterator` | +| [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | Forward/backward | Read/write | yes | `array`, `vector` `string`.| Other iterator concepts include: | Iterator concept | Description | |--|--| -DONE | [`sentinel_for`](#sentinel_for)C++20 | Test that a type is a sentinel for an iterator type. | -DONE | [`sized_sentinel_for`](#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | +| [`sentinel_for`](#sentinel_for)C++20 | Test that a type is a sentinel for an iterator type. | +| [`sized_sentinel_for`](#sized_sentinel_for)C++20 | Specifies that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. | ## `bidirectional_iterator` @@ -103,7 +101,7 @@ Some examples of containers that can be used with a `bidirectional_iterator` are ### Example: `bidirectional_iterator` -The following example shows that a `vector` of `int` has a `bidirectional_iterator`: +The following example uses the `bidirectional_iterator` concept to show that `vector` has a `bidirectional_iterator`: ```cpp // requires /std:c++20 or later @@ -113,6 +111,10 @@ The following example shows that a `vector` of `int` has a `bidirectional_iterat int main() { std::cout << std::boolalpha << std::bidirectional_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::contiguous_iterator; // outputs true } ``` @@ -137,7 +139,7 @@ template *`I`*\ The type to test to see if it's a `contiguous_iterator`. -The elements of a `contiguous_iterator` are stored sequentially in memory and can be accessed using pointer arithmetic. For example, an array iterator is a `contiguous_iterator`. +The elements of a `contiguous_iterator` are stored sequentially in memory and can be accessed using pointer arithmetic. A `std::array` has a `contiguous_iterator`. ### Remarks @@ -147,7 +149,7 @@ Some examples of a `contiguous_iterator` are `std::array`, `std::vector`, and `s ### Example: `contiguous_iterator` -The following example shows that a vector is a `contiguous_iterator`: +The following example uses the `contiguous_iterator` concept to show that a `vector` has a `contiguous_iterator`: ```cpp // requires /std:c++20 or later @@ -156,8 +158,11 @@ The following example shows that a vector is a `contiguous_iterator`: int main() { - // Show that vector has a contiguous_iterator - std::vector v = {0,1,2,3,4,5}; + // Show that vector has a contiguous_iterator + std::cout << std::boolalpha << std::contiguous_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; std::cout << std::boolalpha << std::contiguous_iterator; // outputs true } ``` @@ -188,7 +193,7 @@ Some examples of containers that can be used with a `forward_iterator` are `std: ### Example: `forward_iterator` -The following example shows that an `unordered_set` has a `forward_iterator`: +The following example uses the `forward_iterator` concept to show that a `vector` has a `forward_iterator`: ```cpp // requires /std:c++20 or later @@ -198,7 +203,10 @@ The following example shows that an `unordered_set` has a `forward_iterator`: int main() { // Show that vector has a forward_iterator - std::vector v = {0,1,2,3,4,5}; + std::cout << std::boolalpha << std::forward_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; std::cout << std::boolalpha << std::forward_iterator; // outputs true } ``` @@ -229,23 +237,23 @@ When a type meets the requirements of `input_iterator`: ### Example: `input_iterator` -The following example shows that an `istream_iterator` is an `input_iterator`: +The following example uses the `input_iterator` concept to show that an `istream_iterator` has an `input_iterator`: ```cpp // requires /std:c++20 or later #include -#include int main() { + // Show that a istream_iterator has an input_iterator std::cout << std::boolalpha << std::input_iterator>; // outputs true } ``` ## `input_or_output_iterator` -An `input_or_output_iterator` is the basis of the iterator concept taxonomy and supports dereferencing and incrementing -an iterator. Every iterator models `input_or_output_iterator`, at a minimum. +An `input_or_output_iterator` is the basis of the iterator concept taxonomy. It supports dereferencing and incrementing +an iterator. Every iterator models `input_or_output_iterator`. ```cpp template @@ -259,12 +267,31 @@ concept input_or_output_iterator = ### Parameters *`I`*\ -The type to test to see if it's an `input_iterator`. +The type to test to see if it's an `input_or_output_iterator`. ### Remarks The concept `can-reference` means that the type `I` is a reference, a pointer, or a type that can be implicitly converted to a reference. +### Example: `input_or_output_iterator` + +The following example uses the `input_or_output_iterator` concept to show that `vector` has an `input_or_output_iterator`: + +```cpp +// requires /std:c++20 or later +#include + +int main() +{ + // Show that a vector has an input_or_output_iterator + std::cout << std::boolalpha << std::input_or_output_iterator::iterator> << '\n'; // outputs true + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::input_or_output_iterator; // outputs true +} +``` + ## `output_iterator` An `output_iterator` is a type that you can write to. @@ -291,6 +318,25 @@ The type of the values to write. An `output_iterator` is single pass. That is, it can only write to the same element once. +### Example: `output_iterator` + +The following example uses the `output_iterator` concept to show that `vector` has an `output_iterator`: + +```cpp +// requires /std:c++20 or later +#include +#include + +int main() +{ + // Show that vector has an output_iterator + std::cout << std::boolalpha << std::output_iterator::iterator, int> << "\n"; // outputs "true" + + // another way to test + std::vector v = { 0,1,2,3,4,5 }; + std::cout << std::boolalpha << std::output_iterator; // outputs true +} + ## `random_access_iterator` A `random_access_iterator` can read or write by index. @@ -319,13 +365,13 @@ The type to test to see if it's a `random_access_iterator`. ### Remarks -A `random_access_iterator` is the most flexible iterator. It has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. +A `random_access_iterator` has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. Some examples of a `random_access_iterator` are `std::vector`, `std::array`, and `std::deque`. ### Example: `random_access_iterator` -The following example shows that a `vector` of `int` is a `random_access_iterator`: +The following example shows that a `vector` has a `random_access_iterator`: ```cpp // requires /std:c++20 or later @@ -334,7 +380,12 @@ The following example shows that a `vector` of `int` is a `random_access_iterato int main() { + // Show that vector has a random_access_iterator std::cout << std::boolalpha << std::random_access_iterator::iterator> << '\n'; // outputs "true" + + // another way to test + std::vector v = {0,1,2}; + std::cout << std::boolalpha << std::random_access_iterator; // outputs true } ``` @@ -356,7 +407,7 @@ concept sentinel_for = The iterator type. *`S`*\ -The sentinel type to test to see if it's a sentinel for `I`. +The type to test to see if it's a sentinel for `I`. ### Remarks @@ -364,7 +415,7 @@ A sentinel is a type that can be compared to an iterator to determine if the ite ### Example: `sentinel_for` -The following example shows that a `vector` of `int` is a `random_access_iterator`: +The following example uses the `sentinel_for` concept to show that `std::vector::iterator` is a sentinel for `vector`: ```cpp // requires /std:c++20 or later @@ -373,16 +424,16 @@ The following example shows that a `vector` of `int` is a `random_access_iterato int main() { - std::vector v = { 1, 2, 3, 4, 5 }; + std::vector v = {0, 1, 2}; std::vector::iterator i = v.begin(); - // test if std::vector::iterator is a sentinel for i + // show that vector::iterator is a sentinel for vector std::cout << std::boolalpha << std::sentinel_for::iterator, decltype(i)>; // outputs true } ``` ## `sized_sentinel_for` -Test that an iterator and its sentinel can be subtracted (using `-`) to find their difference in constant time. +Test that an iterator and its sentinel can be subtracted (using `-`) to find the difference in constant time. ```cpp template @@ -407,7 +458,7 @@ The sentinel type to test. ### Example: `sized_sentinel_for` -The following example shows that a the sentinel for a `vector` can be subtracted from a vector iterator in constant time: +The following example uses the `sized_sentinel_for` concept to verify that the sentinel for a `vector` can be subtracted from the vectors iterator in constant time: ```cpp // requires /std:c++20 or later @@ -416,12 +467,12 @@ The following example shows that a the sentinel for a `vector` can be subtracted int main() { - std::vector v = { 1, 2, 3, 4, 5 }; + std::vector v = { 1, 2, 3 }; std::vector::iterator i = v.begin(); std::vector::iterator end = v.end(); - // test if i can be subtracted from end in constant time - std::cout << std::boolalpha << std::sized_sentinel_for; << "\n"; // outputs true - std::cout << end - i; // output 5 + // use the sized_sentinel_for concept to verify that i can be subtracted from end in constant time + std::cout << std::boolalpha << std::sized_sentinel_for << "\n"; // outputs true + std::cout << end - i; // outputs 3 } ``` diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index 776525b9570..acc118c797c 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -52,14 +52,12 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Range concepts are defined in the `std::ranges` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of ranges. They are related to the categories of iterators listed in [` concepts](iterator-concepts.md). - -In order of increasing capability, the categories are: +There are six categories of ranges. They are related to the categories of iterators listed in [`` concepts](iterator-concepts.md). In order of increasing capability, the categories are: | Range concept | Description | |--|--| -| [`output_range`](#output_range) | Specifies a range that you can write to. JTW It supports [output_iterator](iterators.md# JTW) Repeat this pattern for the entries below. | -| [`input_range`](#input_range) | Specifies a range that you can read from at least once. | +| [`output_range`](#output_range) | Specifies a range that you can write to. | +| [`input_range`](#input_range) | Specifies a range that you can read from at least once.| | [`forward_range`](#forward_range) | Specifies a range that can read (and possibly write) multiple times. | | [`bidirectional_range`](#bidirectional_range) | Specifies a range that can read and write both forwards and backwards. | | [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | @@ -96,6 +94,7 @@ The type to test to see if it's a `bidirectional_range`. ### Remarks +This kind of range supports [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) or above. A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. Some examples of a `bidirectional_range` are `std::set`, `std::vector`, and `std::list`. @@ -155,7 +154,7 @@ The type to test to see if it's a `contiguous_range`. ### Remarks -A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. +A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. This kind of range supports [`continguous_iterator`](iterator-concepts.md#contiguous_iterator) which is the most flexible of all the iterators. Some examples of a `contiguous_range` are `std::array`, `std::vector`, and `std::string`. @@ -203,7 +202,7 @@ The type to test to see if it's a `forward_range`. ### Remarks -A `forward_iterator` can iterate over a range multiple times. +This kind of range supports [`forward_iterator`](iterator-concepts.md#forward_iterator) or above. A `forward_iterator` can iterate over a range multiple times. ## `input_range` @@ -226,7 +225,7 @@ When a type meets the requirements of `input_range`: - The `ranges::begin()` function returns an `input_iterator`. Calling `begin()` more than once on an `input_range` results in undefined behavior. - You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_range` isn't multi-pass. Incrementing an iterator invalidates any copies. - It can be used with `ranges::for_each`. -- It *at least* has an `input_iterator`. It may have a more capable iterator type. +- It supports [`input_iterator`](iterator-concepts.md#input_iterator) or above. ## `output_range` @@ -247,7 +246,7 @@ The type of the data to write to the range. ### Remarks -The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. +The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. In other words, it supports [`output_iterator`](iterator-concepts.md#output_iterator) or above. ## `random_access_range` @@ -266,7 +265,7 @@ The type to test to see if it's a `sized_range`. ### Remarks -A `random_access_range` is the most flexible iterator. It has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is also sortable. +This kind of range supports [`random_access_iterator`](iterator-concepts.md#random_access_iterator) or above. A `random_access_range` has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is sortable. Some examples of a `random_access_range` are `std::vector`, `std::array`, and `std::deque`. diff --git a/docs/standard-library/ranges.md b/docs/standard-library/ranges.md index 49e96c06901..dba76984427 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -114,17 +114,17 @@ The range algorithms are almost identical to the corresponding iterator-pair alg | [`size`](range-functions.md#size)C++20 | Get the size of the range as an unsigned value. | | [`ssize`](range-functions.md#ssize)C++20 | Get the size of the range as a signed value. | -### Kinds of ranges +### Range concepts -How you can iterate over the elements of a range depends on its underlying iterator type. Ranges use C++ concepts to specify the iterator they support. +How you iterate over the elements of a range depends on its underlying iterator type. Ranges use C++ concepts to specify the iterator they support. In C++20, to say that concept *X* refines concept *Y* means that everything that satisfies concept *Y* also satisfies concept *X*. For example: *car*, *bus*, and *truck* all refine *vehicle*. -Some of the range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the types of containers that they can be applied to. The order +Some of the range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the types of containers that they can be applied to. | Range concept | Description | Supported containers | |--|--|--| -| `std::ranges::output_range` | Can iterate forward. JTW | +| `std::ranges::output_range` | Can iterate forward. | | `std::ranges::input_range` | Can iterate from beginning to end at least once. | `std::forward_list`
`std::unordered_map`
`std::unordered_multimap`
`std::unordered_set`
`std::unordered_multiset`
`basic_istream_view` | | `std::ranges::forward_range` | Can iterate from beginning to end more than once. | `std::forward_list`
`std::unordered_map`
`std::unordered_multimap`
`std::unordered_set`
`std::unordered_multiset` | | `std::ranges::bidirectional_range` | Can iterate forward and backward more than once. | `std::list`
`std::map`
`std::multimap`
`std::multiset`
`std::set`| diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 9679f8cfe4f..70e8f780eef 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -161,6 +161,8 @@ Generally speaking, an iterator has the capability of the iterators that precede The statement "requires `input_range` or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because they are all as capable as `input_range`. +The ranges iterator hierarchy is directly related to the iterator hierarchy. For more information, see [Iterator concepts](iterator-concepts.md). + ## See also [``](ranges.md)\ From 4fc54119c76343124b6b491a1160f4fc06d8c55a Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Thu, 15 Dec 2022 11:25:59 -0800 Subject: [PATCH 12/31] acrolinx --- docs/standard-library/empty-view-class.md | 2 +- docs/standard-library/iterator-concepts.md | 6 +++--- docs/standard-library/iterator-functions.md | 6 +++--- docs/standard-library/iterator.md | 2 +- docs/standard-library/range-adaptors.md | 2 +- docs/standard-library/range-concepts.md | 18 +++++++++--------- docs/standard-library/view-classes.md | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/standard-library/empty-view-class.md b/docs/standard-library/empty-view-class.md index b449412e6b5..67adb0d220a 100644 --- a/docs/standard-library/empty-view-class.md +++ b/docs/standard-library/empty-view-class.md @@ -82,7 +82,7 @@ inline constexpr empty_view empty{}; ### Parameters *`T`*\ - The type of the underlying element, of which there are none. + The type of the underlying element, of which there is none. ### Remarks diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index a70302a47d2..2865e93cd5b 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -7,7 +7,7 @@ helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ra --- # Iterator concepts -Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. +Concepts are a C++20 language feature that constrains template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. Consider the following example, which defines a concept to prevent instantiating a template with a type that doesn't support division: @@ -52,7 +52,7 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Iterator concepts are defined in the `std` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of iterators. They are directly related to the categories of ranges listed under [Range concepts](ranges.md#range-concepts). +There are six categories of iterators. They're directly related to the categories of ranges listed under [Range concepts](ranges.md#range-concepts). The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. @@ -411,7 +411,7 @@ The type to test to see if it's a sentinel for `I`. ### Remarks -A sentinel is a type that can be compared to an iterator to determine if the iterator has reached the end. This concept determines if a type is a sentinel for one of the `input_or_output_iterator` types which includes `input_iterator`, `output_iterator`, `forward_iterator`, `bidirectional_iterator`, `random_access_iterator`, and `contiguous_iterator`. +A sentinel is a type that can be compared to an iterator to determine if the iterator has reached the end. This concept determines if a type is a sentinel for one of the `input_or_output_iterator` types, which includes `input_iterator`, `output_iterator`, `forward_iterator`, `bidirectional_iterator`, `random_access_iterator`, and `contiguous_iterator`. ### Example: `sentinel_for` diff --git a/docs/standard-library/iterator-functions.md b/docs/standard-library/iterator-functions.md index 8bb9b11f764..17de7983ce5 100644 --- a/docs/standard-library/iterator-functions.md +++ b/docs/standard-library/iterator-functions.md @@ -236,7 +236,7 @@ int main() 160 106 80 70 53 40 35 23 20 16 10 8 5 4 2 1 ``` -The function `reverse_sort` supports containers of any kind, in addition to regular arrays, because it calls the non-member version of `begin()`. If `reverse_sort` were coded to use the container member `begin()`: +The function `reverse_sort` supports containers of any kind, in addition to regular arrays, because it calls the non-member version of `begin()`. Coding `reverse_sort` to use the container member `begin()`: ```cpp template @@ -249,7 +249,7 @@ void reverse_sort(C& c) { } ``` -Then sending an array to it would cause this compiler error: +Then sending an array to it, causes this compiler error: ```Output error C2228: left of '.begin' must have class/struct/union @@ -1031,7 +1031,7 @@ The template function returns `next` decremented `off` times. ## `rbegin` -Get an iterator which returns the elements of the container in reverse order. +Get an iterator, which returns the elements of the container in reverse order. ```cpp template constexpr auto rbegin(C& c) -> decltype(c.rbegin()); diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index da8d3769537..42dd088ec86 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -19,7 +19,7 @@ Defines predefined iterators and stream iterators, iterator primitives, and supp Iterators are a generalization of pointers that allow a C++ program to work with different data structures in a uniform way. Instead of operating on specific data types, algorithms operate on a range of values as specified by a kind of iterator. Algorithms can operate on any data structure that satisfies the requirements of the iterator. -In C++20, there are 6 categories of iterators. Iterators are arranged in a hierarchy of capability. Their capabilities are specified by C++20 concepts. For a description of the various iterators and their capabilities, see [Iterator concepts](iterator-concepts.md) +In C++20, there are six categories of iterators. Iterators are arranged in a hierarchy of capability. Their capabilities are specified by C++20 concepts. For a description of the various iterators and their capabilities, see [Iterator concepts](iterator-concepts.md) Visual Studio has added extensions to C++ Standard Library iterators to support debugging for checked and unchecked iterators. For more information, see [Safe Libraries: C++ Standard Library](../standard-library/safe-libraries-cpp-standard-library.md). diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 3e0051157ce..f1a57340402 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -50,7 +50,7 @@ When a range adaptor produces a view, it doesn't incur the cost of transforming Creating a view is preparation to do work in the future. In the previous example, creating the view doesn't result in finding all the elements divisible by three or squaring those elements. Work happens only when you access an element in the view. -Elements of a view are usually the actual elements of the range used to create the view. The view usually doesn't own the elements; it just refers to them. Although ([`owning_view`](owning-view-class.md) is an exception. Changing an element changes that element in the range that the view was created from. The following example shows this behavior: +Elements of a view are usually the actual elements of the range used to create the view. The view usually doesn't own the elements; it just refers to them. Although [`owning_view`](owning-view-class.md) is an exception. Changing an element changes that element in the range that the view was created from. The following example shows this behavior: ```cpp #include diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index acc118c797c..14fabee517b 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -7,7 +7,7 @@ helpviewer_keywords: ["std::ranges [C++], ranges::range", "std::ranges [C++], ra --- # `` concepts -Concepts are a C++20 language feature that constrain template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. +Concepts are a C++20 language feature that constrains template parameters at compile time. They help prevent incorrect template instantiation, specify template argument requirements in a readable form, and provide more succinct template related compiler errors. Consider the following example, which defines a concept to prevent instantiating a template with a type that doesn't support division: @@ -52,7 +52,7 @@ When you pass the compiler switch `/diagnostics:caret` to Visual Studio 2022 ver Range concepts are defined in the `std::ranges` namespace as declared in the `` header file. They're used in the declarations of [range adaptors](range-adaptors.md), [views](view-classes.md), and so on. -There are six categories of ranges. They are related to the categories of iterators listed in [`` concepts](iterator-concepts.md). In order of increasing capability, the categories are: +There are six categories of ranges. They're related to the categories of iterators listed in [`` concepts](iterator-concepts.md). In order of increasing capability, the categories are: | Range concept | Description | |--|--| @@ -63,7 +63,7 @@ There are six categories of ranges. They are related to the categories of iterat | [`random_access_range`](#random_access_range) | Specifies a range that can read and write by index. | | [`contiguous_range`](#contiguous_range) | Specifies a range whose elements are sequential in memory and can be accessed using pointer arithmetic. | -In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. However, an exception is `input_range` which doesn't have the capability of an `output_range` because it can't be written to. +In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. Except `input_range`, which doesn't have the capability of an `output_range` because it can't be written to. Other range concepts include: @@ -94,7 +94,7 @@ The type to test to see if it's a `bidirectional_range`. ### Remarks -This kind of range supports [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) or above. +This kind of range supports [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) or greater. A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. Some examples of a `bidirectional_range` are `std::set`, `std::vector`, and `std::list`. @@ -154,7 +154,7 @@ The type to test to see if it's a `contiguous_range`. ### Remarks -A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. This kind of range supports [`continguous_iterator`](iterator-concepts.md#contiguous_iterator) which is the most flexible of all the iterators. +A `contiguous_range` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. This kind of range supports [`continguous_iterator`](iterator-concepts.md#contiguous_iterator), which is the most flexible of all the iterators. Some examples of a `contiguous_range` are `std::array`, `std::vector`, and `std::string`. @@ -202,7 +202,7 @@ The type to test to see if it's a `forward_range`. ### Remarks -This kind of range supports [`forward_iterator`](iterator-concepts.md#forward_iterator) or above. A `forward_iterator` can iterate over a range multiple times. +This kind of range supports [`forward_iterator`](iterator-concepts.md#forward_iterator) or greater. A `forward_iterator` can iterate over a range multiple times. ## `input_range` @@ -225,7 +225,7 @@ When a type meets the requirements of `input_range`: - The `ranges::begin()` function returns an `input_iterator`. Calling `begin()` more than once on an `input_range` results in undefined behavior. - You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_range` isn't multi-pass. Incrementing an iterator invalidates any copies. - It can be used with `ranges::for_each`. -- It supports [`input_iterator`](iterator-concepts.md#input_iterator) or above. +- It supports [`input_iterator`](iterator-concepts.md#input_iterator) or greater. ## `output_range` @@ -246,7 +246,7 @@ The type of the data to write to the range. ### Remarks -The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. In other words, it supports [`output_iterator`](iterator-concepts.md#output_iterator) or above. +The meaning of `output_iterator, T>` is that the type provides an iterator that can write values of type `T` to a range of type `R`. In other words, it supports [`output_iterator`](iterator-concepts.md#output_iterator) or greater. ## `random_access_range` @@ -265,7 +265,7 @@ The type to test to see if it's a `sized_range`. ### Remarks -This kind of range supports [`random_access_iterator`](iterator-concepts.md#random_access_iterator) or above. A `random_access_range` has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is sortable. +This kind of range supports [`random_access_iterator`](iterator-concepts.md#random_access_iterator) or greater. A `random_access_range` has the capabilities of an `input_range`, `output_range`, `forward_range`, and `bidirectional_range`. A `random_access_range` is sortable. Some examples of a `random_access_range` are `std::vector`, `std::array`, and `std::deque`. diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 70e8f780eef..8e1f8f45e3f 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -7,7 +7,7 @@ helpviewer_keywords: ["RANGES/VIEWS/std", "VIEWS/std"] --- # View classes -A *view* is a lightweight range that refers to elements that it doesn't own (with the exception of [`owning_view`](owning-view-class.md)). A view is typically based on another range and provides a different way of looking at it, whether by transforming or filtering it. For example, [`std::views::filter`](filter-view-class.md) is a view that uses the criteria that you specify to select elements from another range. +A *view* is a lightweight range that refers to elements that it doesn't own (except [`owning_view`](owning-view-class.md)). A view is typically based on another range and provides a different way of looking at it, whether by transforming or filtering it. For example, [`std::views::filter`](filter-view-class.md) is a view that uses the criteria that you specify to select elements from another range. When you access the elements in a view, it's done "lazily" so that work is done only when you get an element. This makes it possible to combine, or *compose*, views without a performance penalty. @@ -157,9 +157,9 @@ In the **Characteristics** section of each view class topic, the iterator catego | [`random_access_range`](range-concepts.md#random_access_range) | Can access the collection with an index; multi-pass. | | [`contiguous_range`](range-concepts.md#contiguous_range) | Can access the collection with an index, and elements are stored contiguously in memory. | -Generally speaking, an iterator has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) has the capabilities of [`forward_range`](range-concepts.md#forward_range), but not vice versa. An exception is `input_range` which doesn't have the capability of `output_range` because you can't write to an `input_range`. +Generally speaking, an iterator has the capability of the iterators that precede it in the table. For example, [`bidirectional_range`](range-concepts.md#bidirectional_range) has the capabilities of [`forward_range`](range-concepts.md#forward_range), but not vice versa. Except `input_range`, which doesn't have the capability of `output_range` because you can't write to an `input_range`. -The statement "requires `input_range` or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because they are all as capable as `input_range`. +The statement "requires `input_range` or higher" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because they're all as capable as `input_range`. The ranges iterator hierarchy is directly related to the iterator hierarchy. For more information, see [Iterator concepts](iterator-concepts.md). From 2b9467fef586ef0ed2164c5b966d3498c9707a09 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Thu, 15 Dec 2022 11:30:33 -0800 Subject: [PATCH 13/31] fix missing codefence --- docs/standard-library/iterator-concepts.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index 2865e93cd5b..6b6a7a7e9a0 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -336,6 +336,7 @@ int main() std::vector v = { 0,1,2,3,4,5 }; std::cout << std::boolalpha << std::output_iterator; // outputs true } +``` ## `random_access_iterator` From 23b7ced266a368b2514d9c82032da250c2a06d6e Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Thu, 15 Dec 2022 13:41:30 -0800 Subject: [PATCH 14/31] fix link --- docs/standard-library/iterator-concepts.md | 32 ++++++++++------------ docs/standard-library/iterator.md | 4 +-- docs/standard-library/view-classes.md | 2 +- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index 6b6a7a7e9a0..eda1168e9e9 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -56,14 +56,18 @@ There are six categories of iterators. They're directly related to the categorie The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. -| Iterator concept | Description | Direction | Read/write | Multi-pass | Example types that use this iterator | +In the following table, "Multi-pass" refers to whether the iterator can revisit the same element more than once. For example, `vector::iterator` is a multi-pass iterator because you can make a copy of the iterator, read the elements in the collection, and then restore the iterator to the value in the copy, and revisit the same elements again. If an iterator is single-pass, you can only visit the elements in the collection once. + +In the following table, "Types" refers to the types of collections/iterators that satisfy the concept. + +| Iterator concept | Description | Direction | Read/write | Multi-pass | Types | |--|--|--|--|--|--| -| [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | Forward | Read or write | no | `std::istream_iterator`, `std::ostream_iterator` | +| [`input_or_output_iterator`](#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | Forward | Read/write | no | `istream_iterator`, `ostream_iterator` | | [`output_iterator`](#output_iterator)C++20 | Test for an iterator that you can write to. | Forward | Write | no | `ostream`, `inserter` | | [`input_iterator`](#input_iterator)C++20 | Test for an iterator that you can read from at least once. | Forward | Read | no | `istream`, `istreambuf_iterator` | -| [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | Forward | Read/write | yes | `vector::iterator`, `list::iterator` | +| [`forward_iterator`](#forward_iterator)C++20 | Test for an iterator that can read (and possibly write) multiple times. | Forward | Read/write | yes | `vector`, `list` | | [`bidirectional_iterator`](#bidirectional_iterator)C++20 | Test for an iterator that can read and write both forwards and backwards. | Forward/backward | Read/write | yes | `list`, `set`, `multiset`, `map`, and `multimap`. | -| [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | Forward/Backward | Read/write | yes | `vector::iterator`, `array::iterator`, `deque::iterator` | +| [`random_access_iterator`](#random_access_iterator)C++20 | Test for an iterator that can read and write by index. | Forward/Backward | Read/write | yes | `vector`, `array`, `deque` | | [`contiguous_iterator`](#contiguous_iterator)C++20 | Test for an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | Forward/backward | Read/write | yes | `array`, `vector` `string`.| Other iterator concepts include: @@ -97,7 +101,7 @@ The iterator to test to see if it's a `bidirectional_iterator`. A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. -Some examples of containers that can be used with a `bidirectional_iterator` are `std::set`, `std::vector`, and `std::list`. +Some examples of containers that can be used with a `bidirectional_iterator` are `set`, `vector`, and `list`. ### Example: `bidirectional_iterator` @@ -139,13 +143,9 @@ template *`I`*\ The type to test to see if it's a `contiguous_iterator`. -The elements of a `contiguous_iterator` are stored sequentially in memory and can be accessed using pointer arithmetic. A `std::array` has a `contiguous_iterator`. - ### Remarks -A `contiguous_iterator` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. - -Some examples of a `contiguous_iterator` are `std::array`, `std::vector`, and `std::string`. +A `contiguous_iterator` can be accessed by pointer arithmetic because the elements are laid out sequentially in memory and are the same size. Some examples of a `contiguous_iterator` are `array`, `vector`, and `string`. ### Example: `contiguous_iterator` @@ -189,7 +189,7 @@ The iterator to test to see if it's a `forward_iterator`. A `forward_iterator` can only move forward. -Some examples of containers that can be used with a `forward_iterator` are `std::unordered_set`, `std::unordered_multiset`, `std::unordered_map`, and `std::unordered_multimap`. +Some examples of containers that can be used with a `forward_iterator` are `unordered_set`, `unordered_multiset`, `unordered_map`, and `unordered_multimap`. ### Example: `forward_iterator` @@ -231,9 +231,7 @@ The type to test to see if it's an `input_iterator`. ### Remarks -When a type meets the requirements of `input_iterator`: - -- Calling `begin()` more than once on an `input_iterator` results in undefined behavior. This implies that if a type only models `input_iterator`, it isn't multi-pass and can read an element only once. Consider reading from standard input (`cin`) for example. In this case, you can only read the current element once and you can't re-read characters you've already read. You can only read an `input_iterator` forward, not backwards. +Calling `begin()` on an `input_iterator` more than once results in undefined behavior. This implies that if a type only models `input_iterator`, it isn't multi-pass and can read an element only once. Consider reading from standard input (`cin`) for example. In this case, you can only read the current element once and you can't re-read characters you've already read. An `input_iterator` only reads forward, not backwards. ### Example: `input_iterator` @@ -368,7 +366,7 @@ The type to test to see if it's a `random_access_iterator`. A `random_access_iterator` has the capabilities of an `input_iterator`, `output_iterator`, `forward_iterator`, and `bidirectional_iterator`. -Some examples of a `random_access_iterator` are `std::vector`, `std::array`, and `std::deque`. +Some examples of a `random_access_iterator` are `vector`, `array`, and `deque`. ### Example: `random_access_iterator` @@ -416,7 +414,7 @@ A sentinel is a type that can be compared to an iterator to determine if the ite ### Example: `sentinel_for` -The following example uses the `sentinel_for` concept to show that `std::vector::iterator` is a sentinel for `vector`: +The following example uses the `sentinel_for` concept to show that `vector::iterator` is a sentinel for `vector`: ```cpp // requires /std:c++20 or later @@ -434,7 +432,7 @@ int main() ## `sized_sentinel_for` -Test that an iterator and its sentinel can be subtracted (using `-`) to find the difference in constant time. +Test that an iterator and its sentinel can be subtracted using `-` to find the difference, in constant time. ```cpp template diff --git a/docs/standard-library/iterator.md b/docs/standard-library/iterator.md index 42dd088ec86..fa1208fc558 100644 --- a/docs/standard-library/iterator.md +++ b/docs/standard-library/iterator.md @@ -89,12 +89,12 @@ Visual Studio has added extensions to C++ Standard Library iterators to support ## Concepts -The following concepts are defined in the `std` namespace. They apply to iterators, and are related to the iterator categories for ranges described in [`` concepts](range-concepts.md). +The following concepts are defined in the `std` namespace. They apply to iterators, and are directly related to the iterator categories for ranges described in [`` concepts](range-concepts.md). | Iterator concept | Description | |--|--| | [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator)C++20 | Specifies an iterator that can read and write both forwards and backwards. | -| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator)C++20 | Specifies an iterator whose elements are sequential in memory and can be accessed using pointer arithmetic. | +| [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator)C++20 | Specifies an iterator whose elements are sequential in memory, and can be accessed using pointer arithmetic. | | [`forward_iterator`](iterator-concepts.md#forward_iterator)C++20 | Specifies an iterator that can read (and possibly write) multiple times. | | [`input_iterator`](iterator-concepts.md#input_iterator)C++20 | Specifies an iterator that you can read from at least once. | | [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator)C++20 | The basis of the iterator concept taxonomy. | diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 8e1f8f45e3f..9774af96665 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -130,7 +130,7 @@ Many of these classes have corresponding [range adaptors](range-adaptors.md) in Each view class topic has a **Characteristics** section after the syntax section. The **Characteristics** section has the following entries: * **Range adaptor**: A link to the range adaptor that creates the view. You typically use a range adaptor to create a view rather than create a view class directly, so it's listed here for convenience. -* **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See [ranges iterator hierarchy](#ranges_iterator_hierarchy) for more information about the kinds of iterators. +* **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See [ranges iterator hierarchy](#ranges-iterator-hierarchy) for more information about the kinds of iterators. * **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a `bidirectional_iterator`, even if the underlying range has a `random_access_iterator`. * **Element type**: The type of the elements that the view's iterator returns. * **Sized**: Whether the view can return the number of elements that it refers to. Not all views can. From ae7ab66f30786bfdfd2c786af0dc81f2ff369ea7 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 16 Dec 2022 11:13:45 -0800 Subject: [PATCH 15/31] add diagrams and crosslink iterator concepts to definitions --- .../standard-library/drop-while-view-class.md | 2 +- docs/standard-library/iterator-concepts.md | 3 + .../media/iterator-hiearchy.svg | 194 ++++++++++++++++++ .../media/ranges-iterator-hiearchy.svg | 153 ++++++++++++++ .../media/src/iterator-hiearchy.vsdx | Bin 0 -> 36687 bytes .../media/src/range-iterator-hiearchy.vsdx | Bin 0 -> 35334 bytes docs/standard-library/range-adaptors.md | 2 +- docs/standard-library/range-concepts.md | 8 +- docs/standard-library/span-class.md | 2 +- docs/standard-library/subrange-class.md | 6 +- docs/standard-library/view-classes.md | 2 +- docs/standard-library/view-interface.md | 4 +- 12 files changed, 364 insertions(+), 12 deletions(-) create mode 100644 docs/standard-library/media/iterator-hiearchy.svg create mode 100644 docs/standard-library/media/ranges-iterator-hiearchy.svg create mode 100644 docs/standard-library/media/src/iterator-hiearchy.vsdx create mode 100644 docs/standard-library/media/src/range-iterator-hiearchy.vsdx diff --git a/docs/standard-library/drop-while-view-class.md b/docs/standard-library/drop-while-view-class.md index 8538b8a36bf..02f2543e1eb 100644 --- a/docs/standard-library/drop-while-view-class.md +++ b/docs/standard-library/drop-while-view-class.md @@ -36,7 +36,7 @@ For a description of the following entries, see [View class characteristics](vie | Characteristic | Description | |--|--| | **Range adaptor** | [`views::drop_while`](range-adaptors.md#drop_while) | -| **Underlying range** | Must satisfy [`forward_range`](range-concepts.md#forward_range) or higher and the underlying range's iterators must model `sized_sentinel_for` | +| **Underlying range** | Must satisfy [`forward_range`](range-concepts.md#forward_range) or higher and the underlying range's iterators must model [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for) | | **Element type** | Same as the underlying range | | **View iterator category** | Same as the underlying range | | **Sized** | Only if the underlying range satisfies [`random_access_range`](range-concepts.md#random_access_range) | diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index eda1168e9e9..d338046ddd7 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -56,6 +56,8 @@ There are six categories of iterators. They're directly related to the categorie The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. +:::image type="content" source="media/iterator-hierarchy.svg" alt-text="Diagram of the iterator hierarchy. input_or_output_iterator is the base. input_iterator and output_iterator are shown as refining input_or_output_iterator. forward_iterator is next and refines both input_iterator and output_iterator. bidirectional_iterator refines forward_iterator. random_access_iterator refines bidirectional_iterator. Finally, contiguous_iterator refines random_access_iterator"::: + In the following table, "Multi-pass" refers to whether the iterator can revisit the same element more than once. For example, `vector::iterator` is a multi-pass iterator because you can make a copy of the iterator, read the elements in the collection, and then restore the iterator to the value in the copy, and revisit the same elements again. If an iterator is single-pass, you can only visit the elements in the collection once. In the following table, "Types" refers to the types of collections/iterators that satisfy the concept. @@ -477,5 +479,6 @@ int main() ## See also +[Range concepts](range-concepts.md)\ [Range adaptors](range-adaptors.md)\ [View classes](view-classes.md) \ No newline at end of file diff --git a/docs/standard-library/media/iterator-hiearchy.svg b/docs/standard-library/media/iterator-hiearchy.svg new file mode 100644 index 00000000000..53cce9376e4 --- /dev/null +++ b/docs/standard-library/media/iterator-hiearchy.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + Rectangle.1 + input_or_output_iterator + + + + + + + input_or_output_iterator + + Rectangle.3 + input_iterator + + + + + + + input_iterator + + Rectangle.4 + output_iterator + + + + + + + output_iterator + + Rectangle.5 + forward_iterator + + + + + + + forward_iterator + + Rectangle.6 + contiguous_iterator + + + + + + + contiguous_iterator + + Rectangle.7 + random_access_iterator + + + + + + + random_access_iterator + + Rectangle.8 + bidirectional_iterator + + + + + + + bidirectional_iterator + + Line Arrow.17 + + + + + + + + + + + Line Arrow.18 + + + + + + + + + + + Line Arrow.20 + + + + + + + + + Line Arrow.21 + + + + + + + + + + + Line Arrow.22 + + + + + + + + + + + Line Arrow.23 + + + + + + + + + + + Line Arrow.24 + + + + + + + + + + + Line Arrow.25 + + + + + + + + + + + diff --git a/docs/standard-library/media/ranges-iterator-hiearchy.svg b/docs/standard-library/media/ranges-iterator-hiearchy.svg new file mode 100644 index 00000000000..858b00f9544 --- /dev/null +++ b/docs/standard-library/media/ranges-iterator-hiearchy.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + Page-1 + + + + Rectangle.3 + input_range + + + + + + + input_range + + Rectangle.4 + output_range + + + + + + + output_range + + Rectangle.5 + forward_range + + + + + + + forward_range + + Rectangle.6 + contiguous_range + + + + + + + contiguous_range + + Rectangle.7 + random_access_range + + + + + + + random_access_range + + Rectangle.8 + bidirectional_range + + + + + + + bidirectional_range + + Line Arrow.17 + + + + + + + + + + + Line Arrow.18 + + + + + + + + + + + Line Arrow.21 + + + + + + + + + + + Line Arrow.22 + + + + + + + + + + + Line Arrow.23 + + + + + + + + + + + diff --git a/docs/standard-library/media/src/iterator-hiearchy.vsdx b/docs/standard-library/media/src/iterator-hiearchy.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..7845c695a9839a0cd1d07b961bbdc70dc4f66719 GIT binary patch literal 36687 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≤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

bdo@UKBJIdV`pzf>^- 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

M)`2tO{@;wQEuSCEt~v0t&XmB0)Za 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 literal 0 HcmV?d00001 diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index f1a57340402..a2265fc22ab 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -268,7 +268,7 @@ An iterator to the element in the range to start with. The element that the iter ### Return value -A [`span`](span-class.md) is returned if `it` is a `contiguous_iterator` for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [`subrange`](subrange-class.md) is returned. +A [`span`](span-class.md) is returned if `it` is a [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator) for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [`subrange`](subrange-class.md) is returned. ### Remarks diff --git a/docs/standard-library/range-concepts.md b/docs/standard-library/range-concepts.md index 14fabee517b..0a3af0164e2 100644 --- a/docs/standard-library/range-concepts.md +++ b/docs/standard-library/range-concepts.md @@ -65,6 +65,8 @@ There are six categories of ranges. They're related to the categories of iterato In the preceding table, concepts are listed in order of increasing capability. A range that meets the requirements of a concept generally meets the requirements of the concepts in the rows that precede it. For example, a `random_access_range` has the capability of a `bidirectional_range`, `forward_range`, `input_range`, and `output_range`. Except `input_range`, which doesn't have the capability of an `output_range` because it can't be written to. +:::image type="content" source="media/ranges-iterator-hiearchy.svg" alt-text="Diagram of the ranges iterator hierarchy. input_range and output_range are the base. forward_range is next and refines both input_range and output_range. bidirectional_range refines forward_range. random_access_range refines bidirectional_range. Finally, contiguous_range refines random_access_range"::: + Other range concepts include: | Range concept | Description | @@ -95,7 +97,7 @@ The type to test to see if it's a `bidirectional_range`. ### Remarks This kind of range supports [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator) or greater. -A `bidirectional_iterator` has the capabilities of a `forward_iterator`, but can also iterate backwards. +A `bidirectional_iterator` has the capabilities of a [`forward_iterator`](iterator-concepts.md#forward_iterator), but can also iterate backwards. Some examples of a `bidirectional_range` are `std::set`, `std::vector`, and `std::list`. @@ -222,10 +224,10 @@ The type to test to see if it's an `input_range`. When a type meets the requirements of `input_range`: -- The `ranges::begin()` function returns an `input_iterator`. Calling `begin()` more than once on an `input_range` results in undefined behavior. +- The `ranges::begin()` function returns an [`input_iterator`](iterator-concepts.md#input_iterator). Calling `begin()` more than once on an `input_range` results in undefined behavior. - You can dereference an `input_iterator` repeatedly, which yields the same value each time. An `input_range` isn't multi-pass. Incrementing an iterator invalidates any copies. - It can be used with `ranges::for_each`. -- It supports [`input_iterator`](iterator-concepts.md#input_iterator) or greater. +- It supports `input_iterator` or greater. ## `output_range` diff --git a/docs/standard-library/span-class.md b/docs/standard-library/span-class.md index 8661c026d95..be60468ddbf 100644 --- a/docs/standard-library/span-class.md +++ b/docs/standard-library/span-class.md @@ -912,7 +912,7 @@ A `span` doesn't free storage for items in the `span` because it doesn't own the |---------|---------| |`span()` | Construct an empty `span`. Only considered during overload resolution when the template parameter `Extent` is `0` or `dynamic_extent`.| |`span(It first, size_type count)` | Construct a `span` from the first `count` elements from iterator `first`. Only considered during overload resolution when template parameter `Extent` isn't `dynamic_extent`. | -|`span(It first, End last)` | Construct a `span` from the elements in iterator `first` until the end `last` is reached. Only considered during overload resolution when template parameter `Extent` isn't `dynamic_extent`. `It` must be a `contiguous_iterator`. | +|`span(It first, End last)` | Construct a `span` from the elements in iterator `first` until the end `last` is reached. Only considered during overload resolution when template parameter `Extent` isn't `dynamic_extent`. `It` must be a [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator). | |`span(array& arr) noexcept;`

`span(const array& arr) noexcept;`

`span(type_identity_t (&arr)[N]) noexcept;` | Construct a `span` from `N` elements of the specified array. Only considered during overload resolution when template parameter `Extent` is `dynamic_extent` or equals `N`. | |`span(R&& r)` | Construct a `span` from a range. Only participates in overload resolution if template parameter `Extent` isn't `dynamic_extent`.| |`span(const span& other)` | The compiler-generated copy constructor. A shallow copy of the data pointer is safe because the `span` doesn't allocate the memory to hold the elements. | diff --git a/docs/standard-library/subrange-class.md b/docs/standard-library/subrange-class.md index 8eac6cfa217..b0fe6497e74 100644 --- a/docs/standard-library/subrange-class.md +++ b/docs/standard-library/subrange-class.md @@ -21,13 +21,13 @@ class subrange : public view_interface> ### Template parameters *`I`*\ - The begin iterator type. The `input_or_output_iterator` concept ensures that *`I`* is an iterator that can read all of the elements. + The begin iterator type. The [`input_or_output_iterator`](iterator-concepts.md#input_or_output_iterator) concept ensures that *`I`* is an iterator that can read all of the elements. *`K`*\ The kind of subrange: Use `subrange_kind::sized` to specify a sized subrange. Use `sized_sentinel_for` if the iterator and sentinel can be subtracted to yield the size. The requirement `subrange_kind::sized || !sized_sentinel_for` stores the size locally in the subrange object, and requires that you construct the subrange either using the constructor that takes a [`sized_range`](range-concepts.md#sized_range) (for which you would specify `subrange_kind::sized` here) or via the constructor that takes an `iterator`, `sentinel`, and `size` (so you would specify `sized_sentinel_for` here). *`S`*\ - The end iterator type. The `sized_sentinel_for` concept ensures that *`S`* can be used as a sentinel for *`I`* and that it's possible to compute the distance between the sentinel and the current iterator position in *`I`* in constant time. + The end iterator type. The [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for) concept ensures that *`S`* can be used as a sentinel for *`I`* and that it's possible to compute the distance between the sentinel and the current iterator position in *`I`* in constant time. ## View characteristics @@ -105,7 +105,7 @@ Iterator that points to the first element in the subrange. Sentinel that points to the end of the subrange. The element it points to isn't included in the subrange. *`sizeHint`*\ -The size of the range in elements. This is used to optimize the `size` member function and is necessary if you want to make a sized `subrange` from an iterator and sentinel whose types don't model `sized_sentinel_for`. +The size of the range in elements. This is used to optimize the `size` member function and is necessary if you want to make a sized `subrange` from an iterator and sentinel whose types don't model [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for). For information about template parameter types, see [Template parameters](#template-parameters). diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 9774af96665..70eef446d50 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -131,7 +131,7 @@ Each view class topic has a **Characteristics** section after the syntax section * **Range adaptor**: A link to the range adaptor that creates the view. You typically use a range adaptor to create a view rather than create a view class directly, so it's listed here for convenience. * **Underlying range**: Views have different iterator requirements for the kind of underlying range that they can use. See [ranges iterator hierarchy](#ranges-iterator-hierarchy) for more information about the kinds of iterators. -* **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a `bidirectional_iterator`, even if the underlying range has a `random_access_iterator`. +* **View iterator category**: The iterator category of the view. When a view adapts a range, the iterator type for the view is typically the same as the iterator type of the underlying range. However, it might be different for some views. For example, `reverse_view` has a [`bidirectional_iterator`](iterator-concepts.md#bidirectional_iterator), even if the underlying range has a [`random_access_iterator`](iterator-concepts.md#random_access_iterator). * **Element type**: The type of the elements that the view's iterator returns. * **Sized**: Whether the view can return the number of elements that it refers to. Not all views can. * **Common range**: Specifies whether the view is a [`common_range`](range-concepts.md#common_range), which means that the begin iterator and sentinel types are the same. Common ranges are useful for pre-range code that works with iterator pairs. An example is iterator pair constructors for a sequence container, like `vector(ranges::begin(x), ranges::end(x))`. diff --git a/docs/standard-library/view-interface.md b/docs/standard-library/view-interface.md index 1799109b400..c165ead51ec 100644 --- a/docs/standard-library/view-interface.md +++ b/docs/standard-library/view-interface.md @@ -94,7 +94,7 @@ A pointer to the first element in the derived view. ### Remarks -The iterator for the derived view must satisfy `contiguous_iterator`. +The iterator for the derived view must satisfy [`contiguous_iterator`](iterator-concepts.md#contiguous_iterator). ## `empty` @@ -164,7 +164,7 @@ The number of elements in the derived view. ### Remarks -The iterator for the derived view must satisfy `sized_sentinel_for`. +The iterator for the derived view must satisfy [`sized_sentinel_for`](iterator-concepts.md#sized_sentinel_for). ## `operator[]` From e8d2e60432650db131dd15d80c258d74f489f324 Mon Sep 17 00:00:00 2001 From: TylerMSFT Date: Fri, 16 Dec 2022 14:30:42 -0800 Subject: [PATCH 16/31] adjust image size --- docs/standard-library/iterator-concepts.md | 2 +- .../media/iterator-hiearchy.svg | 120 +++++++++--------- .../media/ranges-iterator-hiearchy.svg | 92 +++++++------- .../media/src/iterator-hiearchy.vsdx | Bin 36687 -> 36533 bytes .../media/src/range-iterator-hiearchy.vsdx | Bin 35334 -> 35375 bytes 5 files changed, 107 insertions(+), 107 deletions(-) diff --git a/docs/standard-library/iterator-concepts.md b/docs/standard-library/iterator-concepts.md index d338046ddd7..982c1f08655 100644 --- a/docs/standard-library/iterator-concepts.md +++ b/docs/standard-library/iterator-concepts.md @@ -56,7 +56,7 @@ There are six categories of iterators. They're directly related to the categorie The following iterator concepts are listed in order of increasing capability. `input_or_output_iterator` is at the low end of the capability hierarchy, and `contiguous_iterator` is at the high end. Iterators higher in the hierarchy can generally be used in place of those that are lower, but not vice-versa. For example, a `random_access_iterator` iterator can be used in place of a `forward_iterator`, but not the other way around. An exception is `input_iterator`, which can't be used in place of `output_iterator` because it can't write. -:::image type="content" source="media/iterator-hierarchy.svg" alt-text="Diagram of the iterator hierarchy. input_or_output_iterator is the base. input_iterator and output_iterator are shown as refining input_or_output_iterator. forward_iterator is next and refines both input_iterator and output_iterator. bidirectional_iterator refines forward_iterator. random_access_iterator refines bidirectional_iterator. Finally, contiguous_iterator refines random_access_iterator"::: +:::image type="content" source="media/iterator-hiearchy.svg" alt-text="Diagram of the iterator hierarchy. input_or_output_iterator is the base. input_iterator and output_iterator are shown as refining input_or_output_iterator. forward_iterator is next and refines both input_iterator and output_iterator. bidirectional_iterator refines forward_iterator. random_access_iterator refines bidirectional_iterator. Finally, contiguous_iterator refines random_access_iterator"::: In the following table, "Multi-pass" refers to whether the iterator can revisit the same element more than once. For example, `vector::iterator` is a multi-pass iterator because you can make a copy of the iterator, read the elements in the collection, and then restore the iterator to the value in the copy, and revisit the same elements again. If an iterator is single-pass, you can only visit the elements in the collection once. diff --git a/docs/standard-library/media/iterator-hiearchy.svg b/docs/standard-library/media/iterator-hiearchy.svg index 53cce9376e4..8c0f628d187 100644 --- a/docs/standard-library/media/iterator-hiearchy.svg +++ b/docs/standard-library/media/iterator-hiearchy.svg @@ -2,8 +2,8 @@ + xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="5.1875in" height="8.6875in" + viewBox="0 0 373.5 625.5" xml:space="preserve" color-interpolation-filters="sRGB" class="st5" style="background-color: white"> @@ -34,161 +34,161 @@ Page-1 - + Rectangle.1 input_or_output_iterator - - - input_or_output_iterator - + + + input_or_output_iterator + Rectangle.3 input_iterator - - - input_iterator - + + + input_iterator + Rectangle.4 output_iterator - - - output_iterator - + + + output_iterator + Rectangle.5 forward_iterator - - - forward_iterator - + + + forward_iterator + Rectangle.6 contiguous_iterator - - - contiguous_iterator - + + + contiguous_iterator + Rectangle.7 random_access_iterator - - - random_access_iterator - + + + random_access_iterator + Rectangle.8 bidirectional_iterator - - - bidirectional_iterator - + + + bidirectional_iterator + Line Arrow.17 - - - + + + - + Line Arrow.18 - - - + + + - + Line Arrow.20 - + - + Line Arrow.21 - - - + + + - + Line Arrow.22 - - - + + + - + Line Arrow.23 - - - + + + - + Line Arrow.24 - - - + + + - + Line Arrow.25 - - - + + + diff --git a/docs/standard-library/media/ranges-iterator-hiearchy.svg b/docs/standard-library/media/ranges-iterator-hiearchy.svg index 858b00f9544..ccfc1cec19d 100644 --- a/docs/standard-library/media/ranges-iterator-hiearchy.svg +++ b/docs/standard-library/media/ranges-iterator-hiearchy.svg @@ -1,8 +1,8 @@ - + @@ -34,120 +34,120 @@ Page-1 - + Rectangle.3 input_range - - - input_range - + + + input_range + Rectangle.4 output_range - - - output_range - + + + output_range + Rectangle.5 forward_range - - - forward_range - + + + forward_range + Rectangle.6 contiguous_range - - - contiguous_range - + + + contiguous_range + Rectangle.7 random_access_range - - - random_access_range - + + + random_access_range + Rectangle.8 bidirectional_range - - - bidirectional_range - + + + bidirectional_range + Line Arrow.17 - - - + + + - + Line Arrow.18 - - - + + + - + Line Arrow.21 - - - + + + - + Line Arrow.22 - - - + + + - + Line Arrow.23 - - - + + + diff --git a/docs/standard-library/media/src/iterator-hiearchy.vsdx b/docs/standard-library/media/src/iterator-hiearchy.vsdx index 7845c695a9839a0cd1d07b961bbdc70dc4f66719..451f81a094a0edb4abf7c27f6d3fd4351121148f 100644 GIT binary patch delta 7787 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 diff --git a/docs/standard-library/media/src/range-iterator-hiearchy.vsdx b/docs/standard-library/media/src/range-iterator-hiearchy.vsdx index 7de4e326b43f7846287d7e5ef29738bbf4f38c73..0166f2d2488f82373ff87f35a346e0aafb119f46 100644 GIT binary patch delta 4430 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 delta 4385 zcmY*dXHXN2vJE{%sx;|Rq(piNy^DYb5F~&!=@23Gju7d+h9*ssrhp2BA_#&+R6r02 zJra7C5QDUjcKv)aci!D!XLio+o*%nAv->uWJTZ^FQ2>!ol)ZG!-ahBWP6hTE5`DimWaJw zEP+A#nLGiZ4HwbZR(%cmrF~1z-I+JLPgpc+**;Sf$%P+P^kl3|U@&|H)g(soR%e^d z4_a4M6{NuR<@Vij8-Zu^de9yuju3R7E~hj2o+3ENcKte&QVzKCc6*hL6%z|58z(UC z`flJuvRZ1`cHY`t1$~f-5YX_AcHA6*QzakoeU<5(i;n!eE6HrpQYD~d=}I2tx@fegp}HHgw5P$6=*>_+ z=0{f=nP&c#k-dZ!o{iQ!Tb~Ve+?jZXiLSTOqQ{24hhC*$|H#{JTSnj}%aU4L73+&w zZk8TMNzxo<*Qza=kQAO)^M!$g^9x@NxA#31HesE2&N$;|I;63D&ok(~{c7rgLsn5r zo`x(7sF?p@JAB0L_YONUAT!^bYR2_#;ZS&)C%=k#z=+@@d|G$OybD}QcH|qO2>W4V z$9(?1hX3LFCpVkcBU9(zQr6pa`qHEk%l!ht z18gfH_yJ~?^KIV`{{H+?3ih+@NF&rV{8#F((jE73I2*)Qn|-`wSq7}!`sNszdYS62 z(9krpMbK8m42<2Tjg(T0DxHYCADlLSGw_J_pVMhx|;)SWYsN}D;qNvS*vL)3WwPJ`4P3pM_@FTn)HDj$2gQ7SUK&XTk6YMEOYylso7J|zc?cnnooNEb0*%dDPo}Quiu;~Id|ER@#3(!3&AJZ8Z)GmS1eWzy z7Z4S;OfRhWuOYfvsY@E->~oDGOMa^JOIF#ZUu9ho+9ECn?C#z(KPxYbwl?fkP}^_Y ze47vyb2f3sid&e&E#t-73PZfx)v8&fhqMuMI*g*iz!UwnOtNbKdRMMH(#315SbX@E z=?C{`GtKq534@2RB|&9TH3QVM>-Se#$Q9us&DkaxMc57C7zb;^6kJ3*ht1eOh-6S4 zJWg?tCcWAr_QFxCVPI@7O@p76a#!lb9vWMpP{mYS-uu{tKC269Oq68! zs$*Z1Rbp4C%SLm_UfsOSwQA~~sS*?zCL{e>n^6RWdFHf*`W9?fI$qkMrx8u zp8{9d;JLn2Ir;f`1<=y%+4>&PtGzCNf427mQnbb`O8!I3BD zT0a64#7JO~_}pxd6IPGQmBb;}nGmy(#2M@10%p$LM=VlfdJ$oZdm!{MW1L@Tp~II& z6{avu_{E8OAWPM=n1czDyguia$8*CU-#44?qOd(KOSO1YijAZog2A%7Rn^7_`kPh`gcQ~`xw_~U(<0$=A>Up(krb|W z?BUjrXLG1CZ5FzZYxo~YB-V=$8d_24SH9zdh16iML1BHh69ZV*mxo;%8H_RUj=>!B zH_k^syDOKxNDqSCQ%FURiM}zbxo6BAHfVCXOB1eitVCgfrA-Agwq}eW499!UH)%n! z3QA*#bNf+wKxLk!C8S@f-1w6Am>9#CB4-Q=BQ7+L!VKsgtRDKFE<8KGejxddcKM8X z8SxLT!LBn$KHVp)2Ni;1dahTJp%#49Q?5fT*Etff+O;08&J_(d8_!rfYQax)%w31g zI${@AENsf{bB%4A?C(xX;1qc{S{hh*)|4-_>*b+{vnHmEpAR3QauPNG}!Kw}Dorh#SI58tS zSm!sNs^W|b{2Og_Vi`AX?w5`oOb(Eif3JL5NgMp}sTlIuz{+>v}M_PsUhrtS3 zscp)LlHiP^qo2qq9)pDkY0F}Bw|?Ci5v;@#sWn`U=`u?3D>&O3$1~Obx-FIjbn#=I zyLiJ!a1g|Dl9%*l&DEul5#IXt^oV_euhF;Su<>=tjki+Q@#)*HQu*%Wan1-d_zU9+ z)Sc}skDRr9CM4S)BMLJFW8Qj=XRYC=wMdGX=GGso-bm5lgC%B@vqtldRuz@iyIP0l zNPD`Prz27ZFO)NPJ=^YdCJU~O8cB1pd#PX@TzL!42SVEbkx>0JAN~z9|Hlx*ba9Z8^%0FzbCWbz;ssv$SJV_)pwPm3sr? z<5)w-KJJLgqE>ZsIhy40)~-OR`5TqlSM^y!MkRI7Ef(vQ+bjnbE;Fxw9A<2A4q@|P zmoy9r8LNScAlW3nB|J69Ew~Qb#(2N+$@%r|Mx;)j6oJxAC@U!>R!p*n+^qARxINu1 zH6wGnTV=Gjj;PJ>Bah6*JbK!g^F)tRPO#>!<+b2}XY;KkBZXnBJr)_#twpM|XSa}cjg}(a?7vnw{mvfcYf9W^6 z--dJ`HyKa1SmLw)@kv9l0nQ+VzG`(sI`toST@kkbL8-}95=o0rih;|rnf%eb<*YnA z5a+B6H&Iqu5*96;rB7bV3F z!-EMHlM5yj-KhY8$#!$*f}^8rc}i$aJhBo+OcY(oyZ4X0sw%wchs}f5OcQW3fvc^) zuFk9D4dN9MJQEEMD9!uz%VJc_D*`BqL)wP?XauKJ^<54L^tkY za?fe^mh&g$eir@l@9!130LVeuYJ^ygd*9j}irW-`0k}0<j3AAEE+8#Q<4Uk}w)6fYV<=Y#Cl@zFN%t$~q?k9Hk029oNv7%wSM0yM1X6B{5I)sCf|Nf4Ua&X5fGn>*o`D}zl8=+o^ejjr-(tsCpJeeGKBUEmeP^II>^eu;8=elf6ncipc& z*K)qHow^uGp;bP-%;2-jl8IsHP@>*WYQ3N}z`l9jp5@RuvM+A)EvUkogj95?;%3U1Liig z(caD4+%CW_L$9?K95oeJ#Qk>*6T|D>l6H$pj=?uikvHbn+yjrYFV!addR|TaW8&U} z&UTREr3w-5EPaZ`L`sq&sSX(u37M;|UN!>$jNB1(PsoFFoRy57d0)4=8h*3uiQ?=C zVR6(abuAJx9XASBIBg`5_Qhg=-#)|HCcrs)~Tceh3kLLwwa zwhKKyoEDDKqVwmTUtGC3-r0!aQfwz|=2Khxq!)NL#ROm$vVu~Rw2(S0MdcLWO#moL ztiB>9d-sr?mu?G5vQUY*pwrunO9{G^5PTBzGHy5fV%1RVZg!^`^ImK)u*NRcxh$>T zuHmM?q*Vgza;R>3s%P@*>(WWP=H`E6d4Pqg=H^eup`j2O?!lyA)e+&(TuB^gFk2k;$l+<6x?0-LS%vZC8Gr`lfx3H zgnBu;q%sJK@1KIpJvjCs6r&BNsD$v61R#WwoC00S5x+}8EFKw_m8lxE&ViLK0ZN-F zQN&*#A6{{AsQ?xvW;)6NXsRE5Z+4CDRX}NUfBSuBfND6851HECKa{(wynd47Tq8lb zG&-1N?*C}2U3qjhT=Zc2YwSkh_Ns`+bmx!JOIj`N8?Y*1uZMb3|1SUoH1C}}Ht}#G z=#=m^-UT?uI=t?a_n55mgZJ%TN6txu1)r(3Fm8?Nfqn2D6s!g65Oi!54m+312S(N7 ze8-Ta^MZ$8-ELUMuF`j`bb*E%a*yjAl0F2BV&TJEITrofhN0HqC`VYOxXP3Tx;i@p zm4b3MJh3;QYV3IU>ozY*|nZ(BP_f!J{0CE-p z0Na1L|AIL)6r(u@iaZ%i-e>ct=rt6-EeLflnTh-FHvIFaXrclDnExkc5EYrMNrpgm zChL(;d!jCrb;;;ax+&uSH|!|C6gIL%RAP!InI)<}MTq;~2J<2V0Ng160G9tr Date: Fri, 16 Dec 2022 14:42:39 -0800 Subject: [PATCH 17/31] size --- .../media/ranges-iterator-hiearchy.svg | 113 +++++------------- .../media/src/range-iterator-hiearchy.vsdx | Bin 35375 -> 35720 bytes 2 files changed, 31 insertions(+), 82 deletions(-) diff --git a/docs/standard-library/media/ranges-iterator-hiearchy.svg b/docs/standard-library/media/ranges-iterator-hiearchy.svg index ccfc1cec19d..f169b4aa1d4 100644 --- a/docs/standard-library/media/ranges-iterator-hiearchy.svg +++ b/docs/standard-library/media/ranges-iterator-hiearchy.svg @@ -2,14 +2,9 @@ - - - - - - + xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="2.42083in" height="5.58333in" + viewBox="0 0 174.3 402" xml:space="preserve" color-interpolation-filters="sRGB" class="st5" style="background-color: white"> +