From f08a8c36dde2cc39b8a00fa1f33b8e1224e18c4d Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Wed, 26 Oct 2022 18:03:16 -0500 Subject: [PATCH 1/6] edit pass: range-adaptor-and-view-classes-topics --- docs/standard-library/range-adaptors.md | 355 +++++++++++++----------- 1 file changed, 186 insertions(+), 169 deletions(-) diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 086889545a6..5c76824989c 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -1,17 +1,22 @@ --- -description: "Learn more about range adaptors, which create views on ranges." -title: "Range adaptors" +description: "Learn more about range adapters, which create views on ranges." +title: "Range adapters" ms.date: 10/19/2022 f1_keywords: ["ranges/std::all", "ranges/std::all_t", "ranges/std::common", "ranges/std::counted", "ranges/std::drop", "ranges/std::drop_while", "ranges/std::elements", "ranges/std::filter", "ranges/std::iota", "ranges/std::join", "ranges/std::keys", "ranges/std::lazy_split", "ranges/std::reverse", "ranges/std::split", "ranges/std::subrange", "ranges/std::take", "ranges/std::take_while", "ranges/std::transform"] helpviewer_keywords: ["std::ranges [C++], all", "std::ranges [C++], all_t", "std::ranges [C++], common", "std::ranges [C++], counted", "std::ranges [C++], drop", "std::ranges [C++], drop_while", "std::ranges [C++], elements", "std::ranges [C++], filter", "std::ranges [C++], iota", "std::ranges [C++], join", "std::ranges [C++], keys", "std::ranges [C++], lazy_split", "std::ranges [C++], reverse", "std::ranges [C++], split", "std::ranges [C++], subrange", "std::ranges [C++], take", "std::ranges [C++], take_while", "std::ranges [C++], transform"] --- -# Range adaptors +# Range adapters -Range adaptors create a *view* (one of the [view classes](view-classes.md) in the `std::views` namespace) from a range. Prefer using an adaptor in `std::ranges::views` instead of creating the view types directly. The adaptors are the intended way to access views, are easier to use, and in some cases are more efficient than creating instances of the view types directly. +Range adapters 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 adapter in `std::ranges::views` instead of creating the view types directly. The adapters 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 consist of only certain elements from a range, or it can represent a transformation of elements from a range, or it can be the reverse of, or only the first `n` elements of, a range, and so on. It can also be the result of a combination of those things. +A *view* is a lightweight object that refers to elements from a range. A view can: -A view is cheap, O(1), to copy, assign, and destroy--no matter how many elements are involved. Consider the following example: +- Consist of only certain elements from a range. +- Represent a transformation of elements from a range. +- Be the reverse of, or only the first `n` elements of, a range. +- Be a combination of the preceding things. + +A view is cheap, `O(1)`, to copy, assign, and destroy--no matter how many elements are involved. Consider the following example: ```cpp // requires /std:c++20 or later @@ -39,11 +44,13 @@ int main() 0 9 36 81 ``` -The first range adaptor, `std::views::filter` provides a view that contains the elements from `input` that are divisible by three. The other range adaptor, `std::views::transform`, takes the view containing the elements divisible by three, and provides a view of the square of those elements. +The first range adapter, `std::views::filter`, provides a view that contains the elements from `input` that are divisible by three. The other range adapter, `std::views::transform`, takes the view that contains the elements divisible by three and provides a view of the square of those elements. + +When a range adapter 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. -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 only paid 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, nor does it square the elements it finds. That work only happens when you access an element in the view. +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. -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 (`owning_view` is an exception), it just refers to them. Changing an element changes that element in the range the view was created from. The following example shows this behavior: +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` 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: ```cpp #include @@ -70,41 +77,45 @@ int main() } ``` -Range adaptors come in many forms. There are range adaptors that allow you to produce a view by filtering another range based on a predicate (`view::filter`), transforming the elements in a range (`view::transform`), splitting a range (`view::split`), and more. +Range adapters come in many forms. For example, there are range adapters that allow you to produce a view by: + +- Filtering another range based on a predicate (`view::filter`). +- Transforming the elements in a range (`view::transform`). +- Splitting a range (`view::split`). -Range adaptors can be chained together (composed), which is where the power and flexibility of ranges is most apparent. Composing range adaptors allows you to overcome a core problem with the previous STL algorithms, which is that they aren't easy to chain together (compose). +Range adapters can be chained together (composed). That's where the power and flexibility of ranges is most apparent. Composing range adapters allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms, which is that they aren't easy to chain together. -The following range adaptors are available in the `std::views` namespace. The `std::views`namespace is a convenience alias for `std::ranges::views`. +The following range adapters are available in the `std::views` namespace. The `std::views`namespace is a convenience alias for `std::ranges::views`. -| **Range adaptor** | **Description** | +| **Range adapter** | **Description** | |--|--| | [`all`](#all)C++20 | Create a view that refers to a range and its elements. | | [`common`](#common)C++20 | Create a view that has the same iterator and sentinel types from a range that doesn't. | | [`counted`](#counted)C++20 | Create a view of the first *n* elements of a range, starting from the specified location. | | [`drop`](#drop)C++20 | Create a view from another view, skipping the specified number of elements from the front. | -| [`drop_while`](#drop_while)C++20 | Create a view that contains the elements of a range that remain once the leading elements that match the specified condition are dropped. | +| [`drop_while`](#drop_while)C++20 | Create a view that contains the elements of a range that remain after the leading elements that match the specified condition are dropped. | | [`elements`](#elements)C++20 | Create a view of the selected index into each tuple-like value in a range. | | [`filter`](#filter)C++20 | Create a view that contains the elements of a range that match the specified condition. | | [`iota`](#iota)C++20 | Create a view that contains a sequence of increasing values. | | [`keys`](#keys)C++20 | Create a view of the first index into each tuple-like value in a collection. | | [`lazy_split`](#lazy_split)C++20 | Split a view into subranges based on a delimiter. | | [`reverse`](#reverse)C++20 | Create a view of the elements of a range in reverse order. | -| [`single`](#single)C++20 | Create a view containing one element. | +| [`single`](#single)C++20 | Create a view that contains one element. | | [`split`](#split)C++20 | Split a view into subranges based on a delimiter. | -| [`take`](#take)C++20 | Create a view of the first *N* elements from another view. | +| [`take`](#take)C++20 | Create a view of the first *n* elements from another view. | | [`take_while`](#take_while)C++20 | Create a view that contains the leading elements of a range that match the specified condition. | | [`transform`](#transform)C++20 | Create a view of transformed elements from another view. | | [`values`](#values)C++20 | Create a view of the second index into each tuple-like value in a collection. | -In the previous table, a range adaptor is typically described as taking a range and producing a view. To be precise, range adaptors have a range argument that accepts one of the following: +In the previous table, a range adapter is typically described as taking a range and producing a view. To be precise, range adapters have a range argument that accepts one of the following: -- The cv-unqualified type models `view` and the argument is an rvalue or is copyable. -- When you pass the argument as an lvalue, it must model `range` and live as long as the view. -- When you pass the argument as an rvalue, such as when calling [`owning_view`](owning-view-class.md), it must model `range` and `movable`. +- The `cv-unqualified` type models `view`, and the argument is an `rvalue` or is copyable. +- When you pass the argument as an `lvalue`, it must model `range` and live as long as the view. +- When you pass the argument as an `rvalue`, such as when calling [`owning_view`](owning-view-class.md), it must model `range` and `movable`. -Range adaptor functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. +Range adapter functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. -You can pass range adaptors and the result of pipe operations (`|`) to code that expects function objects. In the following example, the view created by the `split` range adaptor is passed to the `transform` range adaptor as if by function a call because the `transform` range adaptor is a function object. +You can pass range adapters and the result of pipe operations (`|`) to code that expects function objects. In the following example, the view created by the `split` range adapter is passed to the `transform` range adapter as if by a function call, because the `transform` range adapter is a function object. ```cpp std::map x = {{0, "Hello, world"}, {42, "Goodbye, world"}}; @@ -124,26 +135,27 @@ constexpr ranges::view auto all(R&& rg) const noexcept; ### Parameters -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range to create the view from. ### Return value -- If *`rg`* is already a view, a copy of *`rg`*. -- If *`rg`* is a non-view lvalue, a [`ref_view`](ref-view-class.md) that refers to *`rg`* (the lifetime of the view is tied to the lifetime of *`rg`*). -- If *`rg`* is a non-view rvalue such as a temporary object, or is the result of passing the range to `std::move`, an [`owning_view`](owning-view-class.md). +- If `rg` is already a view, a copy of `rg`. +- If `rg` is a non-view lvalue, a [`ref_view`](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) +- If `rg` is a non-view `rvalue` such as a temporary object, or is the result of passing the range to `std::move`, an [`owning_view`](owning-view-class.md). Use `std::views::all_t` to get the type of the returned view. ### Remarks -This range adaptor is the best way to convert a range into a view. One reason to create a view from a range is to pass it by value at low cost if passing the range by value could be expensive.\ -Getting a view for a range is a useful alternative to passing a heavyweight range by value because views are inexpensive to create, copy, and destroy. A possible exception is the `owning_view`, which is a view that owns the underlying range. +This range adapter is the best way to convert a range into a view. One reason to create a view from a range is to pass it by value at low cost if passing the range by value could be expensive. -In general, the worst case scenario for destroying a view has O(N) complexity for the number of elements in the range. Even if you destroy `K` copies of view with `N` elements, the total complexity is still O(N) because the underlying range is destroyed only once. +Getting a view for a range is a useful alternative to passing a heavyweight range by value because views are inexpensive to create, copy, and destroy. A possible exception is `owning_view`, which is a view that owns the underlying range. + +In general, the worst case scenario for destroying a view has `O(N)` complexity for the number of elements in the range. Even if you destroy `K` copies of view with `N` elements, the total complexity is still `O(N)` because the underlying range is destroyed only once. ### Example: `all` @@ -184,20 +196,20 @@ constexpr ranges::view auto common(R&& rg) const noexcept; ### Parameters -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range to create the view from. ### Return value -- `views::all(rg)` if *`rg`* is a range with the same iterator and sentinel type. -- [`common_view(views::all(rg))`](common-view-class.md) if *`rg`* has different iterator and sentinel types. +- `views::all(rg)` if `rg` is a range with the same iterator and sentinel type. +- [`common_view(views::all(rg))`](common-view-class.md) if `rg` has different iterator and sentinel types. ### Remarks -When an API requires the begin iterator and end sentinel have the same type, and the view that you're using doesn't meet that requirement, or you don't know if it does, use this range adaptor to create a `common_view`. It guarantees that the type of the begin iterator and sentinel are the same. +When an API requires the begin iterator and end sentinel to have the same type, and the view that you're using doesn't meet that requirement (or you don't know if it does), use this range adapter to create a `common_view`. It guarantees that the type of the begin iterator and the type of the end sentinel are the same. ### Example: `common` @@ -213,7 +225,7 @@ int main() std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9}; auto firstFive = std::views::take(lst, 5); - // firstFive.begin(), firstFive.end() have different types: counted_iterator vs default_sentinel + // firstFive.begin(), firstFive.end() have different types: counted_iterator versus default_sentinel // auto r = std::accumulate(firstFive.begin(), firstFive.end(), 0); // Error: accumulate() requires firstFive.begin() and firstFive.end() types to be the same. auto common = std::views::common(firstFive); // create a common_view that has the same begin/end iterator types @@ -227,7 +239,7 @@ int main() ## `counted` - Create a view of the first *`count`* elements of a range, starting from the specified location. +Create a view of the first `count` elements of a range, starting from the specified location. ```cpp template @@ -236,29 +248,30 @@ constexpr auto counted(Iterator&& it, iter_difference_t count); ### Parameters -*`DifferenceType`*\ +`DifferenceType`\ The type of the count. -*`Iterator`*\ +`Iterator`\ The type of the iterator. -*`count`*\ +`count`\ The number of elements to include in the view. Must be non-negative. - If `count == 0`, an empty [`span`](span-class.md) is returned. -- If *`count`* is greater than the number of elements in the range, the behavior is undefined. +- If `count` is greater than the number of elements in the range, the behavior is undefined. -*`it`*\ -An iterator to the element in the range to start with. The element the iterator points to is included in the created view. +`it`\ +An iterator to the element in the range to start with. The element that the iterator points to is included in the created view. ### 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` for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [`subrange`](subrange-class.md) is returned. ### Remarks -The included elements are `[it, count)`.\ -Once the view is created, the number of elements in the view stays the same even if the range it was created from changes. However, if the underlying range changes, accessing elements from the view may result in undefined behavior. +The included elements are `[it, count)`. + +After the view is created, the number of elements in the view stays the same, even if the range that it was created from changes. However, if the underlying range changes, accessing elements from the view might result in undefined behavior. ### Example: `counted` @@ -297,7 +310,7 @@ Hi ## `drop` -Create a view that excludes the first *N* elements of a range. +Create a view that excludes the first *n* elements of a range. ```cpp 1) template @@ -309,37 +322,38 @@ constexpr /* range closure object */ drop(DifferenceType&& count); ### Parameters -*`DifferenceType`*\ +`DifferenceType`\ The type that describes the number of elements to skip. -*`count`*\ -The number of elements to drop from the front of *`rg`*. Must be non-negative. -- If `count == 0`, all the elements in *`rg`* are returned. -- If *`count`* is greater than the number of elements in *`rg`*, then an empty view is returned. +`count`\ +The number of elements to drop from the front of `rg`. Must be non-negative. +- If `count == 0`, all the elements in `rg` are returned. +- If `count` is greater than the number of elements in `rg`, an empty view is returned. -*`R`*\ +`R`\ The type of the range. -*`rg`*\ +`rg`\ The range used to create the view. ### Return value -A view of the underlying range, with the specified number of elements dropped from the front.\ -If you specify more elements to drop than exist in the underlying range, then an [`empty_view`](empty-view-class.md) is returned. +A view of the underlying range, with the specified number of elements dropped from the front. + +If you specify more elements to drop than exist in the underlying range, an [`empty_view`](empty-view-class.md) is returned. The returned view is typically, but not always, a specialization of [`drop_view`](drop-view-class.md). That is: -- If `V` is a specialization of [`empty_view`](empty-view-class.md), or a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md) or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- If `V` is a specialization of [`empty_view`](empty-view-class.md) or a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. - Otherwise, the result is a [`drop_view`](drop-view-class.md). ### Remarks -Once created, the number of elements in the view stays the same even if the view it was created from changes. However, if the underlying view changes, accessing elements in the returned view may result in undefined behavior. +After it's created, the number of elements in the view stays the same even if the view it was created from changes. However, if the underlying view changes, accessing elements in the returned view might result in undefined behavior. `drop` is the opposite of [`take`](#take). -2\) Can be used with pipe syntax: `collection | drop(5)`. Or with function call syntax: `drop(collection, 5)` or `drop(5)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | drop(5)`. Or it can be used with function call syntax: `drop(collection, 5)` or `drop(5)(collection)`. ### Example: `drop` @@ -375,37 +389,38 @@ int main() ## `drop_while` -Create a view that contains the elements of a range that remain once the leading elements that match the specified condition are dropped. +Create a view that contains the elements of a range that remain after the leading elements that match the specified condition are dropped. ```cpp 1) template constexpr ranges::view auto drop_while(R&& rg, P&& predicate); 2) template -constexpr /*range adaptor closure*/ drop_while(P&& predicate); +constexpr /*range adapter closure*/ drop_while(P&& predicate); ``` ### Parameters -*`R`*\ +`R`\ The type of the range. -*`predicate`*\ +`predicate`\ The conditions that determine which leading elements to drop from the range. -*`rg`*\ +`rg`\ The underlying range to create the view from. ### Return value -A [`drop_while_view`](drop-while-view-class.md) consisting of the elements that remain when the leading elements that match the predicate are dropped. +A [`drop_while_view`](drop-while-view-class.md) that consists of the elements that remain when the leading elements that match the predicate are dropped. ### Remarks -Stops dropping elements from *`rg`* as soon as the predicate returns `false`.\ +Stops dropping elements from `rg` as soon as the predicate returns `false`. + `drop_while` is the opposite of [`take_while`](#take_while). -2\) Can be used with pipe syntax: `collection | drop_while(predicate)`. Or with function call syntax: `drop_while(collection, predicate)` or `drop_while(predicate)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | drop_while(predicate)`. Or it can be used with function call syntax: `drop_while(collection, predicate)` or `drop_while(predicate)(collection)`. ### Example: `drop_while` @@ -454,18 +469,18 @@ constexpr ranges::view auto elements(R&& rg); ### Parameters -*`N`*\ +`N`\ The index of the element to select from each tuple-like value to include in the view. -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range of tuple-like values to create the view from. ### Return value -An [`elements_view`](elements-view-class.md) consisting of the selected index into each tuple-like value in a collection. +An [`elements_view`](elements-view-class.md) that consists of the selected index into each tuple-like value in a collection. ### Example: `elements` @@ -519,7 +534,7 @@ inline constexpr empty_view empty{}; ### Parameters -*`T`*\ +`T`\ The type of the elements in the view. The view needs an element type, even though there are no elements. ### Return value @@ -528,7 +543,7 @@ An [`empty_view`](empty-view-class.md). ### Remarks -An `empty_view` can be useful when calling code that requires a view, but doesn't need to process any of its elements. +An `empty_view` can be useful when you're calling code that requires a view but doesn't need to process any of its elements. ### Example: `empty` @@ -559,32 +574,32 @@ Create a view that contains the elements of a range that match the specified con constexpr ranges::view auto filter(R&& rg, P&& predicate); 2) template -constexpr /*range adaptor closure*/ filter(P&& predicate); +constexpr /*range adapter closure*/ filter(P&& predicate); ``` ### Parameters -*`P`*\ +`P`\ The type of the predicate. -*`predicate`*\ -The condition(s) that determine which elements to keep in the range. +`predicate`\ +The conditions that determine which elements to keep in the range. -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range to create the view from. ### Return value -A [`filter_view`](filter-view-class.md) containing the elements of a range that match the predicate. +A [`filter_view`](filter-view-class.md) that contains the elements of a range that match the predicate. ### Remarks For efficiency's sake, when you use `filter` and `transform` together with a pipe `|`, do the `filter` first so that you `transform` only the elements that you intend to keep. -2\) Can be used with pipe syntax: `collection | filter(predicate)`. Or with function call syntax: `filter(collection, predicate)` or `filter(predicate)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | filter(predicate)`. Or it can be used with function call syntax: `filter(collection, predicate)` or `filter(predicate)(collection)`. ### Example: `filter` @@ -633,17 +648,17 @@ constexpr ranges::view auto iota(V&& startValue, E&& endValue); // create a boun ### Parameters -*`E`*\ +`E`\ The type of the end value. -*`S`*\ +`S`\ The type of the start value. -*`startValue`*\ +`startValue`\ The first value in the sequence. -*`endValue`*\ -This value is one past the last value that will be in the sequence. For example, `std::views::iota(0, 5)` generates a view that has the values 0,1,2,3,4. +`endValue`\ +This value is one past the last value that will be in the sequence. For example, `std::views::iota(0, 5)` generates a view that has the values `0,1,2,3,4`. ### Return value @@ -671,7 +686,7 @@ void print(auto&& v) int main() { - // create an iota view with its range adaptor (preferred) + // create an iota view with its range adapter (preferred) print(std::views::iota(0, 5)); // outputs 0 1 2 3 4 // create an iota_view class directly @@ -696,16 +711,18 @@ views::istream(str); ### Parameters -*`str`*\ -A stream object. The type of which is derived from a specialization of `std::basic_istream`. +`str`\ +A stream object. Its type is derived from a specialization of `std::basic_istream`. -*`Val`*\ +`Val`\ The type of the elements to extract from the stream. ### Return value -A [`basic_istream_view`](basic-istream-view-class.md).\ -This range adaptor is equivalent to `ranges::basic_istream_view(str)` where `U` is the type of `str`. +A [`basic_istream_view`](basic-istream-view-class.md). + + +This range adapter is equivalent to `ranges::basic_istream_view(str)`, where `U` is the type of `str`. ### Example: `istream` @@ -732,26 +749,26 @@ int main() ## `join` -Create a view that combines all of the elements of multiple ranges into a single view. +Create a view that combines all the elements of multiple ranges into a single view. ```cpp 1) template [[nodiscard]] constexpr ranges::view auto join(R&& rg) const noexcept; -2) inline constexpr /*range adaptor closure*/ join(); +2) inline constexpr /*range adapter closure*/ join(); ``` ### Parameters -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range to create the view from. ### Return value -A [`join_view`](join-view-class.md) that contains the elements of all of the ranges in the underlying range. +A [`join_view`](join-view-class.md) that contains the elements of all the ranges in the underlying range. ### Example: `join` @@ -779,11 +796,11 @@ C++ 20 contains: ranges modules concepts & more. ### Remarks -2\) Can be used with pipe syntax: `collection | join`. Or with function call syntax: `join(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | join`. Or it can be used with function call syntax: `join(collection)`. ## `keys` -Create a [`keys_view`](keys-view-class.md) of the first index into each tuple-like value in a collection. This is useful for extracting keys from associative containers. For example, given a range of `std::tuple`, create a view consisting of all the `string` elements from each tuple. +Create a [`keys_view`](keys-view-class.md) of the first index into each tuple-like value in a collection. This is useful for extracting keys from associative containers. For example, given a range of `std::tuple`, create a view that consists of all the `string` elements from each tuple. ```cpp template @@ -792,12 +809,12 @@ constexpr auto keys(R&& rg); ### Parameters -*`R`*\ +`R`\ The type of the underlying range. ### Return value -A [`keys_view`](keys-view-class.md) consisting of the first index into each tuple-like value in the range. +A [`keys_view`](keys-view-class.md) that consists of the first index into each tuple-like value in the range. ### Example: `keys` @@ -847,7 +864,7 @@ int main() {"Windows 2000", 2000} }; - // Another way to call the range adaptor is by using '|' + // Another way to call the range adapter is by using '|' for (std::string version : windows | std::views::keys) { std::cout << version << ' '; // Windows 1.0 Windows 2.0 Windows 3.0 ... @@ -869,41 +886,41 @@ Split a range into subranges based on a delimiter. The delimiter can be a single constexpr view auto lazy_split(R&& rg, Pattern&& delimiter); 2) template -constexpr /*range adaptor closure*/ lazy_split(Pattern&& delimiter); +constexpr /*range adapter closure*/ lazy_split(Pattern&& delimiter); ``` ### Parameters -*`delimiter`*\ +`delimiter`\ A single value, or a sequence of values that specify where to split the range. -*`Pattern`*\ +`Pattern`\ The type of the delimiter. -*`R`*\ +`R`\ The type of the range to split. -*`rg`*\ +`rg`\ The range to split. ### Return value -A [`lazy_split_view`](lazy-split-view-class.md) containing one or more subranges that is the result of splitting the original range on *`delimiter`*. +A [`lazy_split_view`](lazy-split-view-class.md) that contains one or more subranges and is the result of splitting the original range on `delimiter`. ### Remarks -The delimiter isn't part of the result. For example, if you split the range 1,2,3 on the value 2, you get two subranges: 1 and 3. +The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adaptor is [`split`](#split). The primary differences between `split_view` and `lazy_split_view` are: +A related adapter is [`split`](#split). The primary differences between `split_view` and `lazy_split_view` are: -| **View** | **Can split a `const` range** | **range iterator** | +| View | Can split a `const` range | Range iterator | |--|--| -| `split_view` | no | Supports `forward_range` or higher. | -| `lazy_split_view` | yes | `input_range` or higher. | +| `split_view` | no | Supports `forward_range` or higher | +| `lazy_split_view` | yes | `input_range` or higher | -Prefer `split_view` because it's more efficient unless you must split a range that is `const`. +Prefer `split_view` because it's more efficient, unless you must split a range that is `const`. -2\) Can be used with pipe syntax: `collection | lazy_split(delimiter)`. Or with function call syntax: `lazy_split(collection, delimiter)` or `lazy_split(delimiter)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | lazy_split(delimiter)`. Or it can be used with function call syntax: `lazy_split(collection, delimiter)` or `lazy_split(delimiter)(collection)`. ### Example: `lazy_split` @@ -959,15 +976,15 @@ Create a view of the elements of a range in reverse order. 1) template constexpr ranges::view auto reverse(R&& rg); -2) inline constexpr /*range adaptor closure*/ reverse(); +2) inline constexpr /*range adapter closure*/ reverse(); ``` ### Parameters -*`R`*\ +`R`\ The type of the underlying range to reverse. -*`rg`*\ +`rg`\ The range to reverse. ### Return value @@ -980,7 +997,7 @@ A view that presents the elements of the underlying range in reverse order. The ### Remarks -2\) Can be used with pipe syntax: `collection | reverse`. Or with function call syntax: `reverse(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | reverse`. Or it can be used with function call syntax: `reverse(collection)`. ### Example: `reverse` @@ -1001,7 +1018,7 @@ int main() } std::cout << '\n'; - // using the range adaptor without using the pipe syntax + // using the range adapter without using the pipe syntax auto rv2 = std::views::reverse(v); for (auto &&e : rv2) // outputs 6 5 -4 3 2 1 0 { @@ -1017,7 +1034,7 @@ int main() ## `single` -Create a `single_view`, which is a view containing one element. +Create a `single_view`, which is a view that contains one element. ```cpp template @@ -1026,19 +1043,19 @@ constexpr ranges::view auto single(T&& t); ### Parameters -*`T`*\ +`T`\ The type of the element in the view. -*`t`*\ +`t`\ The value of the element to store in the view. ### Return value -An [`single_view`](single-view-class.md) containing *`t`*. +An [`single_view`](single-view-class.md) that contains `t`. ### Remarks -This view is useful for test purposes for calling code that needs to be provided with a view with at least one element in it. +This view is useful for test purposes, for calling code that needs to be provided with a view that has at least one element in it. ### Example: `single` @@ -1073,41 +1090,41 @@ Split a view into subranges based on a delimiter. The delimiter can be a single constexpr view auto split(R&& rg, Pattern&& delimiter); 2) template -constexpr /*range adaptor closure*/ split(Pattern&& delimiter); +constexpr /*range adapter closure*/ split(Pattern&& delimiter); ``` ### Parameters -*`delimiter`*\ +`delimiter`\ A single value, or a sequence of values that specify where to split the range. -*`Pattern`*\ +`Pattern`\ The type of the delimiter. -*`R`*\ +`R`\ The type of the underlying range to split. -*`rg`*\ +`rg`\ The range to split. ### Return value -A [`split_view`](split-view-class.md) containing one or more subranges. +A [`split_view`](split-view-class.md) that contains one or more subranges. ### Remarks -The delimiter isn't part of the result. For example, if you split the range 1,2,3 on the value 2, you get two subranges: 1 and 3. +The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adaptor is [`lazy_split`](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: +A related adapter is [`lazy_split`](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: -| **view** | **Can split a `const` range** | **range type** | +| View | Can split a `const` range | Range type | |---|---| -| `split_view` | no | Supports `forward_range` or higher. | -| `lazy_split_view` | yes | Supports `input_range` or higher. | +| `split_view` | no | Supports `forward_range` or higher | +| `lazy_split_view` | yes | Supports `input_range` or higher | -Prefer `split_view` because it's more efficient. Unless you must split a range that is `const`. +Prefer `split_view` because it's more efficient, unless you must split a range that is `const`. -2\) Can be used with pipe syntax: `collection | split(delimiter)`. Or with function call syntax: `split(collection, 5)` or `split(5)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | split(delimiter)`. Or it can be used with function call syntax: `split(collection, 5)` or `split(5)(collection)`. ### Example: `split` @@ -1163,34 +1180,34 @@ Create a view that contains the specified number of elements taken from the fron constexpr ranges::view auto take(R&& rg, ranges::range_difference_type count); 2) template -constexpr /*range adaptor closure*/ take(DifferenceType&& count); +constexpr /*range adapter closure*/ take(DifferenceType&& count); ``` ### Parameters -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range to create the view from. -*`count`*\ -The number of elements to take from the front of *`rg`*. +`count`\ +The number of elements to take from the front of `rg`. ### Return value The returned view is typically, but not always, a specialization of [`take_view`](take-view-class.md). Specifically: -- If `V` is a specialization of [`empty_view`](empty-view-class.md), or a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md) or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- If `V` is a specialization of [`empty_view`](empty-view-class.md) or a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. - Otherwise, the result is a [`take_view`](take-view-class.md). ### Remarks -If you specify more elements to take than exist in *`rg`*, then all of the elements are taken. +If you specify more elements to take than exist in `rg`, all of the elements are taken. `take` is the opposite of [`drop`](#drop). -2\) Can be used with pipe syntax: `collection | take(5)`. Or with function call syntax: `take(5, collection)` or `take(5)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | take(5)`. Or it can be used with function call syntax: `take(5, collection)` or `take(5)(collection)`. ### Example: `take` @@ -1233,34 +1250,34 @@ Create a view that contains the leading elements of a range that match the speci constexpr ranges::view auto take_while(R&& rg, P&& predicate); 2) template -constexpr /*range adaptor closure*/ take_while(P&& predicate); +constexpr /*range adapter closure*/ take_while(P&& predicate); ``` ### Parameters -*`P`*\ +`P`\ The type of the predicate. -*`predicate`*\ +`predicate`\ The conditions that determine which leading elements to copy from the range. -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The range to create the view from. ### Return value -A [`take_while_view`](take-while-view-class.md) consisting of the first *`count`* elements that meet the specified criteria in the range. +A [`take_while_view`](take-while-view-class.md) that consists of the first `count` elements that meet the specified criteria in the range. ### Remarks -Stops taking elements from *`rg`* once the predicate returns `false` or the range runs out of elements. +Stops taking elements from `rg` after the predicate returns `false` or the range runs out of elements. `take_while` is the opposite of [`drop_while`](#drop_while). -2\) Can be used with pipe syntax: `collection | take_while(pred)`. Or with function call syntax: `take_while(collection, pred)` or `take_while(pred)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | take_while(pred)`. Or it can be used with function call syntax: `take_while(collection, pred)` or `take_while(pred)(collection)`. ### Example: `take_while` @@ -1305,32 +1322,32 @@ Create a view of elements, each of which is a transformation of an element in th constexpr ranges::view auto transform(R&& rg, F&& fun); 2) template -constexpr /*range adaptor closure*/ transform(F&& fun); +constexpr /*range adapter closure*/ transform(F&& fun); ``` ### Parameters -*`F`*\ +`F`\ The type of the function object to transform the elements. -*`R`*\ +`R`\ The type of the underlying range. -*`fun`*\ +`fun`\ The function that transforms the elements. -*`rg`*\ +`rg`\ The range to create the view from. ### Return value -A [`transform_view`](transform-view-class.md) containing the transformed elements of *`rg`*. +A [`transform_view`](transform-view-class.md) that contains the transformed elements of `rg`. ### Remarks For efficiency's sake, when you compose `filter` and `transform`, do the `filter` first so that you `transform` only the elements that you intend to keep. -2\) Can be used with pipe syntax: `collection | transform(fun)`. Or with function call syntax: `transform(collection, fun)` or `transform(fun)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | transform(fun)`. Or you can use it with function call syntax: `transform(collection, fun)` or `transform(fun)(collection)`. ### Example: `transform` @@ -1367,7 +1384,7 @@ int main() ## `values` -Create a [`values_view`](values-view-class.md) consisting of the second index into each tuple-like value in a collection. This is useful for making a view of the values in an associative container. For example, given a range of `std::tuple` values, create a view consisting of all the `int` elements from each tuple. +Create a [`values_view`](values-view-class.md) that consists of the second index into each tuple-like value in a collection. This is useful for making a view of the values in an associative container. For example, given a range of `std::tuple` values, create a view that consists of all the `int` elements from each tuple. ```cpp template @@ -1376,10 +1393,10 @@ constexpr ranges::view auto values(R&& rg); ### Parameters -*`R`*\ +`R`\ The type of the underlying range. -*`rg`*\ +`rg`\ The underlying range of tuple-like values. ### Return value @@ -1434,8 +1451,8 @@ int main() {"Windows 2000", 2000} }; - // Another way to call the range adaptor using '|' - // Create a values_view containing the year from each pair + // Another way to call the range adapter by using '|' + // Create a values_view that contains the year from each pair for (int years : windows | std::views::values) { std::cout << years << ' '; // 1985 1987 1990 1992 ... @@ -1448,7 +1465,7 @@ int main() 1985 1987 1990 1992 1993 1995 1996 1995 1998 1985 2000 ``` -## Range adaptor type aliases +## Range adapter type aliases ### `all_t` @@ -1461,12 +1478,12 @@ using all_t = decltype(views::all(std::declval())); ### Parameters -*`R`*\ +`R`\ The type of the underlying range. ### Return value -The type of the view that `all` returns: `decltype(views::all(std::declval()))` +The type of the view that `all` returns: `decltype(views::all(std::declval()))`. ### Example: `all_t` From b67dfc884cc33a10425d84003e75d492c64ad8ee Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Thu, 27 Oct 2022 17:58:19 -0500 Subject: [PATCH 2/6] edit pass: range-adaptor-and-view-classes-topics --- docs/standard-library/range-adaptors.md | 22 ++++---- docs/standard-library/ranges.md | 64 ++++++++++----------- docs/standard-library/view-classes.md | 74 ++++++++++++++----------- 3 files changed, 84 insertions(+), 76 deletions(-) diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 5c76824989c..59cce7ebee7 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -9,7 +9,7 @@ helpviewer_keywords: ["std::ranges [C++], all", "std::ranges [C++], all_t", "std Range adapters 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 adapter in `std::ranges::views` instead of creating the view types directly. The adapters 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: +A view is a lightweight object that refers to elements from a range. A view can: - Consist of only certain elements from a range. - Represent a transformation of elements from a range. @@ -83,9 +83,9 @@ Range adapters come in many forms. For example, there are range adapters that al - Transforming the elements in a range (`view::transform`). - Splitting a range (`view::split`). -Range adapters can be chained together (composed). That's where the power and flexibility of ranges is most apparent. Composing range adapters allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms, which is that they aren't easy to chain together. +Range adapters can be chained together (composed). That's where the power and flexibility of ranges are most apparent. Composing range adapters allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms: that they aren't easy to chain together. -The following range adapters are available in the `std::views` namespace. The `std::views`namespace is a convenience alias for `std::ranges::views`. +The following range adapters are available in the `std::views` namespace. The `std::views` namespace is a convenience alias for `std::ranges::views`. | **Range adapter** | **Description** | |--|--| @@ -115,7 +115,7 @@ In the previous table, a range adapter is typically described as taking a range Range adapter functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. -You can pass range adapters and the result of pipe operations (`|`) to code that expects function objects. In the following example, the view created by the `split` range adapter is passed to the `transform` range adapter as if by a function call, because the `transform` range adapter is a function object. +You can pass range adapters and the result of pipe operations (`|`) to code that expects function objects. In the following example, the view that the `split` range adapter creates is passed to the `transform` range adapter as if by a function call, because the `transform` range adapter is a function object. ```cpp std::map x = {{0, "Hello, world"}, {42, "Goodbye, world"}}; @@ -144,18 +144,18 @@ The range to create the view from. ### Return value - If `rg` is already a view, a copy of `rg`. -- If `rg` is a non-view lvalue, a [`ref_view`](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) +- If `rg` is a non-view `lvalue`, a [`ref_view`](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) - If `rg` is a non-view `rvalue` such as a temporary object, or is the result of passing the range to `std::move`, an [`owning_view`](owning-view-class.md). Use `std::views::all_t` to get the type of the returned view. ### Remarks -This range adapter is the best way to convert a range into a view. One reason to create a view from a range is to pass it by value at low cost if passing the range by value could be expensive. +This range adapter is the best way to convert a range into a view. One reason to create a view from a range is to pass it by value at low cost, if passing the range by value could be expensive. Getting a view for a range is a useful alternative to passing a heavyweight range by value because views are inexpensive to create, copy, and destroy. A possible exception is `owning_view`, which is a view that owns the underlying range. -In general, the worst case scenario for destroying a view has `O(N)` complexity for the number of elements in the range. Even if you destroy `K` copies of view with `N` elements, the total complexity is still `O(N)` because the underlying range is destroyed only once. +In general, the worst-case scenario for destroying a view has `O(N)` complexity for the number of elements in the range. Even if you destroy `K` copies of view with `N` elements, the total complexity is still `O(N)` because the underlying range is destroyed only once. ### Example: `all` @@ -344,12 +344,12 @@ If you specify more elements to drop than exist in the underlying range, an [`em The returned view is typically, but not always, a specialization of [`drop_view`](drop-view-class.md). That is: -- If `V` is a specialization of [`empty_view`](empty-view-class.md) or a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- If `V` is a specialization of [`empty_view`](empty-view-class.md), or is a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. - Otherwise, the result is a [`drop_view`](drop-view-class.md). ### Remarks -After it's created, the number of elements in the view stays the same even if the view it was created from changes. However, if the underlying view changes, accessing elements in the returned view might result in undefined behavior. +After it's created, the number of elements in the view stays the same even if the view that it was created from changes. However, if the underlying view changes, accessing elements in the returned view might result in undefined behavior. `drop` is the opposite of [`take`](#take). @@ -1198,7 +1198,7 @@ The number of elements to take from the front of `rg`. The returned view is typically, but not always, a specialization of [`take_view`](take-view-class.md). Specifically: -- If `V` is a specialization of [`empty_view`](empty-view-class.md) or a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- If `V` is a specialization of [`empty_view`](empty-view-class.md), or is a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. - Otherwise, the result is a [`take_view`](take-view-class.md). ### Remarks @@ -1347,7 +1347,7 @@ A [`transform_view`](transform-view-class.md) that contains the transformed elem For efficiency's sake, when you compose `filter` and `transform`, do the `filter` first so that you `transform` only the elements that you intend to keep. -The code shown earlier as "2\)" can be used with pipe syntax: `collection | transform(fun)`. Or you can use it with function call syntax: `transform(collection, fun)` or `transform(fun)(collection)`. +The code shown earlier as "2\)" can be used with pipe syntax: `collection | transform(fun)`. Or it can be used with function call syntax: `transform(collection, fun)` or `transform(fun)(collection)`. ### Example: `transform` diff --git a/docs/standard-library/ranges.md b/docs/standard-library/ranges.md index eac9034cbd6..e62bca1597d 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -1,6 +1,6 @@ --- title: "" -description: "Overview of the Standard Template Library (STL) ranges library" +description: "Get an overview of the Standard Template Library (STL) ranges." ms.date: 10/25/2022 f1_keywords: [""] helpviewer_keywords: ["ranges"] @@ -8,17 +8,17 @@ helpviewer_keywords: ["ranges"] # `` -At a high level, a range is something you can iterate over. The containers, such as `vector`, `list`, and so on, 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. 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 they should operate on. For example, consider how you sort a `vector` using `std::sort()`. You pass two iterators the mark the beginning and end of the `vector`. That provides flexibility, but passing the iterators to the algorithm is extra work since most of the time you just want to sort the whole thing. +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. -With ranges, you can call `std::ranges::sort(myVector);` which is treated as if you had called `std::sort(myVector.begin(), myVector.end());` In range libraries, algorithms take ranges as parameters (although they can also take iterators, if you want). They can operate directly on collections. Some examples of range algorithms available in `` include `copy`, `copy_n`, `copy_if`, `all_of`, `any_of`, and `none_of`, `find`, `find_if`, and `find_if_not`, `count` and `count_if`, `for_each` and `for_each_n`, `equal` and `mismatch`. +With ranges, you can call `std::ranges::sort(myVector);`, which is treated as if you called `std::sort(myVector.begin(), myVector.end());`. In range libraries, algorithms take ranges as parameters (although they can also take iterators, if you want). They can operate directly on collections. Examples of range algorithms available in `` include `copy`, `copy_n`, `copy_if`, `all_of`, `any_of`, `none_of`, `find`, `find_if`, `find_if_not`, `count`, `count_if`, `for_each`, `for_each_n`, `equal`, and `mismatch`. -But the benefits of ranges go further. Perhaps the most important benefit is that you can compose STL algorithms that operate on ranges in a style reminiscent of functional programming. +But perhaps the most important benefit of ranges is that you can compose STL algorithms that operate on ranges in a style that's reminiscent of functional programming. -## A ranges example +## An example of ranges -Before ranges, if you wanted to transform the elements of a collection that meet a certain criteria, you'd need to introduce an intermediate step to hold the results between operations. For example, if you wanted to build a vector of squares from the elements in another vector that are divisible by 3, you could write something like: +Before ranges, if you wanted to transform the elements of a collection that met a certain criteria, you needed to introduce an intermediate step to hold the results between operations. For example, if you wanted to build a vector of squares from the elements in another vector that are divisible by 3, you could write something like: ```cpp std::vector input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -37,26 +37,26 @@ 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; }); ``` -Besides being easier to read, it avoids the memory allocation required for the `intermediate` vector and its contents, while also allowing you to compose two operations. +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. -In the code above, each element that is divisible by three is combined with an operation to square that element. The '`|`' symbol chains the operations together, and is read left to right. +In the preceding code, each element that's divisible by 3 is combined with an operation to square that element. The pipe (`|`) symbol chains the operations together and is read left to right. The result, `output`, is itself a kind of range called a *view*. > [!NOTE] -> The ranges examples require 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`**. +> 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. +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. -Views are created by range adaptors, which are discussed in the following section. For more information about the classes that implement various views, see [View classes](view-classes.md). +Views are created by range adapters, which are discussed in the following section. For more information about the classes that implement various views, see [View classes](view-classes.md). -How the elements in the view appear depends on the range adaptor you use to create the view. In the previous example, a range adaptor takes a range and returns a view of the elements divisible by three. The underlying range is unchanged. +How the elements in the view appear depends on the range adapter that you use to create the view. In the previous example, a range adapter takes a range and returns a view of the elements divisible by 3. The underlying range is unchanged. -Views are composable, which is powerful. In the previous example, the view of vector elements that are divisible by three is combined with the view that squares those elements. +Views are composable, which is powerful. In the previous example, the view of vector elements that are divisible by 3 is combined with the view that squares those elements. -The elements of a view are evaluated lazily. That is, the transformations 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. +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 3. The `square` lambda breakpoint will be hit as the elements that are divisible by 3 are squared. ```cpp // requires /std:c++latest @@ -81,25 +81,25 @@ int main() } ``` -## Range adaptors +## Range adapters -Range adaptors take a range and produce a view. Range adaptors produce lazily evaluated views. That is, you don't incur the cost of transforming every element in the range to produce the view. You only pay the cost to process an element in the view when you access that element. +Range adapters take a range and produce a view. Range adapters produce lazily evaluated views. That is, you don't incur the cost of transforming every element in the range to produce the view. You only pay the cost to process an element in the view when you access that element. -In the previous example, the `filter` range adaptor creates a view named `input` containing the elements that are divisible by three. The `transform` range adaptor takes the view of elements divisible by three, and creates a view of those elements squared. +In the previous example, the `filter` range adapter creates a view named `input` that contains the elements that are divisible by 3. The `transform` range adapter takes the view of elements divisible by 3 and creates a view of those elements squared. -Range adaptors can be chained together (composed), which is the heart of the power and flexibility of ranges. Composing range adaptors allows you to overcome a core problem with the previous STL algorithms because they aren't easily composable. +Range adapters can be chained together (composed), which is the heart of the power and flexibility of ranges. Composing range adapters allows you to overcome the problem that the previous STL algorithms aren't easily composable. -For more information about creating views, see [Range adaptors](range-adaptors.md). +For more information about creating views, see [Range adapters](range-adaptors.md). ## Range algorithms -Range algorithms have been created that take a range argument. For example, `std::ranges::sort(myVector);` +Some range algorithms take a range argument. An example is `std::ranges::sort(myVector);`. -The range algorithms are almost identical to the corresponding iterator-pair algorithms in the `std` namespace, except that they have concept-enforced constraints and they accept either range arguments or more iterator-sentinel argument pairs. They can work directly on a container and can be easily chained together. +The range algorithms are almost identical to the corresponding iterator-pair algorithms in the `std` namespace. The difference is that they have concept-enforced constraints, and they accept either range arguments or more iterator-sentinel argument pairs. They can work directly on a container and can be easily chained together. ## `` functions -| **Get an iterator to a range** | **Description** | +| Function | Description | |--|--| | [`begin`](range-functions.md#begin)C++20 | Get an iterator to the first element in the range. | | [`cbegin`](range-functions.md#cbegin)C++20 | Get a `const` iterator to the first element in the range. | @@ -119,20 +119,20 @@ The range algorithms are almost identical to the corresponding iterator-pair alg How you view the elements of a range depends on its underlying iterator type. The iterator types are specified as C++20 concepts. -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. +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 type of container they can be applied to: +The range concepts mirror the hierarchy of iterator categories. The following table lists various range concepts, along with the type of container that they can be applied to: | Range concept | Description | Supported containers | |--|--|--| -| `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`| -| `std::ranges::random_access_range` | Can access an arbitrary element (in constant time) using the `[]` operator) | `std::deque` | -| `std::ranges::contiguous_range` | The elements are stored in memory consecutively | `std::array`
`std::string`
`std::vector` | +| `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`| +| `std::ranges::random_access_range` | Can access an arbitrary element (in constant time) by using the `[]` operator. | `std::deque` | +| `std::ranges::contiguous_range` | The elements are stored in memory consecutively. | `std::array`
`std::string`
`std::vector` | ## See also [Range functions](range-functions.md)\ -[Range adaptors](range-adaptors.md)\ -[Header Files Reference](../standard-library/cpp-standard-library-header-files.md) \ No newline at end of file +[Range adapters](range-adaptors.md)\ +[Header files reference](../standard-library/cpp-standard-library-header-files.md) \ No newline at end of file diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index a78c1052b03..0909b441361 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -1,5 +1,5 @@ --- -description: "Learn more about view classes, which allow you inexpensively refer to and transform ranges." +description: "Learn more about view classes, which allow you to inexpensively refer to and transform ranges." title: "View classes" ms.date: 10/07/2022 f1_keywords: ["RANGES/std::ranges::views", "RANGES/std::views"] @@ -7,13 +7,15 @@ 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 you specify to select elements from another range. +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. -When you access the elements in a view, it's done 'lazily' so that work is only done when you get an element. This also 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 you access, and only when you access them. +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. -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 it refers to, so it doesn't need to make a copy. This is also why you can 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. -You typically create a view 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 primarily in case you need to create your own custom view type based on an existing view type. +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. + +You typically create a view by using a [range adapter](range-adaptors.md). Range adapters 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. Here's a brief example of creating a view of the squares of the elements that are divisible by 3 in a vector: @@ -43,9 +45,9 @@ int main() 0 9 36 81 ``` -Using a view after the range 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/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 may have made. +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 recreate a view if you modify the underlying range. The following example demonstrates this, and 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 this. It also shows how to store a view pipeline in a variable so that you can reuse it. ```cpp // requires / std:c++20 or later @@ -96,63 +98,69 @@ v | rev3(v): 2 1 0 The following view classes are defined in the `std::ranges` namespace. -| **View ** | **Description** | +| View | Description | |--|--| | [`basic_istream_view`](basic-istream-view-class.md)C++20 | A view of successive elements from an input stream. | | [`common_view`](common-view-class.md)C++20 | Adapts a view that has different iterator/sentinel types into a view with the same iterator/sentinel types. | | [`drop_view`](drop-view-class.md)C++20 | Created from another view, skipping the first `count` elements. | | [`drop_while_view`](drop-while-view-class.md)C++20 | Created from another view, skipping leading elements as long as a predicate holds. | -| [`elements_view`](elements-view-class.md)C++20 | A view over the selected index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view consisting of all the `string` elements from each tuple. | +| [`elements_view`](elements-view-class.md)C++20 | A view over the selected index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of all the `string` elements from each tuple. | | [`empty_view`](empty-view-class.md)C++20 | A view with no elements. | | [`filter_view`](filter-view-class.md)C++20 | Filters out elements of a range that don't match a predicate. | | [`iota_view`](iota-view-class.md)C++20 | A generated view that contains a sequence of incrementing values. | -| [`join_view`](join-view-class.md)C++20 | Combines all of the elements of multiple ranges into a single view. | -| [`keys_view`](keys-view-class.md)C++20 | A view over the first index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view consisting of the `string` elements from each tuple. | +| [`join_view`](join-view-class.md)C++20 | Combines all the elements of multiple ranges into a single view. | +| [`keys_view`](keys-view-class.md)C++20 | A view over the first 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 `string` elements from each tuple. | | [`lazy_split_view`](lazy-split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | | [`owning_view`](owning-view-class.md)C++20 | Takes ownership of the elements from another range. | | [`ref_view`](ref-view-class.md)C++20 | A view that references the elements that belong to another range. | | [`reverse_view`](reverse-view-class.md)C++20 | Presents the elements of a range in reverse order. | -| [`single_view`](single-view-class.md)C++20 | A view containing only one element. | +| [`single_view`](single-view-class.md)C++20 | A view that contains only one element. | | [`split_view`](split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | -| [`subrange`](subrange-class.md)C++20 | A view of part of the elements of a range as defined by a begin iterator and sentinel. | +| [`subrange`](subrange-class.md)C++20 | A view of part of the elements of a range, as defined by a begin iterator and a sentinel. | | [`take_view`](take-view-class.md)C++20 | Contains the specified number of elements taken from the front of a range. | | [`take_while_view`](take-while-view-class.md)C++20 | Contains the leading elements of a range that match the given predicate. | -| [`transform_view`](transform-view-class.md)C++20 | A view of an underlying sequence after applying a transformation function 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 consisting of the `int` elements from each tuple. | +| [`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 adapters](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adapters in `std::views` to creating view classes directly. The range adapters are the intended access points, are easier to use, and in some cases are more efficient. + +## View class characteristics -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. +Each view class topic has a **Characteristics** section after the syntax section. The **Characteristics** section has the following entries: -## View classes characteristics +* **Range adapter**: A link to the range adapter that creates the view. You typically use a range adapter 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. +* **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`, 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))`. +* **Borrowed range**: Specifies whether the view is a *borrowed range*. `borrowed_range` means you can use iterators for `T` after `T` is destroyed. -Each view class topic has a *Characteristics* section following the syntax section. The *Characteristics* section has the following entries: + No standard container is a borrowed range, because destroying the container frees the elements and invalidates any iterators. In that case, we say that the iterators are left "dangling" after destruction. -* **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 they can use. See the table below 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 may be different for some views. For example, a `reverse_view` has a `bidirectional_iterator` category, even if the underlying range has a `random_access_iterator` category. -* **Element type:** The type of the elements that are returned by the view's iterator. -* **Sized:** Whether the view can return the number of elements it refers to. Not all views can. -* **Common range:** Specifies whether the view is a `common_range`, which means that the begin iterator and sentinel types are the same. Common ranges are useful for pre-ranges code that works with iterator pairs. For example, sequence container iterator pair constructors like `vector(ranges::begin(x), ranges::end(x))`. -* **Borrowed range:** Specifies whether the view is a *borrowed range*. `borrowed_range` means you can use iterators for `T` after `T` is destroyed. No standard container is a borrowed range because destroying the container frees the elements, so any iterators are invalidated. In that case, we say that the iterators are left "dangling" after destruction. For example,`std::ranges::find()` typically returns an iterator to the found element in the range argument. If the range argument is a temporary (rvalue) container, it's a mistake to store the returned iterator and use it later because it's "dangling". Range algorithms that return iterators (or subranges) only do so 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 has gone 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. + For example,`std::ranges::find()` typically returns an iterator to the found element in the range argument. If the range argument is a temporary (`rvalue`) container, it's a mistake to store the returned iterator and use it later because it's "dangling." + + Range algorithms that return iterators (or subranges) do so only when their arguments are `lvalue` instances (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 -The iterator category referred to in the *Characteristics* section by **Range adaptor** and **View iterator category** refers to the hierarchy of iterators that ranges and views support. +The iterator category that **Range adapter** and **View iterator category** mention in the in the **Characteristics** section refers to the hierarchy of iterators that ranges and views support. That hierarchy, in increasing order of capability, is: -| **range iterator category** | **Description** | +| Range iterator category | Description | |--|--| -| `output_range` | Write-only, only moves forward; single-pass | -| `input_range` | Only moves forward; single-pass | -| `forward_range` | Only moves forward; multi-pass | +| `output_range` | Write-only, only moves forward; single-pass. | +| `input_range` | Only moves forward; single-pass. | +| `forward_range` | Only moves forward; multi-pass. | | `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. | -An iterator also has the capability of the iterators that precede it in the table. For example, a `bidirectional_range` can be used with a `forward_range` iterator, but not vice versa. +An iterator also has the capability of the iterators that precede it in the table. For example, `bidirectional_range` can be used with a `forward_range` iterator, but not vice versa. -The statement "requires `input_range` or better", means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator because any of those categories is as capable as an `input_range`. +The statement "requires `input_range` or better" means that the view can be used with an `input_range`, `forward_range`, `bidirectional_range`, `random_access_range`, or `contiguous_range` iterator, because any of those categories is as capable as `input_range`. ## See also From 8f21ca301ffe3a0d097d7ec4480a1c73e69c5d6d Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Thu, 27 Oct 2022 18:03:33 -0500 Subject: [PATCH 3/6] edit pass: range-adaptor-and-view-classes-topics --- docs/standard-library/view-classes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 0909b441361..bf366265a9d 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -124,7 +124,7 @@ The following view classes are defined in the `std::ranges` namespace. Many of these classes have corresponding [range adapters](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adapters in `std::views` to creating view classes directly. The range adapters are the intended access points, are easier to use, and in some cases are more efficient. -## View class characteristics +## View classes characteristics Each view class topic has a **Characteristics** section after the syntax section. The **Characteristics** section has the following entries: @@ -145,7 +145,7 @@ Each view class topic has a **Characteristics** section after the syntax section ### Iterator hierarchy -The iterator category that **Range adapter** and **View iterator category** mention in the in the **Characteristics** section refers to the hierarchy of iterators that ranges and views support. +The iterator category that **Range adapter** and **View iterator category** mention in the **Characteristics** section refers to the hierarchy of iterators that ranges and views support. That hierarchy, in increasing order of capability, is: From bcacb431ec861c7284729e379de00962433b1a45 Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Fri, 28 Oct 2022 12:33:15 -0500 Subject: [PATCH 4/6] edit pass: range-adaptor-and-view-classes-topics --- docs/standard-library/range-adaptors.md | 132 ++++++++++++------------ docs/standard-library/ranges.md | 42 ++++---- docs/standard-library/view-classes.md | 58 +++++------ 3 files changed, 116 insertions(+), 116 deletions(-) diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 59cce7ebee7..8b6fd4c2056 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -83,35 +83,35 @@ Range adapters come in many forms. For example, there are range adapters that al - Transforming the elements in a range (`view::transform`). - Splitting a range (`view::split`). -Range adapters can be chained together (composed). That's where the power and flexibility of ranges are most apparent. Composing range adapters allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms: that they aren't easy to chain together. +Range adapters can be chained together (composed). That's where the power and flexibility of ranges are most apparent. Composing range adapters allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms, which is that they aren't easy to chain together. The following range adapters are available in the `std::views` namespace. The `std::views` namespace is a convenience alias for `std::ranges::views`. -| **Range adapter** | **Description** | +| Range adapter | Description | |--|--| -| [`all`](#all)C++20 | Create a view that refers to a range and its elements. | -| [`common`](#common)C++20 | Create a view that has the same iterator and sentinel types from a range that doesn't. | -| [`counted`](#counted)C++20 | Create a view of the first *n* elements of a range, starting from the specified location. | -| [`drop`](#drop)C++20 | Create a view from another view, skipping the specified number of elements from the front. | -| [`drop_while`](#drop_while)C++20 | Create a view that contains the elements of a range that remain after the leading elements that match the specified condition are dropped. | -| [`elements`](#elements)C++20 | Create a view of the selected index into each tuple-like value in a range. | -| [`filter`](#filter)C++20 | Create a view that contains the elements of a range that match the specified condition. | -| [`iota`](#iota)C++20 | Create a view that contains a sequence of increasing values. | -| [`keys`](#keys)C++20 | Create a view of the first index into each tuple-like value in a collection. | -| [`lazy_split`](#lazy_split)C++20 | Split a view into subranges based on a delimiter. | -| [`reverse`](#reverse)C++20 | Create a view of the elements of a range in reverse order. | -| [`single`](#single)C++20 | Create a view that contains one element. | -| [`split`](#split)C++20 | Split a view into subranges based on a delimiter. | -| [`take`](#take)C++20 | Create a view of the first *n* elements from another view. | -| [`take_while`](#take_while)C++20 | Create a view that contains the leading elements of a range that match the specified condition. | -| [`transform`](#transform)C++20 | Create a view of transformed elements from another view. | -| [`values`](#values)C++20 | Create a view of the second index into each tuple-like value in a collection. | +| [all](#all)C++20 | Create a view that refers to a range and its elements. | +| [common](#common)C++20 | Create a view that has the same iterator and sentinel types from a range that doesn't. | +| [counted](#counted)C++20 | Create a view of the first *n* elements of a range, starting from the specified location. | +| [drop](#drop)C++20 | Create a view from another view, skipping the specified number of elements from the front. | +| [drop_while](#drop_while)C++20 | Create a view that contains the elements of a range that remain after the leading elements that match the specified condition are dropped. | +| [elements](#elements)C++20 | Create a view of the selected index into each tuple-like value in a range. | +| [filter](#filter)C++20 | Create a view that contains the elements of a range that match the specified condition. | +| [iota](#iota)C++20 | Create a view that contains a sequence of increasing values. | +| [keys](#keys)C++20 | Create a view of the first index into each tuple-like value in a collection. | +| [lazy_split](#lazy_split)C++20 | Split a view into subranges based on a delimiter. | +| [reverse](#reverse)C++20 | Create a view of the elements of a range in reverse order. | +| [single](#single)C++20 | Create a view that contains one element. | +| [split](#split)C++20 | Split a view into subranges based on a delimiter. | +| [take](#take)C++20 | Create a view of the first *n* elements from another view. | +| [take_while](#take_while)C++20 | Create a view that contains the leading elements of a range that match the specified condition. | +| [transform](#transform)C++20 | Create a view of transformed elements from another view. | +| [values](#values)C++20 | Create a view of the second index into each tuple-like value in a collection. | In the previous table, a range adapter is typically described as taking a range and producing a view. To be precise, range adapters have a range argument that accepts one of the following: -- The `cv-unqualified` type models `view`, and the argument is an `rvalue` or is copyable. -- When you pass the argument as an `lvalue`, it must model `range` and live as long as the view. -- When you pass the argument as an `rvalue`, such as when calling [`owning_view`](owning-view-class.md), it must model `range` and `movable`. +- The `cv-unqualified` type models `view`, and the argument is an rvalue or is copyable. +- When you pass the argument as an lvalue, it must model `range` and live as long as the view. +- When you pass the argument as an rvalue, such as when calling [owning_view](owning-view-class.md), it must model `range` and `movable`. Range adapter functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. @@ -144,8 +144,8 @@ The range to create the view from. ### Return value - If `rg` is already a view, a copy of `rg`. -- If `rg` is a non-view `lvalue`, a [`ref_view`](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) -- If `rg` is a non-view `rvalue` such as a temporary object, or is the result of passing the range to `std::move`, an [`owning_view`](owning-view-class.md). +- If `rg` is a non-view lvalue, a [ref_view](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) +- If `rg` is a non-view rvalue such as a temporary object, or is the result of passing the range to `std::move`, an [owning_view](owning-view-class.md). Use `std::views::all_t` to get the type of the returned view. @@ -205,7 +205,7 @@ The range to create the view from. ### Return value - `views::all(rg)` if `rg` is a range with the same iterator and sentinel type. -- [`common_view(views::all(rg))`](common-view-class.md) if `rg` has different iterator and sentinel types. +- [common_view(views::all(rg))](common-view-class.md) if `rg` has different iterator and sentinel types. ### Remarks @@ -257,7 +257,7 @@ The type of the iterator. `count`\ The number of elements to include in the view. Must be non-negative. -- If `count == 0`, an empty [`span`](span-class.md) is returned. +- If `count == 0`, an empty [span](span-class.md) is returned. - If `count` is greater than the number of elements in the range, the behavior is undefined. `it`\ @@ -265,7 +265,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` for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [subrange](subrange-class.md) is returned. ### Remarks @@ -334,24 +334,24 @@ The number of elements to drop from the front of `rg`. Must be non-negative. The type of the range. `rg`\ -The range used to create the view. +The range that's used to create the view. ### Return value A view of the underlying range, with the specified number of elements dropped from the front. -If you specify more elements to drop than exist in the underlying range, an [`empty_view`](empty-view-class.md) is returned. +If you specify more elements to drop than exist in the underlying range, an [empty_view](empty-view-class.md) is returned. -The returned view is typically, but not always, a specialization of [`drop_view`](drop-view-class.md). That is: +The returned view is typically, but not always, a specialization of [drop_view](drop-view-class.md). That is: -- If `V` is a specialization of [`empty_view`](empty-view-class.md), or is a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. -- Otherwise, the result is a [`drop_view`](drop-view-class.md). +- If `V` is a specialization of [empty_view](empty-view-class.md), or is a specialization of [span](span-class.md), [basic_string_view](basic-string-view-class.md), [iota_view](iota-view-class.md), or [subrange](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- Otherwise, the result is a [drop_view](drop-view-class.md). ### Remarks After it's created, the number of elements in the view stays the same even if the view that it was created from changes. However, if the underlying view changes, accessing elements in the returned view might result in undefined behavior. -`drop` is the opposite of [`take`](#take). +`drop` is the opposite of [take](#take). The code shown earlier as "2\)" can be used with pipe syntax: `collection | drop(5)`. Or it can be used with function call syntax: `drop(collection, 5)` or `drop(5)(collection)`. @@ -412,13 +412,13 @@ The underlying range to create the view from. ### Return value -A [`drop_while_view`](drop-while-view-class.md) that consists of the elements that remain when the leading elements that match the predicate are dropped. +A [drop_while_view](drop-while-view-class.md) that consists of the elements that remain when the leading elements that match the predicate are dropped. ### Remarks Stops dropping elements from `rg` as soon as the predicate returns `false`. -`drop_while` is the opposite of [`take_while`](#take_while). +`drop_while` is the opposite of [take_while](#take_while). The code shown earlier as "2\)" can be used with pipe syntax: `collection | drop_while(predicate)`. Or it can be used with function call syntax: `drop_while(collection, predicate)` or `drop_while(predicate)(collection)`. @@ -460,7 +460,7 @@ int main() ## `elements` -Create an [`elements_view`](elements-view-class.md), which is a view of the selected index into each tuple-like value in a range. For example, given a range of `std::tuple` values, create an `elements_view` of all the `string` elements from each tuple. +Create an [elements_view](elements-view-class.md), which is a view of the selected index into each tuple-like value in a range. For example, given a range of `std::tuple` values, create an `elements_view` of all the `string` elements from each tuple. ```cpp template @@ -480,7 +480,7 @@ The range of tuple-like values to create the view from. ### Return value -An [`elements_view`](elements-view-class.md) that consists of the selected index into each tuple-like value in a collection. +An [elements_view](elements-view-class.md) that consists of the selected index into each tuple-like value in a collection. ### Example: `elements` @@ -539,7 +539,7 @@ The type of the elements in the view. The view needs an element type, even thoug ### Return value -An [`empty_view`](empty-view-class.md). +An [empty_view](empty-view-class.md). ### Remarks @@ -593,7 +593,7 @@ The range to create the view from. ### Return value -A [`filter_view`](filter-view-class.md) that contains the elements of a range that match the predicate. +A [filter_view](filter-view-class.md) that contains the elements of a range that match the predicate. ### Remarks @@ -662,7 +662,7 @@ This value is one past the last value that will be in the sequence. For example, ### Return value -An [`iota_view`](iota-view-class.md) of a sequence of increasing values. +An [iota_view](iota-view-class.md) of a sequence of increasing values. ### Remarks @@ -719,7 +719,7 @@ The type of the elements to extract from the stream. ### Return value -A [`basic_istream_view`](basic-istream-view-class.md). +A [basic_istream_view](basic-istream-view-class.md). This range adapter is equivalent to `ranges::basic_istream_view(str)`, where `U` is the type of `str`. @@ -768,7 +768,7 @@ The range to create the view from. ### Return value -A [`join_view`](join-view-class.md) that contains the elements of all the ranges in the underlying range. +A [join_view](join-view-class.md) that contains the elements of all the ranges in the underlying range. ### Example: `join` @@ -800,7 +800,7 @@ The code shown earlier as "2\)" can be used with pipe syntax: `collection | join ## `keys` -Create a [`keys_view`](keys-view-class.md) of the first index into each tuple-like value in a collection. This is useful for extracting keys from associative containers. For example, given a range of `std::tuple`, create a view that consists of all the `string` elements from each tuple. +Create a [keys_view](keys-view-class.md) of the first index into each tuple-like value in a collection. This is useful for extracting keys from associative containers. For example, given a range of `std::tuple`, create a view that consists of all the `string` elements from each tuple. ```cpp template @@ -814,7 +814,7 @@ The type of the underlying range. ### Return value -A [`keys_view`](keys-view-class.md) that consists of the first index into each tuple-like value in the range. +A [keys_view](keys-view-class.md) that consists of the first index into each tuple-like value in the range. ### Example: `keys` @@ -905,16 +905,16 @@ The range to split. ### Return value -A [`lazy_split_view`](lazy-split-view-class.md) that contains one or more subranges and is the result of splitting the original range on `delimiter`. +A [lazy_split_view](lazy-split-view-class.md) that contains one or more subranges and is the result of splitting the original range on `delimiter`. ### Remarks The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adapter is [`split`](#split). The primary differences between `split_view` and `lazy_split_view` are: +A related adapter is [split](#split). The primary differences between `split_view` and `lazy_split_view` are: | View | Can split a `const` range | Range iterator | -|--|--| +|--|--|--| | `split_view` | no | Supports `forward_range` or higher | | `lazy_split_view` | yes | `input_range` or higher | @@ -989,11 +989,11 @@ The range to reverse. ### Return value -A view that presents the elements of the underlying range in reverse order. The returned view is typically, but not always, a specialization of [`reverse_view`](reverse-view-class.md). That is: +A view that presents the elements of the underlying range in reverse order. The returned view is typically, but not always, a specialization of [reverse_view](reverse-view-class.md). That is: - If `V` is a specialization of `reverse_view`, the result is the argument's underlying view. A double-reverse is a no-op (no operation). -- If `V` has the form `subrange, reverse_iterator>`, the result is a [`subrange`](subrange-class.md) of the unwrapped iterators. A double-reverse is a no-op. -- Otherwise, the result is a [`reverse_view`](reverse-view-class.md). +- If `V` has the form `subrange, reverse_iterator>`, the result is a [subrange](subrange-class.md) of the unwrapped iterators. A double-reverse is a no-op. +- Otherwise, the result is a [reverse_view](reverse-view-class.md). ### Remarks @@ -1051,7 +1051,7 @@ The value of the element to store in the view. ### Return value -An [`single_view`](single-view-class.md) that contains `t`. +An [single_view](single-view-class.md) that contains `t`. ### Remarks @@ -1109,17 +1109,17 @@ The range to split. ### Return value -A [`split_view`](split-view-class.md) that contains one or more subranges. +A [split_view](split-view-class.md) that contains one or more subranges. ### Remarks The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adapter is [`lazy_split`](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: +A related adapter is [lazy_split](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: | View | Can split a `const` range | Range type | -|---|---| -| `split_view` | no | Supports `forward_range` or higher | +|---|---|---| +| `split_view` | no | Supports `forward_range` or higher | | `lazy_split_view` | yes | Supports `input_range` or higher | Prefer `split_view` because it's more efficient, unless you must split a range that is `const`. @@ -1196,16 +1196,16 @@ The number of elements to take from the front of `rg`. ### Return value -The returned view is typically, but not always, a specialization of [`take_view`](take-view-class.md). Specifically: +The returned view is typically, but not always, a specialization of [take_view](take-view-class.md). Specifically: -- If `V` is a specialization of [`empty_view`](empty-view-class.md), or is a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. -- Otherwise, the result is a [`take_view`](take-view-class.md). +- If `V` is a specialization of [empty_view](empty-view-class.md), or is a specialization of [span](span-class.md), [basic_string_view](basic-string-view-class.md), [iota_view](iota-view-class.md), or [subrange](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- Otherwise, the result is a [take_view](take-view-class.md). ### Remarks If you specify more elements to take than exist in `rg`, all of the elements are taken. -`take` is the opposite of [`drop`](#drop). +`take` is the opposite of [drop](#drop). The code shown earlier as "2\)" can be used with pipe syntax: `collection | take(5)`. Or it can be used with function call syntax: `take(5, collection)` or `take(5)(collection)`. @@ -1269,13 +1269,13 @@ The range to create the view from. ### Return value -A [`take_while_view`](take-while-view-class.md) that consists of the first `count` elements that meet the specified criteria in the range. +A [take_while_view](take-while-view-class.md) that consists of the first `count` elements that meet the specified criteria in the range. ### Remarks Stops taking elements from `rg` after the predicate returns `false` or the range runs out of elements. -`take_while` is the opposite of [`drop_while`](#drop_while). +`take_while` is the opposite of [drop_while](#drop_while). The code shown earlier as "2\)" can be used with pipe syntax: `collection | take_while(pred)`. Or it can be used with function call syntax: `take_while(collection, pred)` or `take_while(pred)(collection)`. @@ -1341,7 +1341,7 @@ The range to create the view from. ### Return value -A [`transform_view`](transform-view-class.md) that contains the transformed elements of `rg`. +A [transform_view](transform-view-class.md) that contains the transformed elements of `rg`. ### Remarks @@ -1384,7 +1384,7 @@ int main() ## `values` -Create a [`values_view`](values-view-class.md) that consists of the second index into each tuple-like value in a collection. This is useful for making a view of the values in an associative container. For example, given a range of `std::tuple` values, create a view that consists of all the `int` elements from each tuple. +Create a [values_view](values-view-class.md) that consists of the second index into each tuple-like value in a collection. This is useful for making a view of the values in an associative container. For example, given a range of `std::tuple` values, create a view that consists of all the `int` elements from each tuple. ```cpp template @@ -1401,7 +1401,7 @@ The underlying range of tuple-like values. ### Return value -A [`values_view`](values-view-class.md) built from the second index into each tuple-like value in the range. +A [values_view](values-view-class.md) built from the second index into each tuple-like value in the range. ### Example: `values` @@ -1469,7 +1469,7 @@ int main() ### `all_t` -Provides the type of the view that [`all`](#all) returns. +Provides the type of the view that [all](#all) returns. ```cpp template @@ -1502,5 +1502,5 @@ int main() ## See also -[``](ranges.md)\ +[](ranges.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 e62bca1597d..d2c89ab8efd 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -18,7 +18,7 @@ But perhaps the most important benefit of ranges is that you can compose STL alg ## An example of ranges -Before ranges, if you wanted to transform the elements of a collection that met a certain criteria, you needed to introduce an intermediate step to hold the results between operations. For example, if you wanted to build a vector of squares from the elements in another vector that are divisible by 3, you could write something like: +Before ranges, if you wanted to transform the elements of a collection that met a certain criterion, you needed to introduce an intermediate step to hold the results between operations. For example, if you wanted to build a vector of squares from the elements in another vector that are divisible by three, you could write something like: ```cpp std::vector input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -39,12 +39,12 @@ auto output = input | std::views::filter([](const int n) {return n % 3 == 0; }) 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. -In the preceding code, each element that's divisible by 3 is combined with an operation to square that element. The pipe (`|`) symbol chains the operations together and is read left to right. +In the preceding code, each element that's divisible by three is combined with an operation to square that element. The pipe (`|`) symbol chains the operations together and is read left to right. 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`. +> 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 @@ -52,11 +52,11 @@ A view is a lightweight range. View operations--such as default construction, mo Views are created by range adapters, which are discussed in the following section. For more information about the classes that implement various views, see [View classes](view-classes.md). -How the elements in the view appear depends on the range adapter that you use to create the view. In the previous example, a range adapter takes a range and returns a view of the elements divisible by 3. The underlying range is unchanged. +How the elements in the view appear depends on the range adapter that you use to create the view. In the previous example, a range adapter takes a range and returns a view of the elements divisible by three. The underlying range is unchanged. -Views are composable, which is powerful. In the previous example, the view of vector elements that are divisible by 3 is combined with the view that squares those elements. +Views are composable, which is powerful. In the previous example, the view of vector elements that are divisible by three is combined with the view that squares those elements. -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 3. The `square` lambda breakpoint will be hit as the elements that are divisible by 3 are squared. +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 @@ -85,7 +85,7 @@ int main() Range adapters take a range and produce a view. Range adapters produce lazily evaluated views. That is, you don't incur the cost of transforming every element in the range to produce the view. You only pay the cost to process an element in the view when you access that element. -In the previous example, the `filter` range adapter creates a view named `input` that contains the elements that are divisible by 3. The `transform` range adapter takes the view of elements divisible by 3 and creates a view of those elements squared. +In the previous example, the `filter` range adapter creates a view named `input` that contains the elements that are divisible by three. The `transform` range adapter takes the view of elements divisible by three and creates a view of those elements squared. Range adapters can be chained together (composed), which is the heart of the power and flexibility of ranges. Composing range adapters allows you to overcome the problem that the previous STL algorithms aren't easily composable. @@ -101,19 +101,19 @@ The range algorithms are almost identical to the corresponding iterator-pair alg | Function | Description | |--|--| -| [`begin`](range-functions.md#begin)C++20 | Get an iterator to the first element in the range. | -| [`cbegin`](range-functions.md#cbegin)C++20 | Get a `const` iterator to the first element in the range. | -| [`cend`](range-functions.md#cend)C++20 | Get the sentinel at the end of the `const`-qualified range. | -| [`cdata`](range-functions.md#cdata)C++20 | Get a `const` pointer to the first element in the contiguous range. | -| [`crbegin`](range-functions.md#crbegin)C++20 | Get a reverse `const` iterator to the beginning of the range. | -| [`crend`](range-functions.md#crend)C++20 | Get the sentinel at the end of what `crbegin()` returns. | -| [`data`](range-functions.md#data)C++20 | Get a pointer to the first element in the contiguous range. | -| [`empty`](range-functions.md#empty)C++20 | Determine if the range is empty. | -| [`end`](range-functions.md#end)C++20 | Get the sentinel at the end of the range. | -| [`rbegin`](range-functions.md#rbegin)C++20 | Get a reverse iterator to the beginning of the range. | -| [`rend`](range-functions.md#rend)C++20 | Get a reverse iterator to the sentinel at the end of the range. | -| [`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. | +| [begin](range-functions.md#begin)C++20 | Get an iterator to the first element in the range. | +| [cbegin](range-functions.md#cbegin)C++20 | Get a `const` iterator to the first element in the range. | +| [cend](range-functions.md#cend)C++20 | Get the sentinel at the end of the `const`-qualified range. | +| [cdata](range-functions.md#cdata)C++20 | Get a `const` pointer to the first element in the contiguous range. | +| [crbegin](range-functions.md#crbegin)C++20 | Get a reverse `const` iterator to the beginning of the range. | +| [crend](range-functions.md#crend)C++20 | Get the sentinel at the end of what `crbegin()` returns. | +| [data](range-functions.md#data)C++20 | Get a pointer to the first element in the contiguous range. | +| [empty](range-functions.md#empty)C++20 | Determine if the range is empty. | +| [end](range-functions.md#end)C++20 | Get the sentinel at the end of the range. | +| [rbegin](range-functions.md#rbegin)C++20 | Get a reverse iterator to the beginning of the range. | +| [rend](range-functions.md#rend)C++20 | Get a reverse iterator to the sentinel at the end of the range. | +| [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 @@ -121,7 +121,7 @@ How you view the elements of a range depends on its underlying iterator type. Th 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 type of container that they can be applied to: +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 | |--|--|--| diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index bf366265a9d..32749e7fc09 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 (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 (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. 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. @@ -17,7 +17,7 @@ A view can be copied, assigned, and destroyed in constant time no matter how man You typically create a view by using a [range adapter](range-adaptors.md). Range adapters 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. -Here's a brief example of creating a view of the squares of the elements that are divisible by 3 in a vector: +Here's a brief example of creating a view of the squares of the elements that are divisible by three in a vector: ```cpp // requires /std:c++20 or later @@ -45,7 +45,7 @@ int main() 0 9 36 81 ``` -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. +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. @@ -100,27 +100,27 @@ The following view classes are defined in the `std::ranges` namespace. | View | Description | |--|--| -| [`basic_istream_view`](basic-istream-view-class.md)C++20 | A view of successive elements from an input stream. | -| [`common_view`](common-view-class.md)C++20 | Adapts a view that has different iterator/sentinel types into a view with the same iterator/sentinel types. | -| [`drop_view`](drop-view-class.md)C++20 | Created from another view, skipping the first `count` elements. | -| [`drop_while_view`](drop-while-view-class.md)C++20 | Created from another view, skipping leading elements as long as a predicate holds. | -| [`elements_view`](elements-view-class.md)C++20 | A view over the selected index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of all the `string` elements from each tuple. | -| [`empty_view`](empty-view-class.md)C++20 | A view with no elements. | -| [`filter_view`](filter-view-class.md)C++20 | Filters out elements of a range that don't match a predicate. | -| [`iota_view`](iota-view-class.md)C++20 | A generated view that contains a sequence of incrementing values. | -| [`join_view`](join-view-class.md)C++20 | Combines all the elements of multiple ranges into a single view. | -| [`keys_view`](keys-view-class.md)C++20 | A view over the first 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 `string` elements from each tuple. | -| [`lazy_split_view`](lazy-split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | -| [`owning_view`](owning-view-class.md)C++20 | Takes ownership of the elements from another range. | -| [`ref_view`](ref-view-class.md)C++20 | A view that references the elements that belong to another range. | -| [`reverse_view`](reverse-view-class.md)C++20 | Presents the elements of a range in reverse order. | -| [`single_view`](single-view-class.md)C++20 | A view that contains only one element. | -| [`split_view`](split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | -| [`subrange`](subrange-class.md)C++20 | A view of part of the elements of a range, as defined by a begin iterator and a sentinel. | -| [`take_view`](take-view-class.md)C++20 | Contains the specified number of elements taken from the front of a range. | -| [`take_while_view`](take-while-view-class.md)C++20 | Contains the leading elements of a range that match the given predicate. | -| [`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. | +| [basic_istream_view](basic-istream-view-class.md)C++20 | A view of successive elements from an input stream. | +| [common_view](common-view-class.md)C++20 | Adapts a view that has different iterator/sentinel types into a view with the same iterator/sentinel types. | +| [drop_view](drop-view-class.md)C++20 | Created from another view, skipping the first `count` elements. | +| [drop_while_view](drop-while-view-class.md)C++20 | Created from another view, skipping leading elements as long as a predicate holds. | +| [elements_view](elements-view-class.md)C++20 | A view over the selected index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of all the `string` elements from each tuple. | +| [empty_view](empty-view-class.md)C++20 | A view with no elements. | +| [filter_view](filter-view-class.md)C++20 | Filters out elements of a range that don't match a predicate. | +| [iota_view](iota-view-class.md)C++20 | A generated view that contains a sequence of incrementing values. | +| [join_view](join-view-class.md)C++20 | Combines all the elements of multiple ranges into a single view. | +| [keys_view](keys-view-class.md)C++20 | A view over the first 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 `string` elements from each tuple. | +| [lazy_split_view](lazy-split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | +| [owning_view](owning-view-class.md)C++20 | Takes ownership of the elements from another range. | +| [ref_view](ref-view-class.md)C++20 | A view that references the elements that belong to another range. | +| [reverse_view](reverse-view-class.md)C++20 | Presents the elements of a range in reverse order. | +| [single_view](single-view-class.md)C++20 | A view that contains only one element. | +| [split_view](split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | +| [subrange](subrange-class.md)C++20 | A view of part of the elements of a range, as defined by a begin iterator and a sentinel. | +| [take_view](take-view-class.md)C++20 | Contains the specified number of elements taken from the front of a range. | +| [take_while_view](take-while-view-class.md)C++20 | Contains the leading elements of a range that match the given predicate. | +| [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 adapters](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adapters in `std::views` to creating view classes directly. The range adapters are the intended access points, are easier to use, and in some cases are more efficient. @@ -134,13 +134,13 @@ Each view class topic has a **Characteristics** section after the syntax section * **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`, 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))`. -* **Borrowed range**: Specifies whether the view is a *borrowed range*. `borrowed_range` means you can use iterators for `T` after `T` is destroyed. +* **Borrowed range**: Specifies whether the view is a borrowed range. `borrowed_range` means you can use iterators for `T` after `T` is destroyed. No standard container is a borrowed range, because destroying the container frees the elements and invalidates any iterators. In that case, we say that the iterators are left "dangling" after destruction. - For example,`std::ranges::find()` typically returns an iterator to the found element in the range argument. If the range argument is a temporary (`rvalue`) container, it's a mistake to store the returned iterator and use it later because it's "dangling." + For example, `std::ranges::find()` typically returns an iterator to the found element in the range argument. If the range argument is a temporary (rvalue) container, it's a mistake to store the returned iterator and use it later because it's "dangling." - Range algorithms that return iterators (or subranges) do so only when their arguments are `lvalue` instances (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. + 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 @@ -164,5 +164,5 @@ The statement "requires `input_range` or better" means that the view can be used ## See also -[``](ranges.md)\ -[`range-adaptors`](range-adaptors.md) +[](ranges.md)\ +[range-adaptors](range-adaptors.md) From 6e04d557c32cf5be31b2821bba89d53a69fc5603 Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Fri, 28 Oct 2022 13:16:33 -0500 Subject: [PATCH 5/6] edit pass: range-adaptor-and-view-classes-topics --- docs/standard-library/range-adaptors.md | 120 ++++++++++++------------ docs/standard-library/ranges.md | 28 +++--- docs/standard-library/view-classes.md | 50 +++++----- 3 files changed, 99 insertions(+), 99 deletions(-) diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 8b6fd4c2056..5c81cc1191f 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -89,29 +89,29 @@ The following range adapters are available in the `std::views` namespace. The `s | Range adapter | Description | |--|--| -| [all](#all)C++20 | Create a view that refers to a range and its elements. | -| [common](#common)C++20 | Create a view that has the same iterator and sentinel types from a range that doesn't. | -| [counted](#counted)C++20 | Create a view of the first *n* elements of a range, starting from the specified location. | -| [drop](#drop)C++20 | Create a view from another view, skipping the specified number of elements from the front. | -| [drop_while](#drop_while)C++20 | Create a view that contains the elements of a range that remain after the leading elements that match the specified condition are dropped. | -| [elements](#elements)C++20 | Create a view of the selected index into each tuple-like value in a range. | -| [filter](#filter)C++20 | Create a view that contains the elements of a range that match the specified condition. | -| [iota](#iota)C++20 | Create a view that contains a sequence of increasing values. | -| [keys](#keys)C++20 | Create a view of the first index into each tuple-like value in a collection. | -| [lazy_split](#lazy_split)C++20 | Split a view into subranges based on a delimiter. | -| [reverse](#reverse)C++20 | Create a view of the elements of a range in reverse order. | -| [single](#single)C++20 | Create a view that contains one element. | -| [split](#split)C++20 | Split a view into subranges based on a delimiter. | -| [take](#take)C++20 | Create a view of the first *n* elements from another view. | -| [take_while](#take_while)C++20 | Create a view that contains the leading elements of a range that match the specified condition. | -| [transform](#transform)C++20 | Create a view of transformed elements from another view. | -| [values](#values)C++20 | Create a view of the second index into each tuple-like value in a collection. | +| [`all`](#all)C++20 | Create a view that refers to a range and its elements. | +| [`common`](#common)C++20 | Create a view that has the same iterator and sentinel types from a range that doesn't. | +| [`counted`](#counted)C++20 | Create a view of the first *n* elements of a range, starting from the specified location. | +| [`drop`](#drop)C++20 | Create a view from another view, skipping the specified number of elements from the front. | +| [`drop_while`](#drop_while)C++20 | Create a view that contains the elements of a range that remain after the leading elements that match the specified condition are dropped. | +| [`elements`](#elements)C++20 | Create a view of the selected index into each tuple-like value in a range. | +| [`filter`](#filter)C++20 | Create a view that contains the elements of a range that match the specified condition. | +| [`iota`](#iota)C++20 | Create a view that contains a sequence of increasing values. | +| [`keys`](#keys)C++20 | Create a view of the first index into each tuple-like value in a collection. | +| [`lazy_split`](#lazy_split)C++20 | Split a view into subranges based on a delimiter. | +| [`reverse`](#reverse)C++20 | Create a view of the elements of a range in reverse order. | +| [`single`](#single)C++20 | Create a view that contains one element. | +| [`split`](#split)C++20 | Split a view into subranges based on a delimiter. | +| [`take`](#take)C++20 | Create a view of the first *n* elements from another view. | +| [`take_while`](#take_while)C++20 | Create a view that contains the leading elements of a range that match the specified condition. | +| [`transform`](#transform)C++20 | Create a view of transformed elements from another view. | +| [`values`](#values)C++20 | Create a view of the second index into each tuple-like value in a collection. | In the previous table, a range adapter is typically described as taking a range and producing a view. To be precise, range adapters have a range argument that accepts one of the following: - The `cv-unqualified` type models `view`, and the argument is an rvalue or is copyable. - When you pass the argument as an lvalue, it must model `range` and live as long as the view. -- When you pass the argument as an rvalue, such as when calling [owning_view](owning-view-class.md), it must model `range` and `movable`. +- When you pass the argument as an rvalue, such as when calling [`owning_view`](owning-view-class.md), it must model `range` and `movable`. Range adapter functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. @@ -144,8 +144,8 @@ The range to create the view from. ### Return value - If `rg` is already a view, a copy of `rg`. -- If `rg` is a non-view lvalue, a [ref_view](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) -- If `rg` is a non-view rvalue such as a temporary object, or is the result of passing the range to `std::move`, an [owning_view](owning-view-class.md). +- If `rg` is a non-view lvalue, a [`ref_view`](ref-view-class.md) that refers to `rg`. (The lifetime of the view is tied to the lifetime of `rg`.) +- If `rg` is a non-view rvalue such as a temporary object, or is the result of passing the range to `std::move`, an [`owning_view`](owning-view-class.md). Use `std::views::all_t` to get the type of the returned view. @@ -205,7 +205,7 @@ The range to create the view from. ### Return value - `views::all(rg)` if `rg` is a range with the same iterator and sentinel type. -- [common_view(views::all(rg))](common-view-class.md) if `rg` has different iterator and sentinel types. +- [`common_view(views::all(rg))`](common-view-class.md) if `rg` has different iterator and sentinel types. ### Remarks @@ -257,7 +257,7 @@ The type of the iterator. `count`\ The number of elements to include in the view. Must be non-negative. -- If `count == 0`, an empty [span](span-class.md) is returned. +- If `count == 0`, an empty [`span`](span-class.md) is returned. - If `count` is greater than the number of elements in the range, the behavior is undefined. `it`\ @@ -265,11 +265,11 @@ 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` for arrays, vectors, and other containers that store their elements contiguously. Otherwise, a [`subrange`](subrange-class.md) is returned. ### Remarks -The included elements are `[it, count)`. +The included elements are `it` and `count`. After the view is created, the number of elements in the view stays the same, even if the range that it was created from changes. However, if the underlying range changes, accessing elements from the view might result in undefined behavior. @@ -340,18 +340,18 @@ The range that's used to create the view. A view of the underlying range, with the specified number of elements dropped from the front. -If you specify more elements to drop than exist in the underlying range, an [empty_view](empty-view-class.md) is returned. +If you specify more elements to drop than exist in the underlying range, an [`empty_view`](empty-view-class.md) is returned. -The returned view is typically, but not always, a specialization of [drop_view](drop-view-class.md). That is: +The returned view is typically, but not always, a specialization of [`drop_view`](drop-view-class.md). That is: -- If `V` is a specialization of [empty_view](empty-view-class.md), or is a specialization of [span](span-class.md), [basic_string_view](basic-string-view-class.md), [iota_view](iota-view-class.md), or [subrange](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. -- Otherwise, the result is a [drop_view](drop-view-class.md). +- If `V` is a specialization of [`empty_view`](empty-view-class.md), or is a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- Otherwise, the result is a [`drop_view`](drop-view-class.md). ### Remarks After it's created, the number of elements in the view stays the same even if the view that it was created from changes. However, if the underlying view changes, accessing elements in the returned view might result in undefined behavior. -`drop` is the opposite of [take](#take). +`drop` is the opposite of [`take`](#take). The code shown earlier as "2\)" can be used with pipe syntax: `collection | drop(5)`. Or it can be used with function call syntax: `drop(collection, 5)` or `drop(5)(collection)`. @@ -412,13 +412,13 @@ The underlying range to create the view from. ### Return value -A [drop_while_view](drop-while-view-class.md) that consists of the elements that remain when the leading elements that match the predicate are dropped. +A [`drop_while_view`](drop-while-view-class.md) that consists of the elements that remain when the leading elements that match the predicate are dropped. ### Remarks Stops dropping elements from `rg` as soon as the predicate returns `false`. -`drop_while` is the opposite of [take_while](#take_while). +`drop_while` is the opposite of [`take_while`](#take_while). The code shown earlier as "2\)" can be used with pipe syntax: `collection | drop_while(predicate)`. Or it can be used with function call syntax: `drop_while(collection, predicate)` or `drop_while(predicate)(collection)`. @@ -460,7 +460,7 @@ int main() ## `elements` -Create an [elements_view](elements-view-class.md), which is a view of the selected index into each tuple-like value in a range. For example, given a range of `std::tuple` values, create an `elements_view` of all the `string` elements from each tuple. +Create an [`elements_view`](elements-view-class.md), which is a view of the selected index into each tuple-like value in a range. For example, given a range of `std::tuple` values, create an `elements_view` of all the `string` elements from each tuple. ```cpp template @@ -480,7 +480,7 @@ The range of tuple-like values to create the view from. ### Return value -An [elements_view](elements-view-class.md) that consists of the selected index into each tuple-like value in a collection. +An [`elements_view`](elements-view-class.md) that consists of the selected index into each tuple-like value in a collection. ### Example: `elements` @@ -539,7 +539,7 @@ The type of the elements in the view. The view needs an element type, even thoug ### Return value -An [empty_view](empty-view-class.md). +An [`empty_view`](empty-view-class.md). ### Remarks @@ -593,7 +593,7 @@ The range to create the view from. ### Return value -A [filter_view](filter-view-class.md) that contains the elements of a range that match the predicate. +A [`filter_view`](filter-view-class.md) that contains the elements of a range that match the predicate. ### Remarks @@ -662,7 +662,7 @@ This value is one past the last value that will be in the sequence. For example, ### Return value -An [iota_view](iota-view-class.md) of a sequence of increasing values. +An [`iota_view`](iota-view-class.md) of a sequence of increasing values. ### Remarks @@ -719,7 +719,7 @@ The type of the elements to extract from the stream. ### Return value -A [basic_istream_view](basic-istream-view-class.md). +A [`basic_istream_view`](basic-istream-view-class.md). This range adapter is equivalent to `ranges::basic_istream_view(str)`, where `U` is the type of `str`. @@ -768,7 +768,7 @@ The range to create the view from. ### Return value -A [join_view](join-view-class.md) that contains the elements of all the ranges in the underlying range. +A [`join_view`](join-view-class.md) that contains the elements of all the ranges in the underlying range. ### Example: `join` @@ -800,7 +800,7 @@ The code shown earlier as "2\)" can be used with pipe syntax: `collection | join ## `keys` -Create a [keys_view](keys-view-class.md) of the first index into each tuple-like value in a collection. This is useful for extracting keys from associative containers. For example, given a range of `std::tuple`, create a view that consists of all the `string` elements from each tuple. +Create a [`keys_view`](keys-view-class.md) of the first index into each tuple-like value in a collection. This is useful for extracting keys from associative containers. For example, given a range of `std::tuple`, create a view that consists of all the `string` elements from each tuple. ```cpp template @@ -814,7 +814,7 @@ The type of the underlying range. ### Return value -A [keys_view](keys-view-class.md) that consists of the first index into each tuple-like value in the range. +A [`keys_view`](keys-view-class.md) that consists of the first index into each tuple-like value in the range. ### Example: `keys` @@ -905,13 +905,13 @@ The range to split. ### Return value -A [lazy_split_view](lazy-split-view-class.md) that contains one or more subranges and is the result of splitting the original range on `delimiter`. +A [`lazy_split_view`](lazy-split-view-class.md) that contains one or more subranges and is the result of splitting the original range on `delimiter`. ### Remarks The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adapter is [split](#split). The primary differences between `split_view` and `lazy_split_view` are: +A related adapter is [`split`](#split). The primary differences between `split_view` and `lazy_split_view` are: | View | Can split a `const` range | Range iterator | |--|--|--| @@ -989,11 +989,11 @@ The range to reverse. ### Return value -A view that presents the elements of the underlying range in reverse order. The returned view is typically, but not always, a specialization of [reverse_view](reverse-view-class.md). That is: +A view that presents the elements of the underlying range in reverse order. The returned view is typically, but not always, a specialization of [`reverse_view`](reverse-view-class.md). That is: - If `V` is a specialization of `reverse_view`, the result is the argument's underlying view. A double-reverse is a no-op (no operation). -- If `V` has the form `subrange, reverse_iterator>`, the result is a [subrange](subrange-class.md) of the unwrapped iterators. A double-reverse is a no-op. -- Otherwise, the result is a [reverse_view](reverse-view-class.md). +- If `V` has the form `subrange, reverse_iterator>`, the result is a [`subrange`](subrange-class.md) of the unwrapped iterators. A double-reverse is a no-op. +- Otherwise, the result is a [`reverse_view`](reverse-view-class.md). ### Remarks @@ -1051,7 +1051,7 @@ The value of the element to store in the view. ### Return value -An [single_view](single-view-class.md) that contains `t`. +An [`single_view`](single-view-class.md) that contains `t`. ### Remarks @@ -1109,13 +1109,13 @@ The range to split. ### Return value -A [split_view](split-view-class.md) that contains one or more subranges. +A [`split_view`](split-view-class.md) that contains one or more subranges. ### Remarks The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adapter is [lazy_split](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: +A related adapter is [`lazy_split`](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: | View | Can split a `const` range | Range type | |---|---|---| @@ -1196,16 +1196,16 @@ The number of elements to take from the front of `rg`. ### Return value -The returned view is typically, but not always, a specialization of [take_view](take-view-class.md). Specifically: +The returned view is typically, but not always, a specialization of [`take_view`](take-view-class.md). Specifically: -- If `V` is a specialization of [empty_view](empty-view-class.md), or is a specialization of [span](span-class.md), [basic_string_view](basic-string-view-class.md), [iota_view](iota-view-class.md), or [subrange](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. -- Otherwise, the result is a [take_view](take-view-class.md). +- If `V` is a specialization of [`empty_view`](empty-view-class.md), or is a specialization of [`span`](span-class.md), [`basic_string_view`](basic-string-view-class.md), [`iota_view`](iota-view-class.md), or [`subrange`](subrange-class.md) that is both `random_access_range` and `sized_range`, the result is a specialization of `V`. +- Otherwise, the result is a [`take_view`](take-view-class.md). ### Remarks If you specify more elements to take than exist in `rg`, all of the elements are taken. -`take` is the opposite of [drop](#drop). +`take` is the opposite of [`drop`](#drop). The code shown earlier as "2\)" can be used with pipe syntax: `collection | take(5)`. Or it can be used with function call syntax: `take(5, collection)` or `take(5)(collection)`. @@ -1269,13 +1269,13 @@ The range to create the view from. ### Return value -A [take_while_view](take-while-view-class.md) that consists of the first `count` elements that meet the specified criteria in the range. +A [`take_while_view`](take-while-view-class.md) that consists of the first `count` elements that meet the specified criteria in the range. ### Remarks Stops taking elements from `rg` after the predicate returns `false` or the range runs out of elements. -`take_while` is the opposite of [drop_while](#drop_while). +`take_while` is the opposite of [`drop_while`](#drop_while). The code shown earlier as "2\)" can be used with pipe syntax: `collection | take_while(pred)`. Or it can be used with function call syntax: `take_while(collection, pred)` or `take_while(pred)(collection)`. @@ -1341,7 +1341,7 @@ The range to create the view from. ### Return value -A [transform_view](transform-view-class.md) that contains the transformed elements of `rg`. +A [`transform_view`](transform-view-class.md) that contains the transformed elements of `rg`. ### Remarks @@ -1384,7 +1384,7 @@ int main() ## `values` -Create a [values_view](values-view-class.md) that consists of the second index into each tuple-like value in a collection. This is useful for making a view of the values in an associative container. For example, given a range of `std::tuple` values, create a view that consists of all the `int` elements from each tuple. +Create a [`values_view`](values-view-class.md) that consists of the second index into each tuple-like value in a collection. This is useful for making a view of the values in an associative container. For example, given a range of `std::tuple` values, create a view that consists of all the `int` elements from each tuple. ```cpp template @@ -1401,7 +1401,7 @@ The underlying range of tuple-like values. ### Return value -A [values_view](values-view-class.md) built from the second index into each tuple-like value in the range. +A [`values_view`](values-view-class.md) built from the second index into each tuple-like value in the range. ### Example: `values` @@ -1469,7 +1469,7 @@ int main() ### `all_t` -Provides the type of the view that [all](#all) returns. +Provides the type of the view that [`all`](#all) returns. ```cpp template @@ -1502,5 +1502,5 @@ int main() ## See also -[](ranges.md)\ -[view classes](view-classes.md) \ No newline at end of file +[``](ranges.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 d2c89ab8efd..6639c9ab251 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -44,7 +44,7 @@ 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`. +> 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 @@ -101,19 +101,19 @@ The range algorithms are almost identical to the corresponding iterator-pair alg | Function | Description | |--|--| -| [begin](range-functions.md#begin)C++20 | Get an iterator to the first element in the range. | -| [cbegin](range-functions.md#cbegin)C++20 | Get a `const` iterator to the first element in the range. | -| [cend](range-functions.md#cend)C++20 | Get the sentinel at the end of the `const`-qualified range. | -| [cdata](range-functions.md#cdata)C++20 | Get a `const` pointer to the first element in the contiguous range. | -| [crbegin](range-functions.md#crbegin)C++20 | Get a reverse `const` iterator to the beginning of the range. | -| [crend](range-functions.md#crend)C++20 | Get the sentinel at the end of what `crbegin()` returns. | -| [data](range-functions.md#data)C++20 | Get a pointer to the first element in the contiguous range. | -| [empty](range-functions.md#empty)C++20 | Determine if the range is empty. | -| [end](range-functions.md#end)C++20 | Get the sentinel at the end of the range. | -| [rbegin](range-functions.md#rbegin)C++20 | Get a reverse iterator to the beginning of the range. | -| [rend](range-functions.md#rend)C++20 | Get a reverse iterator to the sentinel at the end of the range. | -| [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. | +| [`begin`](range-functions.md#begin)C++20 | Get an iterator to the first element in the range. | +| [`cbegin`](range-functions.md#cbegin)C++20 | Get a `const` iterator to the first element in the range. | +| [`cend`](range-functions.md#cend)C++20 | Get the sentinel at the end of the `const`-qualified range. | +| [`cdata`](range-functions.md#cdata)C++20 | Get a `const` pointer to the first element in the contiguous range. | +| [`crbegin`](range-functions.md#crbegin)C++20 | Get a reverse `const` iterator to the beginning of the range. | +| [`crend`](range-functions.md#crend)C++20 | Get the sentinel at the end of what `crbegin()` returns. | +| [`data`](range-functions.md#data)C++20 | Get a pointer to the first element in the contiguous range. | +| [`empty`](range-functions.md#empty)C++20 | Determine if the range is empty. | +| [`end`](range-functions.md#end)C++20 | Get the sentinel at the end of the range. | +| [`rbegin`](range-functions.md#rbegin)C++20 | Get a reverse iterator to the beginning of the range. | +| [`rend`](range-functions.md#rend)C++20 | Get a reverse iterator to the sentinel at the end of the range. | +| [`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 diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 32749e7fc09..273021b7671 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 (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 (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. 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. @@ -45,7 +45,7 @@ int main() 0 9 36 81 ``` -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. +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. @@ -100,27 +100,27 @@ The following view classes are defined in the `std::ranges` namespace. | View | Description | |--|--| -| [basic_istream_view](basic-istream-view-class.md)C++20 | A view of successive elements from an input stream. | -| [common_view](common-view-class.md)C++20 | Adapts a view that has different iterator/sentinel types into a view with the same iterator/sentinel types. | -| [drop_view](drop-view-class.md)C++20 | Created from another view, skipping the first `count` elements. | -| [drop_while_view](drop-while-view-class.md)C++20 | Created from another view, skipping leading elements as long as a predicate holds. | -| [elements_view](elements-view-class.md)C++20 | A view over the selected index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of all the `string` elements from each tuple. | -| [empty_view](empty-view-class.md)C++20 | A view with no elements. | -| [filter_view](filter-view-class.md)C++20 | Filters out elements of a range that don't match a predicate. | -| [iota_view](iota-view-class.md)C++20 | A generated view that contains a sequence of incrementing values. | -| [join_view](join-view-class.md)C++20 | Combines all the elements of multiple ranges into a single view. | -| [keys_view](keys-view-class.md)C++20 | A view over the first 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 `string` elements from each tuple. | -| [lazy_split_view](lazy-split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | -| [owning_view](owning-view-class.md)C++20 | Takes ownership of the elements from another range. | -| [ref_view](ref-view-class.md)C++20 | A view that references the elements that belong to another range. | -| [reverse_view](reverse-view-class.md)C++20 | Presents the elements of a range in reverse order. | -| [single_view](single-view-class.md)C++20 | A view that contains only one element. | -| [split_view](split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | -| [subrange](subrange-class.md)C++20 | A view of part of the elements of a range, as defined by a begin iterator and a sentinel. | -| [take_view](take-view-class.md)C++20 | Contains the specified number of elements taken from the front of a range. | -| [take_while_view](take-while-view-class.md)C++20 | Contains the leading elements of a range that match the given predicate. | -| [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. | +| [`basic_istream_view`](basic-istream-view-class.md)C++20 | A view of successive elements from an input stream. | +| [`common_view`](common-view-class.md)C++20 | Adapts a view that has different iterator/sentinel types into a view with the same iterator/sentinel types. | +| [`drop_view`](drop-view-class.md)C++20 | Created from another view, skipping the first `count` elements. | +| [`drop_while_view`](drop-while-view-class.md)C++20 | Created from another view, skipping leading elements as long as a predicate holds. | +| [`elements_view`](elements-view-class.md)C++20 | A view over the selected index into each tuple-like value in a collection. For example, given a range of `std::tuple` values, create a view that consists of all the `string` elements from each tuple. | +| [`empty_view`](empty-view-class.md)C++20 | A view with no elements. | +| [`filter_view`](filter-view-class.md)C++20 | Filters out elements of a range that don't match a predicate. | +| [`iota_view`](iota-view-class.md)C++20 | A generated view that contains a sequence of incrementing values. | +| [`join_view`](join-view-class.md)C++20 | Combines all the elements of multiple ranges into a single view. | +| [`keys_view`](keys-view-class.md)C++20 | A view over the first 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 `string` elements from each tuple. | +| [`lazy_split_view`](lazy-split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | +| [`owning_view`](owning-view-class.md)C++20 | Takes ownership of the elements from another range. | +| [`ref_view`](ref-view-class.md)C++20 | A view that references the elements that belong to another range. | +| [`reverse_view`](reverse-view-class.md)C++20 | Presents the elements of a range in reverse order. | +| [`single_view`](single-view-class.md)C++20 | A view that contains only one element. | +| [`split_view`](split-view-class.md)C++20 | Splits a view into subranges based on a delimiter. | +| [`subrange`](subrange-class.md)C++20 | A view of part of the elements of a range, as defined by a begin iterator and a sentinel. | +| [`take_view`](take-view-class.md)C++20 | Contains the specified number of elements taken from the front of a range. | +| [`take_while_view`](take-while-view-class.md)C++20 | Contains the leading elements of a range that match the given predicate. | +| [`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 adapters](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adapters in `std::views` to creating view classes directly. The range adapters are the intended access points, are easier to use, and in some cases are more efficient. @@ -164,5 +164,5 @@ The statement "requires `input_range` or better" means that the view can be used ## See also -[](ranges.md)\ -[range-adaptors](range-adaptors.md) +[``](ranges.md)\ +[Range adapters](range-adaptors.md) From 2155469a52bd0c4752dbb41b633a6f9696621041 Mon Sep 17 00:00:00 2001 From: Shawn Jackson Date: Mon, 31 Oct 2022 17:44:45 -0500 Subject: [PATCH 6/6] reverting adaptor --- docs/standard-library/range-adaptors.md | 64 ++++++++++++------------- docs/standard-library/ranges.md | 16 +++---- docs/standard-library/view-classes.md | 10 ++-- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/docs/standard-library/range-adaptors.md b/docs/standard-library/range-adaptors.md index 5c81cc1191f..c3f56cfe75d 100644 --- a/docs/standard-library/range-adaptors.md +++ b/docs/standard-library/range-adaptors.md @@ -1,13 +1,13 @@ --- -description: "Learn more about range adapters, which create views on ranges." -title: "Range adapters" +description: "Learn more about range adaptors, which create views on ranges." +title: "Range adaptors" ms.date: 10/19/2022 f1_keywords: ["ranges/std::all", "ranges/std::all_t", "ranges/std::common", "ranges/std::counted", "ranges/std::drop", "ranges/std::drop_while", "ranges/std::elements", "ranges/std::filter", "ranges/std::iota", "ranges/std::join", "ranges/std::keys", "ranges/std::lazy_split", "ranges/std::reverse", "ranges/std::split", "ranges/std::subrange", "ranges/std::take", "ranges/std::take_while", "ranges/std::transform"] helpviewer_keywords: ["std::ranges [C++], all", "std::ranges [C++], all_t", "std::ranges [C++], common", "std::ranges [C++], counted", "std::ranges [C++], drop", "std::ranges [C++], drop_while", "std::ranges [C++], elements", "std::ranges [C++], filter", "std::ranges [C++], iota", "std::ranges [C++], join", "std::ranges [C++], keys", "std::ranges [C++], lazy_split", "std::ranges [C++], reverse", "std::ranges [C++], split", "std::ranges [C++], subrange", "std::ranges [C++], take", "std::ranges [C++], take_while", "std::ranges [C++], transform"] --- -# Range adapters +# Range adaptors -Range adapters 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 adapter in `std::ranges::views` instead of creating the view types directly. The adapters 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 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. A view is a lightweight object that refers to elements from a range. A view can: @@ -44,9 +44,9 @@ int main() 0 9 36 81 ``` -The first range adapter, `std::views::filter`, provides a view that contains the elements from `input` that are divisible by three. The other range adapter, `std::views::transform`, takes the view that contains the elements divisible by three and provides a view of the square of those elements. +The first range adaptor, `std::views::filter`, provides a view that contains the elements from `input` that are divisible by three. The other range adaptor, `std::views::transform`, takes the view that contains the elements divisible by three and provides a view of the square of those elements. -When a range adapter 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. +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. @@ -77,17 +77,17 @@ int main() } ``` -Range adapters come in many forms. For example, there are range adapters that allow you to produce a view by: +Range adaptors come in many forms. For example, there are range adaptors that allow you to produce a view by: - Filtering another range based on a predicate (`view::filter`). - Transforming the elements in a range (`view::transform`). - Splitting a range (`view::split`). -Range adapters can be chained together (composed). That's where the power and flexibility of ranges are most apparent. Composing range adapters allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms, which is that they aren't easy to chain together. +Range adaptors can be chained together (composed). That's where the power and flexibility of ranges are most apparent. Composing range adaptors allows you to overcome a core problem with the previous Standard Template Library (STL) algorithms, which is that they aren't easy to chain together. -The following range adapters are available in the `std::views` namespace. The `std::views` namespace is a convenience alias for `std::ranges::views`. +The following range adaptors are available in the `std::views` namespace. The `std::views` namespace is a convenience alias for `std::ranges::views`. -| Range adapter | Description | +| Range adaptor | Description | |--|--| | [`all`](#all)C++20 | Create a view that refers to a range and its elements. | | [`common`](#common)C++20 | Create a view that has the same iterator and sentinel types from a range that doesn't. | @@ -107,15 +107,15 @@ The following range adapters are available in the `std::views` namespace. The `s | [`transform`](#transform)C++20 | Create a view of transformed elements from another view. | | [`values`](#values)C++20 | Create a view of the second index into each tuple-like value in a collection. | -In the previous table, a range adapter is typically described as taking a range and producing a view. To be precise, range adapters have a range argument that accepts one of the following: +In the previous table, a range adaptor is typically described as taking a range and producing a view. To be precise, range adaptors have a range argument that accepts one of the following: - The `cv-unqualified` type models `view`, and the argument is an rvalue or is copyable. - When you pass the argument as an lvalue, it must model `range` and live as long as the view. - When you pass the argument as an rvalue, such as when calling [`owning_view`](owning-view-class.md), it must model `range` and `movable`. -Range adapter functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. +Range adaptor functions are typically [function objects](https://eel.is/c++draft/function.objects), which look like function calls and enforce constraints on the types that can be passed. -You can pass range adapters and the result of pipe operations (`|`) to code that expects function objects. In the following example, the view that the `split` range adapter creates is passed to the `transform` range adapter as if by a function call, because the `transform` range adapter is a function object. +You can pass range adaptors and the result of pipe operations (`|`) to code that expects function objects. In the following example, the view that the `split` range adaptor creates is passed to the `transform` range adaptor as if by a function call, because the `transform` range adaptor is a function object. ```cpp std::map x = {{0, "Hello, world"}, {42, "Goodbye, world"}}; @@ -151,7 +151,7 @@ Use `std::views::all_t` to get the type of the returned view. ### Remarks -This range adapter is the best way to convert a range into a view. One reason to create a view from a range is to pass it by value at low cost, if passing the range by value could be expensive. +This range adaptor is the best way to convert a range into a view. One reason to create a view from a range is to pass it by value at low cost, if passing the range by value could be expensive. Getting a view for a range is a useful alternative to passing a heavyweight range by value because views are inexpensive to create, copy, and destroy. A possible exception is `owning_view`, which is a view that owns the underlying range. @@ -209,7 +209,7 @@ The range to create the view from. ### Remarks -When an API requires the begin iterator and end sentinel to have the same type, and the view that you're using doesn't meet that requirement (or you don't know if it does), use this range adapter to create a `common_view`. It guarantees that the type of the begin iterator and the type of the end sentinel are the same. +When an API requires the begin iterator and end sentinel to have the same type, and the view that you're using doesn't meet that requirement (or you don't know if it does), use this range adaptor to create a `common_view`. It guarantees that the type of the begin iterator and the type of the end sentinel are the same. ### Example: `common` @@ -396,7 +396,7 @@ Create a view that contains the elements of a range that remain after the leadin constexpr ranges::view auto drop_while(R&& rg, P&& predicate); 2) template -constexpr /*range adapter closure*/ drop_while(P&& predicate); +constexpr /*range adaptor closure*/ drop_while(P&& predicate); ``` ### Parameters @@ -574,7 +574,7 @@ Create a view that contains the elements of a range that match the specified con constexpr ranges::view auto filter(R&& rg, P&& predicate); 2) template -constexpr /*range adapter closure*/ filter(P&& predicate); +constexpr /*range adaptor closure*/ filter(P&& predicate); ``` ### Parameters @@ -686,7 +686,7 @@ void print(auto&& v) int main() { - // create an iota view with its range adapter (preferred) + // create an iota view with its range adaptor (preferred) print(std::views::iota(0, 5)); // outputs 0 1 2 3 4 // create an iota_view class directly @@ -722,7 +722,7 @@ The type of the elements to extract from the stream. A [`basic_istream_view`](basic-istream-view-class.md). -This range adapter is equivalent to `ranges::basic_istream_view(str)`, where `U` is the type of `str`. +This range adaptor is equivalent to `ranges::basic_istream_view(str)`, where `U` is the type of `str`. ### Example: `istream` @@ -755,7 +755,7 @@ Create a view that combines all the elements of multiple ranges into a single vi 1) template [[nodiscard]] constexpr ranges::view auto join(R&& rg) const noexcept; -2) inline constexpr /*range adapter closure*/ join(); +2) inline constexpr /*range adaptor closure*/ join(); ``` ### Parameters @@ -864,7 +864,7 @@ int main() {"Windows 2000", 2000} }; - // Another way to call the range adapter is by using '|' + // Another way to call the range adaptor is by using '|' for (std::string version : windows | std::views::keys) { std::cout << version << ' '; // Windows 1.0 Windows 2.0 Windows 3.0 ... @@ -886,7 +886,7 @@ Split a range into subranges based on a delimiter. The delimiter can be a single constexpr view auto lazy_split(R&& rg, Pattern&& delimiter); 2) template -constexpr /*range adapter closure*/ lazy_split(Pattern&& delimiter); +constexpr /*range adaptor closure*/ lazy_split(Pattern&& delimiter); ``` ### Parameters @@ -911,7 +911,7 @@ A [`lazy_split_view`](lazy-split-view-class.md) that contains one or more subran The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adapter is [`split`](#split). The primary differences between `split_view` and `lazy_split_view` are: +A related adaptor is [`split`](#split). The primary differences between `split_view` and `lazy_split_view` are: | View | Can split a `const` range | Range iterator | |--|--|--| @@ -976,7 +976,7 @@ Create a view of the elements of a range in reverse order. 1) template constexpr ranges::view auto reverse(R&& rg); -2) inline constexpr /*range adapter closure*/ reverse(); +2) inline constexpr /*range adaptor closure*/ reverse(); ``` ### Parameters @@ -1018,7 +1018,7 @@ int main() } std::cout << '\n'; - // using the range adapter without using the pipe syntax + // using the range adaptor without using the pipe syntax auto rv2 = std::views::reverse(v); for (auto &&e : rv2) // outputs 6 5 -4 3 2 1 0 { @@ -1090,7 +1090,7 @@ Split a view into subranges based on a delimiter. The delimiter can be a single constexpr view auto split(R&& rg, Pattern&& delimiter); 2) template -constexpr /*range adapter closure*/ split(Pattern&& delimiter); +constexpr /*range adaptor closure*/ split(Pattern&& delimiter); ``` ### Parameters @@ -1115,7 +1115,7 @@ A [`split_view`](split-view-class.md) that contains one or more subranges. The delimiter isn't part of the result. For example, if you split the range `1,2,3` on the value `2`, you get two subranges: `1` and `3`. -A related adapter is [`lazy_split`](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: +A related adaptor is [`lazy_split`](#lazy_split). The primary differences between `split_view` and `lazy_split_view` are: | View | Can split a `const` range | Range type | |---|---|---| @@ -1180,7 +1180,7 @@ Create a view that contains the specified number of elements taken from the fron constexpr ranges::view auto take(R&& rg, ranges::range_difference_type count); 2) template -constexpr /*range adapter closure*/ take(DifferenceType&& count); +constexpr /*range adaptor closure*/ take(DifferenceType&& count); ``` ### Parameters @@ -1250,7 +1250,7 @@ Create a view that contains the leading elements of a range that match the speci constexpr ranges::view auto take_while(R&& rg, P&& predicate); 2) template -constexpr /*range adapter closure*/ take_while(P&& predicate); +constexpr /*range adaptor closure*/ take_while(P&& predicate); ``` ### Parameters @@ -1322,7 +1322,7 @@ Create a view of elements, each of which is a transformation of an element in th constexpr ranges::view auto transform(R&& rg, F&& fun); 2) template -constexpr /*range adapter closure*/ transform(F&& fun); +constexpr /*range adaptor closure*/ transform(F&& fun); ``` ### Parameters @@ -1451,7 +1451,7 @@ int main() {"Windows 2000", 2000} }; - // Another way to call the range adapter by using '|' + // Another way to call the range adaptor by using '|' // Create a values_view that contains the year from each pair for (int years : windows | std::views::values) { @@ -1465,7 +1465,7 @@ int main() 1985 1987 1990 1992 1993 1995 1996 1995 1998 1985 2000 ``` -## Range adapter type aliases +## Range adaptor type aliases ### `all_t` diff --git a/docs/standard-library/ranges.md b/docs/standard-library/ranges.md index 6639c9ab251..ed4390f9103 100644 --- a/docs/standard-library/ranges.md +++ b/docs/standard-library/ranges.md @@ -50,9 +50,9 @@ The result, `output`, is itself a kind of range called a *view*. 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. -Views are created by range adapters, which are discussed in the following section. For more information about the classes that implement various views, see [View classes](view-classes.md). +Views are created by range adaptors, which are discussed in the following section. For more information about the classes that implement various views, see [View classes](view-classes.md). -How the elements in the view appear depends on the range adapter that you use to create the view. In the previous example, a range adapter takes a range and returns a view of the elements divisible by three. The underlying range is unchanged. +How the elements in the view appear depends on the range adaptor that you use to create the view. In the previous example, a range adaptor takes a range and returns a view of the elements divisible by three. The underlying range is unchanged. Views are composable, which is powerful. In the previous example, the view of vector elements that are divisible by three is combined with the view that squares those elements. @@ -81,15 +81,15 @@ int main() } ``` -## Range adapters +## Range adaptors -Range adapters take a range and produce a view. Range adapters produce lazily evaluated views. That is, you don't incur the cost of transforming every element in the range to produce the view. You only pay the cost to process an element in the view when you access that element. +Range adaptors take a range and produce a view. Range adaptors produce lazily evaluated views. That is, you don't incur the cost of transforming every element in the range to produce the view. You only pay the cost to process an element in the view when you access that element. -In the previous example, the `filter` range adapter creates a view named `input` that contains the elements that are divisible by three. The `transform` range adapter takes the view of elements divisible by three and creates a view of those elements squared. +In the previous example, the `filter` range adaptor creates a view named `input` that contains the elements that are divisible by three. The `transform` range adaptor takes the view of elements divisible by three and creates a view of those elements squared. -Range adapters can be chained together (composed), which is the heart of the power and flexibility of ranges. Composing range adapters allows you to overcome the problem that the previous STL algorithms aren't easily composable. +Range adaptors can be chained together (composed), which is the heart of the power and flexibility of ranges. Composing range adaptors allows you to overcome the problem that the previous STL algorithms aren't easily composable. -For more information about creating views, see [Range adapters](range-adaptors.md). +For more information about creating views, see [Range adaptors](range-adaptors.md). ## Range algorithms @@ -134,5 +134,5 @@ The range concepts mirror the hierarchy of iterator categories. The following ta ## See also [Range functions](range-functions.md)\ -[Range adapters](range-adaptors.md)\ +[Range adaptors](range-adaptors.md)\ [Header files reference](../standard-library/cpp-standard-library-header-files.md) \ No newline at end of file diff --git a/docs/standard-library/view-classes.md b/docs/standard-library/view-classes.md index 273021b7671..513e1cbe4ce 100644 --- a/docs/standard-library/view-classes.md +++ b/docs/standard-library/view-classes.md @@ -15,7 +15,7 @@ For example, you could create a view that provides only the even elements from a 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. -You typically create a view by using a [range adapter](range-adaptors.md). Range adapters 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. +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. Here's a brief example of creating a view of the squares of the elements that are divisible by three in a vector: @@ -122,13 +122,13 @@ 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 adapters](range-adaptors.md) in the `std:views` namespace that creates them. Prefer the adapters in `std::views` to creating view classes directly. The range adapters 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 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 Each view class topic has a **Characteristics** section after the syntax section. The **Characteristics** section has the following entries: -* **Range adapter**: A link to the range adapter that creates the view. You typically use a range adapter to create a view rather than create a view class directly, so it's listed here for convenience. +* **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. * **Element type**: The type of the elements that the view's iterator returns. @@ -145,7 +145,7 @@ Each view class topic has a **Characteristics** section after the syntax section ### Iterator hierarchy -The iterator category that **Range adapter** and **View iterator category** mention in the **Characteristics** section refers to the hierarchy of iterators that ranges and views support. +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. That hierarchy, in increasing order of capability, is: @@ -165,4 +165,4 @@ The statement "requires `input_range` or better" means that the view can be used ## See also [``](ranges.md)\ -[Range adapters](range-adaptors.md) +[Range adaptors](range-adaptors.md)