In C#, I can write the following code:
IEnumerable<int> evenUpTo(int max)
{
for (int i = 0; i < max; i += 2)
{
yield return i;
}
}
foreach(int e in evenUpTo(11))
{
Console.WriteLine(e);
}
And the compiler will generate a class for me, which satisfies the IEnumerable<int>
interface.
Now, C++20 got coroutines as well. In principle, the code looks very similar:
#include <print>
#include <coroutine>
??? evenUpTo(int max) {
for (int i = 0; i < max; i += 2) {
co_yield i;
}
}
int main() {
for (auto e : evenUpTo(11)) {
std::print("{0}\n", e);
}
}
What do I put as the return type ???
?
I read that IEnumerable isn't needed in C++, because C++ has iterators. A pair of iterators (.begin()
and .end()
) is certainly enough to get a range-based for-loop working. But which container would I use? But linked question is from 2012 and coroutines are from C++20, so this topic hasn't been covered.
I can probably write my own Generator<T>
template, but I'd like to avoid that, if there is a built-in STL type.
In C#, I can write the following code:
IEnumerable<int> evenUpTo(int max)
{
for (int i = 0; i < max; i += 2)
{
yield return i;
}
}
foreach(int e in evenUpTo(11))
{
Console.WriteLine(e);
}
And the compiler will generate a class for me, which satisfies the IEnumerable<int>
interface.
Now, C++20 got coroutines as well. In principle, the code looks very similar:
#include <print>
#include <coroutine>
??? evenUpTo(int max) {
for (int i = 0; i < max; i += 2) {
co_yield i;
}
}
int main() {
for (auto e : evenUpTo(11)) {
std::print("{0}\n", e);
}
}
What do I put as the return type ???
?
I read that IEnumerable isn't needed in C++, because C++ has iterators. A pair of iterators (.begin()
and .end()
) is certainly enough to get a range-based for-loop working. But which container would I use? But linked question is from 2012 and coroutines are from C++20, so this topic hasn't been covered.
I can probably write my own Generator<T>
template, but I'd like to avoid that, if there is a built-in STL type.
1 Answer
Reset to default 8C++23
C++23 now has the std::generator<>
template, which you get with #include <generator>
.
#include <print>
#include <coroutine>
#include <generator>
std::generator<int> evenUpTo(int max) {
for (int i = 0; i < max; i += 2) {
co_yield i;
}
}
int main() {
for (auto e : evenUpTo(11)) {
std::print("{0}\n", e);
}
}
Compiler Explorer: https://godbolt./z/s66jbq9c7
C++20
Reiner Grimm explains how to write your own template in the book Concurrency with Modern C++ [Amazon]. There's an updated version by Roger Voss available on Github.
There's also a the reference implementation [Github] of the proposal P2168 which suggests to introduce the synchronous std::generator
to C++23.