1. C++20 ranges 基础概念解析
在传统C++标准库中,我们习惯使用迭代器对容器进行操作,比如std::sort(vec.begin(), vec.end())。这种方式虽然灵活,但存在几个明显痛点:需要显式传递首尾迭代器、组合操作时需要中间存储、代码可读性较差。C++20引入的ranges库正是为了解决这些问题。
范围(ranges)本质上是一个可以迭代的元素序列,由开始迭代器和结束标记(sentinel)表示。与STL容器不同,ranges更强调对元素序列的抽象操作。标准库中的容器(vector/list等)都是范围的特例,但范围的概念更为广泛。
范围适配器(range adaptor)是ranges库的核心组件,它能将一个范围转换为另一个范围。这种转换是惰性的——只有在真正访问元素时才会进行计算。例如:
cpp复制auto even_squares = numbers
| views::filter([](int n){ return n%2==0; })
| views::transform([](int n){ return n*n; });
这段代码创建了一个视图(view),它首先过滤出偶数,然后计算它们的平方。整个过程没有分配任何中间存储,也没有立即执行计算。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 范围适配器的核心优势
2.1 惰性求值机制
范围适配器最显著的特点是惰性求值(lazy evaluation)。当我们组合多个适配器时,并不会立即执行任何操作,只有在真正迭代结果时才会按需计算。这种机制带来两个好处:
- 性能优化:避免不必要的中间结果计算和存储
- 无限序列处理:可以表示和处理理论上无限长的序列
例如,我们可以创建一个生成所有正整数的视图:
cpp复制auto naturals = views::iota(1); // 无限序列
auto first10 = naturals | views::take(10); // 只取前10个
2.2 管道操作符组合
管道操作符(|)让多个范围适配器可以像Unix管道一样串联起来,极大提升了代码的可读性。对比传统写法:
cpp复制// 传统方式
std::vector<int> temp;
std::copy_if(input.begin(), input.end(), std::back_inserter(temp), pred);
std::transform(temp.begin(), temp.end(), output.begin(), func);
// ranges方式
auto result = input | views::filter(pred) | views::transform(func);
管道风格不仅更简洁
