std::ranges::starts_with是C++23引入的通用范围算法,作用于任意range类型;而string::starts_with是C++20添加的string专属成员函数,仅支持字符串类型参数。

std::ranges::starts_with 是什么,和 string::starts_with 有什么区别
它不是 std::string 的成员函数,而是 C++23 引入的独立算法,定义在 <ranges></ranges> 头文件中,作用对象是任意符合范围(std::ranges::range)概念的容器或视图,比如 std::vector<int></int>、std::array<char n></char>、甚至自定义的迭代器对。而 std::string::starts_with 是 C++20 加入的成员函数,只对 std::string(及 std::wstring 等)有效,参数仅支持 char、const char* 和 std::string_view。
这意味着:如果你要检查一个 std::vector<:byte></:byte> 是否以某字节序列开头,或者一个 std::span<int></int> 是否以 {1, 2} 开头,std::string::starts_with 完全无能为力,必须用 std::ranges::starts_with。
怎么写才能通过编译并正确匹配
最常见错误是忘记包含头文件或误用迭代器对。它不接受裸指针对(如 begin, end),而是直接接收两个范围:
- 必须包含
<ranges></ranges>(C++23 起);C++20 中该函数尚未存在,别指望它能用 - 两个参数都必须是 range:不能传
std::string::c_str(),但可以传std::string_view(str)或str本身(因为std::string满足 range 概念) - 空范围自动返回
true:即std::ranges::starts_with(v, std::vector<int>{})</int>恒为true - 若前缀长度 > 主范围长度,立即返回
false,不触发未定义行为
示例:
#include <ranges>
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> prefix = {1, 2};
bool ok = std::ranges::starts_with(v, prefix); // true
std::string s = "hello world";
bool s_ok = std::ranges::starts_with(s, "hello"); // true —— 注意:这里 "hello" 是 const char[6],隐式转为 std::string_view
}</int></int></iostream></string></vector></ranges>
自定义比较或投影时容易踩的坑
std::ranges::starts_with 支持 pred(谓词)和 proj1/proj2(投影),但它们的调用时机和顺序容易被误解:
-
pred是二元比较函数,签名应为bool(decltype(*it1), decltype(*it2)),不是bool(auto, auto)的泛型 lambda 就可能推导失败 -
proj1作用于主范围每个元素,proj2作用于前缀范围每个元素;两者结果再交给pred比较。例如想忽略大小写比字符串,应写std::ranges::starts_with(s, "HELLO", {}, ::tolower, ::tolower) - 若只传
proj1没传proj2,编译器不会默认补 identity —— 会报错:参数数量不匹配 - 投影函数必须是可调用对象(函数指针、lambda、functor),不能是成员函数指针(除非绑定)
性能与兼容性关键点
它底层不做拷贝、不分配内存,时间复杂度 O(N),N 是前缀长度;但注意:如果传入的范围没有 size()(比如输入迭代器),它可能需要遍历整个主范围来确认长度是否足够,导致 O(M)(M 是主范围长度)—— 这在 std::istream_iterator 场景下是致命的。
- 安全前提:确保前缀范围是
std::ranges::sized_range,主范围最好是std::ranges::random_access_range或至少有size() - 不要对
std::ranges::istream_view<char></char>直接用starts_with,它没有 size,且无法回退迭代器 - 在 C++20 工程中强行使用需自行实现或降级到
std::equal+ 迭代器偏移,但得手动处理长度判断和越界防护
真正要用好它,得先看清你的范围类型是否“诚实”地提供了 size 和随机访问能力 —— 否则看似简洁的一行,背后可能是不可控的遍历开销。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











