std::generator尚未纳入C++23标准,主流编译器均不支持;可行方案是基于std::coroutine_handle手动实现generator类,或使用std::ranges::iota_view与transform_view替代。

std::generator 在 C++23 中尚未正式标准化
目前(截至 GCC 14.2 / Clang 18 / MSVC 19.39),std::generator 并不在 C++23 标准中——它仍处于 P2505R3 技术规范草案阶段,未被纳入 ISO/IEC 14882:2023。所有主流编译器都**不提供 std::generator 的实现**,也没有 <generator></generator> 头文件。
如果你看到某段代码用了 std::generator<int></int>,那要么是实验性编译器扩展(如早期 GCC trunk 的非默认分支),要么是误传或混淆了其他库(比如 range-v3、cppcoro 或自定义协程包装器)。
用 std::coroutine_handle + 自定义 generator 类模拟惰性生成
真正可行的 C++23 方式,是手动实现一个轻量 generator 类型,基于标准协程设施(std::coroutine_handle、promise_type)。核心在于:让每次 operator++() 触发一次协程恢复,直到下一个 co_yield。
关键点:
立即学习“C++免费学习笔记(深入)”;
- 必须定义自己的
generator模板类(含嵌套promise_type) -
promise_type::final_suspend()必须返回std::suspend_always{},否则协程可能提前销毁 -
promise_type::get_return_object()返回 generator 实例本身,不是 handle -
co_yield的值通过promise.value()暴露,需确保生命周期安全(通常用 move-only 设计)
示例骨架(省略异常处理和移动语义):
template<typename T>
class generator {
struct promise_type {
T value_;
generator get_return_object() { return generator{handle::from_promise(*this)}; }
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
std::suspend_always yield_value(T v) {
value_ = std::move(v);
return {};
}
};
using handle = std::coroutine_handle<promise_type>
handle h_ = nullptr;
public:
explicit generator(handle h) : h_(h) {}
~generator() { if (h_) h_.destroy(); }
T operator*() const { return h_.promise().value_; }
void operator++() { h_.resume(); }
bool done() const { return !h_ || h_.done(); }
};
斐波那契数列的 co_yield 实现要注意整数溢出与迭代控制
直接写 while(true) { co_yield a; ... } 会无限生成,实际使用时必须由调用方控制步数(例如用 for (auto x : take(gen, 10))),或在 generator 内部加计数/边界条件。
常见错误:
- 用
int计算第 48 项就溢出 → 建议用uint64_t或__int128(GCC) - 忘记检查
h_.done()就调用operator*→ 未定义行为 - 协程首次 resume 前未调用
initial_suspend→ 可能跳过首项
安全写法片段:
generator<uint64_t> fib() {
uint64_t a = 0, b = 1;
co_yield a;
while (true) {
co_yield b;
uint64_t next = a + b;
a = b;
b = next;
}
}
替代方案:用 std::ranges::iota_view + transform_view 更简单且已可用
如果目标只是“惰性、按需计算斐波那契”,而不需要协程语法糖,C++20 的 ranges 库配合自定义访问器更稳妥、无编译器支持门槛:
-
std::ranges::iota_view{0, 100}提供索引序列 -
transform_view将每个索引映射为对应斐波那契数(O(n) 时间但只算当前项) - 完全标准、无需协程、所有 C++20 编译器都支持
缺点是无法复用中间状态(每次索引访问都重算),但对多数场景(如取前 N 项、流式消费)足够高效。
真正需要协程 generator 的场景,其实是状态复杂、有外部 I/O 或分段 yield 的逻辑——单纯斐波那契,反而容易把问题过度工程化。
协程 generator 的调试成本、编译器差异、ABI 不稳定性,远高于它带来的收益。除非你明确要练手协程机制,否则先用 ranges。


















