Closed wg21bot closed 1 year ago
generator::begin
has a precondition that the generator's coroutine handle refers to a coroutine suspended at its initial suspend point. This is necessary since begin
resumes the coroutine so it can yield the first element of the generated range so it is ready to be retrieved from the returned iterator's operator*
. We don't call begin
on recursive generators, but we must similarly resume
a recursively yielded coroutine to allow it to generate an element before the iterator observes that element. A partially executed coroutine will already have a "current" element that would be effectively skipped by the iteration if we permitted it to be yielded recursively, disappearing into the ether.
This precondition also prevents a generator recursively yielding itself. For example:
std::generator<int> x;
std::generator<int> foo() {
co_yield std::ranges::elements_of(std::move(x));
}
int main() {
x = foo();
for (auto&& meow : x) {
// ...
}
}
we suspect that the other requirements on generator
are unimplementable, or at the very least not efficiently implementable, for self-recursive generators - we'd need another way to forbid this.
All of which is to say that the preconditions are subtle, and that the requested relaxation needs some investigation (i.e., a paper) to ensure there's no ancillary damage. There seems to be no impediment to making such a change after shipping C++23 with such a paper in hand.
Rejected. There is no consensus for a change.
There doesn't seem to be a reason to forbid yielding from a partially executed generator.
Proposed change:
Require merely that g.range.coroutine_ be suspended and not at its final suspend point.