std::ranges::equal要求两范围值类型对称可比较且支持==,不隐式转换,长度不等时立即返回false;传自定义谓词时按pred(it1,it2)调用,需注意参数顺序和const引用习惯。

std::ranges::equal 要求两个范围元素类型可比较,且默认用 ==
它不像 std::equal(老式迭代器版本)那样默认要求左操作数能转成右操作数类型,std::ranges::equal 对两个范围的值类型做对称比较:即 a == b 和 b == a 都得合法(除非显式传了自定义谓词)。常见翻车点是自定义类型没重载 operator==,或者只重载了单向转换(比如 MyType == int 但 int == MyType 不成立),这时编译直接失败。
使用场景包括:比较 std::vector 和 std::array、比较两个 std::string_view、或比较一个容器和字面量数组:
std::vector<int> v1 = {1,2,3};
std::array<int,3> a = {1,2,3};
bool same = std::ranges::equal(v1, a); // ✅ OK
传入自定义谓词时,注意参数顺序和 const 引用习惯
如果你传第三个参数作为二元谓词(比如 std::less{} 或 lambda),它会被调用为 pred(*it1, *it2) —— 第一个参数来自第一个范围,第二个来自第二个范围。这和 std::equal 一致,但容易误写成 pred(*it2, *it1) 导致逻辑反转。
- 谓词参数建议用
const auto&,避免拷贝;若类型小(如int),传值也行 - 不能捕获局部变量的 lambda 在函数返回后被调用?不会 ——
std::ranges::equal是立即求值,不存储谓词 - 谓词返回
false会立刻停止遍历,不继续比较剩余元素
std::vector<std::string> v1 = {"a", "bb"};
std::vector<std::string> v2 = {"A", "BB"};
bool icase = std::ranges::equal(v1, v2, [](const auto& a, const auto& b) {
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
[](char x, char y) { return std::tolower(x) == std::tolower(y); });
});
范围长度不等时,std::ranges::equal 立即返回 false,不崩溃
它先检查两个范围的 size()(如果支持),不等就直接返回 false;否则退化为逐个迭代比较,到任一范围结束为止。这意味着:
立即学习“C++免费学习笔记(深入)”;
- 对
std::list这种无size()的容器,性能是 O(n),且无法短路(必须走到短的那个末尾) - 对输入范围(如
std::istream_view),它根本没法预判长度,只能逐个比,且一旦第一个范围提前结束就停 - 如果传入两个不同长度的
std::vector,它在第一次 size 比较就返回false,非常快
所以别指望它“截断比较”——想比前 N 个元素,得手动用 std::views::take 构造子范围:
auto r1 = v1 | std::views::take(2); auto r2 = v2 | std::views::take(2); bool first_two_equal = std::ranges::equal(r1, r2);
与 std::equal 的关键差异:支持非随机访问、更严格的约束、无隐式转换
std::ranges::equal 要求两个范围都满足 std::ranges::input_range,而旧版 std::equal 只要迭代器满足 InputIterator 就行。表面上差不多,但实际影响是:某些仅满足 LegacyInputIterator 的自定义迭代器(比如老式 istream_iterator)可能无法用于 std::ranges::equal,因为缺少 range 概念的配套类型别名(如 iterator_t, sentinel_t)。
另一个坑是:旧版 std::equal(first1, last1, first2) 允许 first2 是任意迭代器类型,只要能递增;而 std::ranges::equal(r1, r2) 要求两个范围的 value_type 在语义上可比,编译器会更早报错,而不是等到运行时崩掉。
最容易被忽略的是:它不接受三个迭代器形式(即不能只给一个范围的 begin/end + 另一个范围的 begin),必须传两个完整范围。想复用旧代码?得包一层:std::ranges::equal(std::ranges::subrange{first1, last1}, r2)。


















