C++20中的<ranges>库详解
C++20引入了范围库(Ranges),这是一个功能强大且灵活的库,用于处理和操作集合。范围库是对迭代器和算法库的扩展,提供了一种更直观、更易用的集合操作方式。本文将详细介绍C++20中的<ranges>库及其主要特性和用法。
范围的基本概念
范围(Range)表示一个可以遍历的序列,范围库中的主要组件包括:
- 范围概念(Range Concepts):定义了范围和迭代器的特性。
- 视图(Views):懒惰计算的范围转换器。
- 适配器(Adapters):用于组合和修改范围的工具。
- 范围算法(Range Algorithms):对范围进行操作的算法。
范围概念
范围库中的概念定义在std::ranges命名空间中,主要的范围概念包括:
std::ranges::range:表示一个范围。std::ranges::input_range:表示一个输入范围。std::ranges::output_range:表示一个输出范围。std::ranges::forward_range:表示一个前向范围。std::ranges::bidirectional_range:表示一个双向范围。std::ranges::random_access_range:表示一个随机访问范围。std::ranges::contiguous_range:表示一个连续范围。
范围视图
视图(View)是范围库中的核心组件之一,提供了一种懒惰计算的方式来操作范围。视图不会立即计算结果,而是当结果被访问时才进行计算。
1. std::views::all
std::views::all用于将一个范围转换为视图。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto view = std::views::all(vec);
for (int v : view) {
std::cout << v << " ";
}
// 输出:1 2 3 4 5
return 0;
}
2. std::views::filter
std::views::filter用于过滤范围中的元素。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto even_view = vec | std::views::filter([](int n) { return n % 2 == 0; });
for (int v : even_view) {
std::cout << v << " ";
}
// 输出:2 4
return 0;
}
3. std::views::transform
std::views::transform用于对范围中的元素进行转换。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto square_view = vec | std::views::transform([](int n) { return n * n; });
for (int v : square_view) {
std::cout << v << " ";
}
// 输出:1 4 9 16 25
return 0;
}
4. 组合视图
视图可以组合使用,实现复杂的范围操作。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6};
auto even_square_view = vec
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; });
for (int v : even_square_view) {
std::cout << v << " ";
}
// 输出:4 16 36
return 0;
}
范围算法
范围库中的算法是标准算法的扩展,支持直接对范围进行操作,而无需显式地处理迭代器。
1. std::ranges::for_each
std::ranges::for_each用于对范围中的每个元素执行操作。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::ranges::for_each(vec, [](int& n) { n *= 2; });
for (int v : vec) {
std::cout << v << " ";
}
// 输出:2 4 6 8 10
return 0;
}
2. std::ranges::sort
std::ranges::sort用于对范围进行排序。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {5, 3, 1, 4, 2};
std::ranges::sort(vec);
for (int v : vec) {
std::cout << v << " ";
}
// 输出:1 2 3 4 5
return 0;
}
3. std::ranges::copy
std::ranges::copy用于将一个范围的内容复制到另一个范围。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dest(5);
std::ranges::copy(src, dest.begin());
for (int v : dest) {
std::cout << v << " ";
}
// 输出:1 2 3 4 5
return 0;
}
4. 其他算法
范围库还包括其他常用的算法,如std::ranges::find、std::ranges::count、std::ranges::unique等。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = std::ranges::find(vec, 3);
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl; // 输出:Found: 3
}
int count = std::ranges::count(vec, 2);
std::cout << "Count of 2: " << count << std::endl; // 输出:Count of 2: 1
return 0;
}
范围适配器
范围适配器用于组合和修改范围,提供了一种直观的方式来构建复杂的范围操作。
1. std::views::reverse
std::views::reverse用于逆转范围的元素顺序。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto reversed_view = std::views::reverse(vec);
for (int v : reversed_view) {
std::cout << v << " ";
}
// 输出:5 4 3 2 1
return 0;
}
2. std::views::take和std::views::drop
std::views::take用于获取范围的前N个元素,std::views::drop用于跳过范围的前N个元素。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
auto first_three = vec | std::views::take(3);
auto last_two = vec | std::views::drop(3);
for (int v : first_three) {
std::cout << v << " ";
}
// 输出:1 2 3
std::cout << std::endl;
for (int v : last_two) {
std::cout << v << " ";
}
// 输出:4 5
return 0;
}
3. std::views::zip和std::views::zip_with
std::views::zip用于将多个范围的元素合并为一个范围,std::views::zip_with用于将多个范围的元素合并并应用一个操作。
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec1 = {1, 2, 3};
std::vector<int> vec2 = {4, 5, 6};
auto zipped_view = std::views::zip(vec1, vec2);
for (const auto& [v1, v2]
: zipped_view) {
std::cout << "(" << v1 << ", " << v2 << ") ";
}
// 输出:(1, 4) (2, 5) (3, 6)
std::cout << std::endl;
auto sum_view = std::views::zip_with(std::plus<>(), vec1, vec2);
for (int sum : sum_view) {
std::cout << sum << " ";
}
// 输出:5 7 9
return 0;
}
总结
C++20中的<ranges>库提供了一种强大且灵活的方式来处理和操作集合。通过使用范围、视图、适配器和算法,开发者可以编写出更加简洁、直观和高效的代码。希望本文对<ranges>库的详细介绍能够帮助读者更好地理解和应用这一新特性,从而提升代码的质量和可维护性。