Using Views with C++20 Coroutines
How do views interact with C++20's coroutines?
C++20's coroutines and views can work together to create powerful, lazy-evaluated pipelines for data processing. Coroutines allow you to define sequences of values that can be produced on-demand, and views can consume these sequences efficiently.
Example: Using a Coroutine with a View
Here's a simple example of a coroutine that generates an infinite sequence of numbers, which can be consumed by a view:
#include <coroutine>
#include <iostream>
#include <ranges>
class Generator {
public:
struct promise_type {
int value_;
std::suspend_always yield_value(int value) {
value_ = value;
return {};
}
std::suspend_always initial_suspend() {
return {};
}
std::suspend_always final_suspend() noexcept {
return {};
}
void unhandled_exception() {
std::terminate();
}
Generator get_return_object() {
return Generator{std::coroutine_handle<
promise_type>::from_promise(*this)};
}
void return_void() {}
};
using handle_type =
std::coroutine_handle<promise_type>;
handle_type coro_;
Generator(handle_type h) : coro_(h) {}
~Generator() {
if (coro_) coro_.destroy();
}
bool next() {
coro_.resume();
return !coro_.done();
}
int value() const {
return coro_.promise().value_; }
};
Generator GenerateNumbers() {
for (int i = 1;; ++i) co_yield i;
}
int main() {
auto gen = GenerateNumbers();
auto view = std::views::iota(0)
| std::views::transform([&gen](int) {
if (gen.next()) return gen.value();
return -1; // Placeholder value
});
for (int x : view | std::views::take(10)) {
std::cout << x << ", ";
}
}
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
Explanation
- Generator Class: Implements the coroutine generator. It uses
std::coroutine_handle
to manage the coroutine state. - GenerateNumbers: A coroutine function that yields an infinite sequence of numbers.
- View Usage: Combines the coroutine with a view using
std::views::iota
andstd::views::transform
to produce the sequence.
Benefits
- Lazy Evaluation: Coroutines produce values on-demand, which aligns well with the lazy nature of views.
- Efficiency: Only the needed values are generated and processed, reducing overhead.
Combining coroutines and views can help create highly efficient and readable code for complex data processing tasks.
Standard Library Views
Learn how to create and use views in C++ using examples from std::views