Skip to content

Commit 222845b

Browse files
TylerMSFTTylerMSFT
authored andcommitted
more draft
1 parent a429f23 commit 222845b

1 file changed

Lines changed: 19 additions & 21 deletions

File tree

docs/standard-library/ranges.md

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ helpviewer_keywords: ["ranges header"]
1010

1111
At a high level, a range is something you can iterate over. A range is a rich abstraction over iterators that simplifies and amplifies your ability to use the Standard Template Library (STL).
1212

13-
STL algorithms usually take iterators that point to the collection they operate on. But generally speaking, you want to operate on the entire collection. Consider how you sort a `vector` today. To call `std::sort()`, you pass two iterators marking the beginning and end of the `vector`. That's flexible, but is noisy since much of the time you just want to sort the entire `vector`, but you still have to pass the beginning and end of what to sort.
13+
STL algorithms usually take iterators that point to the collection they operate on. But you usually want to operate on the entire collection. Consider how you sort a `vector` today. To call `std::sort()`, you pass two iterators marking the beginning and end of the `vector`. That's flexible, but is noisy since much of the time you just want to sort the entire `vector`, yet you still have to pass the beginning and end of what to sort.
1414

15-
With ranges, you can call `std::ranges::sort(myVector);`. It is treated as if you had called `std::sort(myVector.begin(), myVector.end());` In range libraries, in addition to taking iterators, STL algorithms can take ranges as parameters. Examples of range algorithms available in `<algorithm>` 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`.
15+
With ranges, you can call `std::ranges::sort(myVector);` It is treated as if you had called `std::sort(myVector.begin(), myVector.end());` In range libraries, in addition to taking iterators, algorithms can take ranges as parameters. Examples of range algorithms available in `<algorithm>` 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`.
1616

17-
Simplified code that is more readable is great, but the benefits of ranges extend further to making it much easier to filter and transform collections of data, and to compose STL algorithms more easily.
17+
More readable and easier to write code is great, but the benefits of ranges goes further than that. They also make it much easier to filter and transform collections of data, and to compose STL algorithms more easily.
1818

1919
Because ranges don't own elements like a container does, they are lightweight.
2020

