从迭代器到 Range
// C++17 — 迭代器对,啰嗦
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> even;
std::copy_if(v.begin(), v.end(),
std::back_inserter(even),
[](int x) { return x % 2 == 0; });
std::transform(even.begin(), even.end(), even.begin(),
[](int x) { return x * x; });
// C++20 — 管道风格
auto result = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * x; })
| std::ranges::to<std::vector<int>>();
// {4, 16, 36, 64} — 懒求值,只在 to<> 时执行
核心 View 速查
| View | 效果 | 示例 |
|---|
filter | 保留满足条件的 | v | filter([](int x){return x>0;}) |
transform | 映射转换 | v | transform([](int x){return x*2;}) |
take / drop | 取前N / 跳过前N | v | take(3) |
take_while / drop_while | 条件取/跳 | v | take_while([](int x){return x<10;}) |
reverse | 逆序 | v | views::reverse |
enumerate | 带索引 | v | enumerate |
join | 展平嵌套 | vv | join |
split | 按分隔符拆分字符串 | str | split('\n') |
iota | 无限序列 | views::iota(0) |
common | 统一 iterator/sentinel 类型 | v | common |
懒求值
// Ranges 是懒求值:管道定义操作,不立即执行
auto pipeline = views::iota(0) // 0, 1, 2, ...
| views::filter(isEven) // 过滤偶数
| views::transform(square) // 平方
| views::take(5); // 取 5 个
// 只有遍历时才真正计算
for (int x : pipeline) // 0, 4, 16, 36, 64
std::cout << x << ' ';
Projection — 投影
struct Person { std::string name; int age; };
std::vector<Person> people = {{"Bob", 30}, {"Alice", 25}};
// C++17: 需要 lambda
std::sort(people.begin(), people.end(),
[](auto &a, auto &b) { return a.name < b.name; });
// C++20: projection 直接指定比较成员
std::ranges::sort(people, {}, &Person::name); // 按 name 排序
std::ranges::sort(people, {}, &Person::age); // 按 age 排序
// 第二个参数 {} = 默认比较器(less)
// 第三个参数 = projection:提取要比较的字段
算法升级
// C++20 std::ranges 版算法——直接用容器,不再需要 begin/end
std::ranges::sort(v);
std::ranges::find(v, 42);
std::ranges::copy_if(v, std::back_inserter(out), pred);
// 返回值更丰富
auto result = std::ranges::minmax(v);
// result.min, result.max — 结构化返回
自定义 Range
// 实现一个只读的循环缓冲区 View
template <typename T>
class RingView : public std::ranges::view_interface<RingView<T>> {
const T *data_;
size_t size_, head_;
public:
RingView(const T *d, size_t n, size_t h)
: data_(d), size_(n), head_(h) {}
auto begin() const { return data_ + head_; }
auto end() const {
return std::default_sentinel; // C++20 sentinel
}
// 需要定义迭代器类型时...
};
// 更简单:用已有的 range adaptor 组合
auto top5 = v | views::reverse | views::take(5);
常见陷阱
// 陷阱 1: View 是借用语义 — 原数据不能提前析构
auto bad() {
std::vector<int> v = {1, 2, 3};
return v | views::reverse; // ❌ v 析构 → view 悬空
}
// 陷阱 2: filter 后的元素不再是随机访问
auto evens = v | views::filter(isEven);
// evens[0] // ❌ filter 后的 range 不是 random_access
// 陷阱 3: view 本身不拥有数据
auto v = views::iota(0); // 这是 OK 的 — iota 自己生成数据
auto w = someVec | views::drop(5); // w 只引用 someVec,不拷贝