Skip to content

Commit ee2b577

Browse files
Add a section on coroutines.
1 parent 2be1f10 commit ee2b577

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

CPP20.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words.
55

66
C++20 includes the following new language features:
7+
- [coroutines](#coroutines)
78
- [concepts](#concepts)
89
- [designated initializers](#designated-initializers)
910
- [template syntax for lambdas](#template-syntax-for-lambdas)
@@ -34,6 +35,54 @@ C++20 includes the following new library features:
3435

3536
## C++20 Language Features
3637

38+
### Coroutines
39+
_Coroutines_ are special functions that can have their execution suspended and resumed. To define a coroutine, the `co_return`, `co_await`, or `co_yield` keywords must be present in the function's body. C++20's coroutines are stackless; unless optimized out by the compiler, their state is allocated on the heap.
40+
41+
An example of a coroutine is a _generator_ function, which yields (i.e. generates) a value at each invocation:
42+
```c++
43+
generator<int> range(int start, int end) {
44+
while (start < end) {
45+
co_yield start;
46+
start++;
47+
}
48+
49+
// Implicit co_return at the end of this function:
50+
// co_return;
51+
}
52+
53+
for (int n : range(0, 10)) {
54+
std::cout << n << std::endl;
55+
}
56+
```
57+
The above `range` generator function generates values starting at `start` until `end` (exclusive), with each iteration step yielding the current value stored in `start`. The generator maintains its state across each invocation of `range` (in this case, the invocation is for each iteration in the for loop). `co_yield` takes the given expression, yields (i.e. returns) its value, and suspends the coroutine at that point. Upon resuming, execution continues after the `co_yield`.
58+
59+
Another example of a coroutine is a _task_, which is an asynchronous computation that is executed when the task is awaited:
60+
```c++
61+
task<void> echo(socket s) {
62+
for (;;) {
63+
auto data = co_await s.async_read();
64+
co_await async_write(s, data);
65+
}
66+
67+
// Implicit co_return at the end of this function:
68+
// co_return;
69+
}
70+
```
71+
In this example, the `co_await` keyword is introduced. This keyword takes an expression and suspends execution if the thing you're awaiting on (in this case, the read or write) is not ready, otherwise you continue execution. (Note that under the hood, `co_yield` uses `co_await`.)
72+
73+
Using a task to lazily evaluate a value:
74+
```c++
75+
task<int> calculate_meaning_of_life() {
76+
co_return 42;
77+
}
78+
79+
auto meaning_of_life = calculate_meaning_of_life();
80+
// ...
81+
co_await meaning_of_life; // == 42
82+
```
83+
84+
**Note:** While these examples illustrate how to use coroutines at a basic level, there is lots more going on when the code is compiled. These examples are not meant to be complete coverage of C++20's coroutines. Since the `generator` and `task` classes are not provided by the standard library yet, I used the cppcoro library to compile these examples.
85+
3786
### Concepts
3887
_Concepts_ are named compile-time predicates which constrain types. They take the following form:
3988
```

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words.
55

66
C++20 includes the following new language features:
7+
- [coroutines](#coroutines)
78
- [concepts](#concepts)
89
- [designated initializers](#designated-initializers)
910
- [template syntax for lambdas](#template-syntax-for-lambdas)
@@ -127,6 +128,54 @@ C++11 includes the following new library features:
127128

128129
## C++20 Language Features
129130

131+
### Coroutines
132+
_Coroutines_ are special functions that can have their execution suspended and resumed. To define a coroutine, the `co_return`, `co_await`, or `co_yield` keywords must be present in the function's body. C++20's coroutines are stackless; unless optimized out by the compiler, their state is allocated on the heap.
133+
134+
An example of a coroutine is a _generator_ function, which yields (i.e. generates) a value at each invocation:
135+
```c++
136+
generator<int> range(int start, int end) {
137+
while (start < end) {
138+
co_yield start;
139+
start++;
140+
}
141+
142+
// Implicit co_return at the end of this function:
143+
// co_return;
144+
}
145+
146+
for (int n : range(0, 10)) {
147+
std::cout << n << std::endl;
148+
}
149+
```
150+
The above `range` generator function generates values starting at `start` until `end` (exclusive), with each iteration step yielding the current value stored in `start`. The generator maintains its state across each invocation of `range` (in this case, the invocation is for each iteration in the for loop). `co_yield` takes the given expression, yields (i.e. returns) its value, and suspends the coroutine at that point. Upon resuming, execution continues after the `co_yield`.
151+
152+
Another example of a coroutine is a _task_, which is an asynchronous computation that is executed when the task is awaited:
153+
```c++
154+
task<void> echo(socket s) {
155+
for (;;) {
156+
auto data = co_await s.async_read();
157+
co_await async_write(s, data);
158+
}
159+
160+
// Implicit co_return at the end of this function:
161+
// co_return;
162+
}
163+
```
164+
In this example, the `co_await` keyword is introduced. This keyword takes an expression and suspends execution if the thing you're awaiting on (in this case, the read or write) is not ready, otherwise you continue execution. (Note that under the hood, `co_yield` uses `co_await`.)
165+
166+
Using a task to lazily evaluate a value:
167+
```c++
168+
task<int> calculate_meaning_of_life() {
169+
co_return 42;
170+
}
171+
172+
auto meaning_of_life = calculate_meaning_of_life();
173+
// ...
174+
co_await meaning_of_life; // == 42
175+
```
176+
177+
**Note:** While these examples illustrate how to use coroutines at a basic level, there is lots more going on when the code is compiled. These examples are not meant to be complete coverage of C++20's coroutines. Since the `generator` and `task` classes are not provided by the standard library yet, I used the cppcoro library to compile these examples.
178+
130179
### Concepts
131180
_Concepts_ are named compile-time predicates which constrain types. They take the following form:
132181
```

0 commit comments

Comments
 (0)