C++20 标准引入了 std::ranges 库,它将 STL 容器和算法与概念(Concepts)以及范围(Range)模型结合起来,极大地方便了对容器数据的处理。本文从基础概念入手,展示 std::ranges 如何让代码更简洁、表达更直观,并通过实例演示其高效优势。
1. 范围(Range)概念
在传统 STL 中,算法需要两个迭代器参数(begin、end)来标识操作区间。std::ranges 把这两个迭代器封装成一个范围对象(Range),并将算法改为接受范围作为单一参数。这样做的好处是:
- 更少的重复代码:不再手动传递
begin/end。 - 更安全:避免传递错误的迭代器对。
- 更易组合:范围可以通过管道(
|)符号串联多个操作。
2. 范围适配器(Range Adapters)
std::ranges 提供了多种适配器,用来变换、过滤或重组范围,而不需要显式地编写循环。常见适配器包括:
std::views::filter:按条件筛选元素。std::views::transform:对元素做一次性转换。std::views::reverse:反向遍历。std::views::take/std::views::drop:截取前后若干元素。
适配器本身是惰性求值(lazy),只有在真正迭代时才执行,保证了性能。
3. 示例:统计字符串长度
下面演示一个经典场景:给定一个字符串集合,统计长度大于 5 的字符串数量。
#include <iostream>
#include <vector>
#include <string>
#include <ranges>
#include <algorithm>
int main() {
std::vector<std::string> words{
"hello", "world", "C++", "ranges", "concepts", "template"
};
// 直接用 ranges 过滤并计数
auto count = std::ranges::count_if(
words,
[](const std::string& s){ return s.size() > 5; }
);
std::cout << "长度 > 5 的字符串数量: " << count << '\n';
}
传统写法:
int count = 0;
for (const auto& w : words)
if (w.size() > 5) ++count;
虽然两者都很简洁,但 ranges 版本更具表达力,尤其在链式操作时优势更明显。
4. 更复杂的链式操作
假设我们想做以下操作:取出长度大于 3 的字符串,将其全部转成大写,再倒序输出。
#include <algorithm>
#include <cctype>
#include <iterator>
int main() {
std::vector<std::string> words{
"apple", "banana", "kiwi", "cherry", "mango"
};
auto upper = [](std::string s){
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return std::toupper(c); });
return s;
};
auto view = words | std::views::filter([](const std::string& s){ return s.size() > 3; })
| std::views::transform(upper)
| std::views::reverse;
for (const auto& w : view)
std::cout << w << ' ';
std::cout << '\n';
}
输出:
MANGO CHERRY BANANA APPLE
整个过程只用一行链式表达,极大提升代码可读性。
5. 性能考量
- 惰性求值:适配器只在真正迭代时才执行,避免不必要的中间容器。
- 概念约束:编译器在编译时检查类型安全,减少运行时错误。
- 函数内联:
std::ranges函数往往被内联,消除了函数调用开销。
在大多数情况下,使用 std::ranges 与传统 STL 并没有显著的性能差距,甚至在复杂链式操作中反而更快,因为编译器可以更好地优化整体流程。
6. 小结
std::ranges通过范围和适配器提供了更直观、更安全的容器操作方式。- 其惰性求值和概念约束使得代码既简洁又高效。
- 在需要复杂数据处理链的场景中,
std::ranges能大幅降低代码量并提升可维护性。
如果你正在使用 C++20 或更高版本,强烈建议尝试 std::ranges,它将成为你日常编码的强大工具。