#include #include #include #include #include #include #include class Generator { public: struct promise_type { int current = 0; std::exception_ptr error; Generator get_return_object(); std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } std::suspend_always yield_value(int n) noexcept { current = n; return {}; } void return_void() noexcept {} void unhandled_exception() noexcept { error = std::current_exception(); } }; private: using Handle = std::coroutine_handle; Handle handle_; explicit Generator(Handle h) noexcept : handle_(h) {} public: Generator(const Generator&) = delete; Generator& operator=(const Generator&) = delete; Generator(Generator&& other) noexcept : handle_(std::exchange(other.handle_, {})) {} Generator& operator=(Generator&& other) noexcept { if (this != &other) { if (handle_) handle_.destroy(); handle_ = std::exchange(other.handle_, {}); } return *this; } ~Generator() { if (handle_) handle_.destroy(); } std::optional next() { if (!handle_ || handle_.done()) return std::nullopt; handle_.resume(); if (handle_.promise().error) std::rethrow_exception(handle_.promise().error); if (handle_.done()) return std::nullopt; return handle_.promise().current; } }; Generator Generator::promise_type::get_return_object() { return Generator{std::coroutine_handle::from_promise(*this)}; } struct Guard { inline static int live = 0; Guard() { ++live; } ~Guard() { --live; } }; Generator numbers() { Guard guard; for (int n = 1; n <= 3; ++n) co_yield n; } Generator failure() { throw std::runtime_error("failed"); co_return; } int main() { { auto early = numbers(); assert(Guard::live == 0); auto first = early.next(); assert(first && *first == 1 && Guard::live == 1); auto moved = std::move(early); assert(!early.next()); } assert(Guard::live == 0); auto all = numbers(); int total = 0; while (auto n = all.next()) total += *n; assert(total == 6 && Guard::live == 0); assert(!all.next()); bool caught = false; try { auto bad = failure(); bad.next(); } catch (const std::runtime_error&) { caught = true; } assert(caught); std::cout << total << ' ' << Guard::live << '\n'; }