std::ranges::starts_with仅支持随机访问范围且要求元素可比较,默认用==,支持自定义比较器(被查元素在前、pattern元素在后),不支持投影和单字符/长度参数,空pattern恒为true。
它只能用于支持随机访问迭代器的范围,比如 std::vector、std::string、std::array,不能直接用于 std::list 或自定义的单向链表——否则编译失败,报错类似 no matching function for call to 'starts_with'。
调用时需确保两个参数都是范围(range),且元素可比较(默认用 ==):
std::string s = "hello world";bool b1 = std::ranges::starts_with(s, "hello"); // truebool b2 = std::ranges::starts_with(s, std::vector{'h','e','l'}); // truebool b3 = std::ranges::starts_with(s, "hi"); // false
const char[N],被识别为 range,无需手动转 std::string_view
std::string_view 作为 pattern,也完全合法,且零开销std::string{"abc"} 直接传入可能引发 lifetime 问题,建议先命名再用第三个参数必须是可调用对象(比如 lambda 或函数指针),且签名应为 bool(decltype(*first1), decltype(*first2)),注意不是 (lhs, rhs) 的惯常顺序,而是「被查范围元素在前,pattern 元素在后」。
常见错误是写反参数顺序,导致编译失败或逻辑颠倒:
立即学习“C++免费学习笔记(深入)”;
std::string s = "Hello World";// ✅ 正确:忽略大小写bool ok = std::ranges::starts_with(s, "HELLO", [](char a, char b) { return std::tolower(a) == std::tolower(b); });// ❌ 错误:a 是 pattern 元素,b 是 s 的元素 —— 这里语义就反了// std::ranges::starts_with(s, "HELLO", [](char a, char b) { return ... });
false,不会越界访问std::views::transform)再传入std::string::starts_with 是成员函数,仅限 std::string 和 std::string_view;而 std::ranges::starts_with 是算法,泛型更强,但代价是:它不接受整数长度或单字符作为 pattern。
例如这些写法在 ranges 版本中非法:
// ❌ 编译错误:没有重载接受 size_t 或 charstd::ranges::starts_with(s, 3); // nopestd::ranges::starts_with(s, 'h'); // nope// ✅ 替代方案:用视图构造单元素范围std::ranges::starts_with(s, std::array{ 'h' });std::ranges::starts_with(s, std::string_view{"h"});
std::string::starts_with("hello", "he") 返回 true,而 std::ranges::starts_with("hello", "he") 同样成立,行为一致std::ranges::starts_with 对空 pattern 永远返回 true(符合“空序列是任意序列前缀”的数学定义),而老式接口没这个重载当你对视图链(如 std::views::filter | std::views::take)调用 starts_with,要小心其是否仍满足 RandomAccessRange 要求。多数惰性视图(如 filter)只提供 InputIterator,直接传入会编译失败。
auto v = std::vector{1,2,3,4,5};auto filtered = v | std::views::filter([](int x){return x%2==1;}); // {1,3,5}// ❌ 编译失败:filtered 不是 RandomAccessRange// std::ranges::starts_with(filtered, std::array{1,3});// ✅ 正确:materialize 成支持随机访问的容器std::vector<int> vec(filtered.begin(), filtered.end());std::ranges::starts_with(vec, std::array{1,3});
std::views::take 和 std::views::drop 在 C++23 中已支持 RandomAccessRange(当原 range 支持时),可以安全使用std::span、std::string_view、std::array 等原生 view,starts_with 表现良好,无需额外转换static_assert(std::ranges::random_access_range<r>)</r>
std::string_view 或小数组,比依赖隐式转换更稳。