@@ -27,30 +27,32 @@ std::copy_if(input.begin(), input.end(), std::back_inserter(intermediate), [](co
2727
std::transform(intermediate.begin(), intermediate.end(), std::back_inserter(output), [](const int i) {return i*i; });
2828
```
2929
30-
With ranges, you can instead write this as:
30+
With ranges, you can write this as:
3131
3232
```cpp
3333
// requires /std:c++latest
3434
std::vector<int> input = { 1, 2, 3, 5, 8, 13, 21, 34, 45, 79 };
3535
auto output = input | std::views::filter([](const int n) {return n % 3 == 0; }) | std::views::transform([](const int n) {return n * n; });
3636
```
37-
> [!NOTE] The ranges examples need to be compiled with the [`/std:c++latest`](../build/reference/std-specify-language-standard-version.md) compiler option.
3837

39-
In addition to being a little easier to read, it avoid the memory allocation required for `intermediate` in the non-ranges example.
38+
In addition to being easier to read, it avoids the memory allocation required for `intermediate` in the non-ranges example.
4039

41-
In the code above, the input is first filtered to just the entries that are divisible by three. The result is combined with a transformation that squares those elements (the ones divisible by three). The '`|`' symbol chains the range view operations together, and is read left to right.
40+
In the code above, each element that is divisible by three is combined with a transformation to square that element. The '`|`' symbol chains the operations together, and is read left to right.
4241

4342
The result, `output`, is itself a type of range called a view, which is discussed next.
4443

44+
> [!NOTE] The ranges examples require the [`/std:c++latest`](../build/reference/std-specify-language-standard-version.md) compiler option.
45+
46+
4547
## Views
4648

4749
A view is essentially a range that takes another range and transforms it in the way that you specify.
4850

49-
A view is lightweight. Like a range, a view doesn't own the elements it provides access to. The time it takes to copy, move, or assign a view is constant, regardless of how many elements it points to.
51+
A view is lightweight. Like a range, it doesn't own the elements it provides access to. The time it takes to copy, move, or assign a view is constant, regardless of how many elements it points to.
5052

51-
Views are composable. In the example above, the view of vector elements that are divisible by three is then combined with the view that squares those elements.
53+
Views are composable. In the example above, the view of vector elements that are divisible by three is combined with the view that squares those elements.
5254

53-
The elements of a view are evaluated lazily. That is, the transformation you apply to yield elements in a view is not evaluated until you ask for an 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 first breakpoint as every element is tested for divisibility by three, and then the second breakpoint as the ones that are divisible by three are squared.
55+
The elements of a view are evaluated lazily. That is, the transformations you apply to yield the elements in a view are not evaluated until you ask for an element in the view. 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. Then you'll see the `square` lambda hit as those elements that are divisible by three are squared.
5456

5557
```cpp
5658
// requires /std:c++latest
@@ -77,36 +79,32 @@ int main()
7779

7880
## View adaptors
7981

80-
A view adaptor provides a view over a range. The range being viewed remains unchanged. The produced view doesn't own any elements. Instead, a view allows you to iterate over the underlying range, but using customized behavior that you specify.
82+
A view adaptor provides a view over a range. The range being viewed is not changed. A view doesn't own any elements. Instead, a view allows you to iterate over the underlying range, but using customized behavior that you specify.
8183

8284
In the example above, the first view acts like an iterator that only provides the elements of `input` that are divisible by three. The other view acts like an iterator that takes the elements divisible by three, and provides their square.
8385

84-
The `<ranges>` library provides many kinds of view adaptors. In addition to the filter and transform views above, there are views that take or skip the first N elements of another view, reverse the order of a view, join views, skip elements of another view until a condition is met, transform the elements of another view, among others.
86+
The `<ranges>` library provides many kinds of view adaptors. In addition to the filter and transform views above, there are views that take or skip the first N elements of another view, reverse the order of a view, join views, skip elements of another view until a condition is met, transform the elements of another view, and more.
8587

8688
## Range adaptors
8789

8890
A range adaptor produces a new range from an existing range. Views, discussed above, are a kind of range adaptor.
8991

90-
Range adaptors produce lazily evaluated ranges. That is, you don't incur the cost of transforming every element in the range; only the ones that you access.
92+
Range adaptors produce lazily evaluated ranges. That is, you don't incur the cost of transforming every element in the range--only the ones that you access.
9193

9294
Range adaptors come in many forms. For example, there are range adaptors that allow you to filter another range based on a predicate (`view::filter()`), transform the elements in a range (`view::transform`), split a range (`view::split()`), and more.
9395

94-
Range adaptors can be chained, as shown in the example in this article. And that's where the true power of ranges lies, in the ability to chain various transformations together.
96+
Range adaptors can be chained, which is where the power of ranges express itself.
9597

9698
## Range algorithms
9799

98-
Range algorithms have been introduced that take a range for an argument. `std::ranges::sort(myVector);` is an example.
99-
100-
The range algorithms are lazy, meaning that they operate on the range only when an element is accessed. They can work directly on a container, and are easily composed.
100+
Range algorithms have been introduced that can take ranges for an argument. For example, `std::ranges::sort(myVector);`
101101

102-
Range-based algorithms are basically iterator-based algorithms where instead of taking two iterators, they take a range, instead.
102+
The range algorithms are lazy, meaning that they operate on the range only when an element is accessed. They can work directly on a container, and can be easily chained together.
103103

104104
## Types of ranges
105105

106-
What you can do with a range depends on the underlying iterator type. Range concepts are named to reflect the traversal category its iterators support.
106+
What you can do with a range depends on the underlying iterator type of the range. There are different kinds of ranges, called refinements. The different kinds of ranges are codified as C++ 20 concepts. This table lists various range concepts, along with the type of container they can be applied to:
107107

108-
There are different kinds, or refinements, of ranges, that are codified as concepts. This table lists them, along with the type of container they can be applied to:
109-
j
110108
| Range refinement | Description | Supported containers |
111109
|--|--|--|
112110
| `std::ranges::input_range` | Can iterate from beginning to end at least once | `std::forward_list`<br>`std::unordered_map`<br>`std::unordered_multimap`<br>`std::unordered_set`<br>`std::unordered_multiset`<br>`basic_istream_view` |

0 commit comments

Comments
 (0)