std::generator 是 C++23 协程返回类型,非容器,由协程函数构造并用 co_yield 驱动;其迭代器单遍、不可复制、不可回溯,需用 std::default_sentinel 安全遍历。

std::generator 在 C++23 中是实验性特性(目前仅 GCC 13+ 启用,Clang 尚未支持),它本身不“配合”co_yield——而是 co_yield 用来定义 std::generator 的主体。你不能手动调用 co_yield 外部函数去“喂”一个已存在的 std::generator 实例;它的值流完全由协程函数体内的 co_yield 语句驱动。
std::generator 是协程返回类型,不是容器
很多人误以为 std::generator 像 std::vector 那样可 push、可迭代初始化。其实它只是一个协程的**句柄包装器**:构造时即启动协程,但暂停在首个 co_yield;每次调用 begin() / operator++ 才恢复执行到下一个 co_yield 或结束。
-
std::generator<int></int>只能由返回该类型的协程函数生成,例如:std::generator<int> fib() { int a = 0, b = 1; while (true) { co_yield a; a += b; std::swap(a, b); } }</int> - 不能写
std::generator<int> g; g.co_yield(42);</int>——co_yield不是成员函数,也不可外部触发 - 其迭代器是单遍(single-pass)、不可复制(仅可移动),且无法 rewind
常见错误:试图“收集”或“缓存” generator 输出
因为 std::generator 的迭代器只前移、不保存历史,一旦 ++ 过某个值,就再也拿不回来了。想重复使用?必须重新调用原协程函数重建实例。
- 错:
auto g = fib(); auto v = std::vector(g.begin(), g.end()); // ❌ 编译失败:g.end() 不是标准 end 迭代器 - 对:
auto g = fib(); std::vector<int> v{g.begin(), std::default_sentinel}; // ✅ C++23 允许 sentinel 构造</int> - 但注意:这会**耗尽整个 generator**(比如
fib()是无限的,必须加 break 条件) - 若需多次遍历,别依赖
std::generator,改用普通函数 +std::vector或自定义 range adaptor
实际可用的惰性数列写法(GCC 13.2+,-std=c++2b -fcoroutines)
下面是一个带边界控制的有限斐波那契生成器示例,展示如何安全 yield 并终止:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
std::generator<int> fib(int limit) {
int a = 0, b = 1;
while (a < limit) {
co_yield a;
a += b;
std::swap(a, b);
}
// 协程自然结束 → generator 迭代器到达 sentinel
}
使用时:
for (int x : fib(100)) std::coutauto g = fib(100); auto it = g.begin(); if (it != std::default_sentinel) { std::cout- 所有操作都延迟执行:
fib(100)构造时不计算任何值,++it才触发下一次计算
真正容易被忽略的一点:C++23 的 std::generator 没有异常传播机制(exception safety 由用户协程保证),且其内存布局和调度完全依赖编译器协程 ABI——目前 GCC 实现中,每个 std::generator 实例携带完整协程帧,频繁构造/析构小 generator(如每循环一次 new 一个)会有可观开销。

















