【C++20新特性】ranges::sort()使用方法,优势,注意点
以下是关于 ranges::sort() 的详细说明:
1. ranges::sort() 的使用方法
ranges::sort()
是 C++20
引入的基于范围(Ranges)的排序函数,其语法更简洁,支持直接操作容器或范围对象。
(1)基本用法
#include <vector>
#include <ranges>
#include <algorithm>int main() {std::vector<int> numbers = {3, 1, 4, 1, 5};std::ranges::sort(numbers); // 直接对容器排序return 0;
}
(2)逆序排序
通过传递 std::greater<>
实现降序:
std::ranges::sort(numbers, std::greater<>());
(3)自定义排序规则
使用 Lambda
表达式或自定义比较函数:
std::ranges::sort(numbers, [](int a, int b) {return a % 3 < b % 3; // 按模3的余数排序
});
2. 相比于传统 std::sort 的优势
(1) 更简洁的语法
传统 std::sort
需要手动指定迭代器范围:
std::sort(numbers.begin(), numbers.end());
ranges::sort
直接操作容器,省去迭代器:
std::ranges::sort(numbers); // 无需 begin/end
(2) 支持范围概念(Concepts)
ranges::sort
在编译期通过概念(Concepts)检查参数合法性,错误提示更清晰。例如,若元素类型不支持比较,编译器会直接报错。
(3) 与范围库的无缝结合
可与其他范围适配器(如视图 views
)结合使用,实现链式操作:
// 过滤偶数后排序
auto filtered = numbers | std::views::filter([](int x) { return x % 2 == 0; });
std::ranges::sort(filtered);
(4) 性能优化
对大型数据集可能有性能优化,因底层实现可能采用更高效的策略。
3. 使用注意点
(1) C++20 兼容性
需确保编译器支持 C++20 标准(如 GCC 10+、Clang 13+、MSVC 19.29+)。
(2) 元素类型需支持比较
元素类型必须定义 < 运算符或提供自定义比较函数。否则编译失败。
(3) 比较函数的严格弱序
自定义比较函数需满足严格弱序(Strict Weak Ordering),否则行为未定义。
(4) 视图的惰性计算
若对视图(如 views::filter 结果)调用 ranges::sort,需注意视图可能是惰性计算的,可能导致意外结果3。
总结
ranges::sort
通过简化语法、增强类型安全和优化性能,成为 C++20 中更现代的排序选择。在支持 C++20 的项目中优先使用,可提升代码可读性和健壮性。传统 std::sort 仍适用于旧代码或低版本编译器环境。
4. 实际分析
看灵神的代码的时候发现一个排序是这样写的:
vector<vector<int>> queries;
//...
ranges::sort(queries, {}, [](auto& q) { return q[0]; });
这段代码的作用是对二维向量 queries
按每行第一个元素(即 q
)进行升序排序。以下是详细分析:
4.1 代码解析
ranges::sort(queries, {}, [](auto& q) { return q; });
-
参数含义:
queries
:待排序的二维向量(vector<vector<int>>
)。{}
:占位符,表示使用默认比较规则(std::less
,即升序)。[](auto& q) { return q; }
:投影函数(Projection),指定排序依据为每行的第一个元素q
。
-
等效传统写法(使用
std::sort
):std::sort(queries.begin(), queries.end(), [](const auto& a, const auto& b) {return a < b; });
4.2 优势:ranges::sort 的简洁性
- 直接操作容器:无需手动传递
begin/end
迭代器(传统写法需queries.begin(), queries.end()
)。 - 投影函数:通过
[](auto& q) { return q; }
直接指定排序字段,避免了在比较函数中重复提取a
和b
,代码更简洁。 - 类型安全:C++20 的
ranges::sort
通过概念(Concepts)检查参数合法性,确保投影后的值可比较。
3. 注意点
- 子向量非空:必须确保每行子向量至少有一个元素,否则
q
会导致未定义行为(如越界访问)。 - 严格弱序:默认使用
std::less
升序排序,若需降序,需显式传递std::greater{}
作为第二个参数:ranges::sort(queries, std::greater{}, [](auto& q) { return q; });
- 兼容性:需编译器支持 C++20(如 GCC 10+、Clang 13+)。
4. 与传统 std::sort 的对比
特性 | ranges::sort | 传统 std::sort |
---|---|---|
语法简洁性 | 直接操作容器,无需迭代器 | 需手动传递 begin/end 迭代器 |
投影函数 | 支持,简化字段提取逻辑 | 需在比较函数中显式提取字段 |
类型检查 | 编译期概念检查,错误提示更友好 | 运行时可能因类型错误崩溃 |
总结
这段代码利用 C++20 的 ranges::sort
对二维向量按首元素升序排序,通过投影函数简化了逻辑,是更现代的写法。注意确保子向量非空,并根据需求调整升/降序规则。在支持 C++20 的项目中推荐优先使用 ranges::sort
。