C++中能否创建generator范围并将它们合并?
关于std::generator组成的范围及合并问题
核心结论
- 可以创建由std::generator组成的范围,但要注意
std::generator是仅移动类型(拷贝构造/赋值运算符被显式删除),存储时必须遵循移动语义,避免拷贝操作。 - 可以合并多个std::generator,但同样需要规避拷贝,通过移动语义或引用语义实现。
编译错误原因分析
你遇到的编译错误,本质是std::generator的拷贝构造函数被删除——因为它内部持有协程状态,无法被安全拷贝。当你用数组存储generator时,如果初始化或操作过程中尝试拷贝左值generator(比如将一个已存在的generator变量直接赋值给数组元素),就会触发错误;另外,部分视图操作如果隐含拷贝元素的逻辑,也会导致同样问题。
解决方案与示例
方案1:用可移动容器存储并直接合并
使用std::vector或支持移动语义的容器存储generator,直接通过views::join合并。容器中的generator通过右值移动构造初始化,避免拷贝:
#include <generator> #include <ranges> #include <vector> #include <iostream> std::generator<int> gen1() { co_yield 1; co_yield 2; } std::generator<int> gen2() { co_yield 3; co_yield 4; } int main() { // 用vector存储generator,通过右值移动构造 std::vector<std::generator<int>> generators{gen1(), gen2()}; // 直接合并 auto joined = generators | std::views::join; for (int num : joined) { std::cout << num << " "; // 输出:1 2 3 4 } return 0; }
方案2:用引用包装器保留原generator
如果需要保留原generator(不转移所有权),可以用std::reference_wrapper包装generator,存储引用而非值。这样views::join操作时只会访问引用,不会触发拷贝:
#include <generator> #include <ranges> #include <array> #include <functional> #include <iostream> std::generator<int> gen1() { co_yield 1; co_yield 2; } std::generator<int> gen2() { co_yield 3; co_yield 4; } int main() { auto g1 = gen1(); auto g2 = gen2(); // 用reference_wrapper包装generator,存储引用 std::array<std::reference_wrapper<std::generator<int>>, 2> generators{g1, g2}; // 合并视图 auto joined = generators | std::views::join; for (int num : joined) { std::cout << num << " "; // 输出:1 2 3 4 } return 0; }
注意事项
std::generator属于输入范围(input_range),每个实例只能被迭代一次。合并后的视图会消耗原generator的状态,迭代后原generator将无法再次使用。- 如果使用数组存储
generator,必须确保元素通过移动构造初始化(比如用std::move转移左值generator的所有权),禁止直接拷贝左值generator到数组中。
内容的提问来源于stack exchange,提问作者Ludovic Aubert
相关产品推荐
相关产品推荐

