std::ranges::fill要求传入满足std::ranges::range概念的可写范围(如std::vector、std::array、原生数组)和可复制值,不接受迭代器对;正确用法为std::ranges::fill(v, 42),错误用法为std::ranges::fill(v.begin(), v.end(), 42)。

std::ranges::fill 的基本用法和参数要求
必须传入一个满足 std::ranges::range 概念的范围(比如 std::vector、原生数组、std::array),以及一个可复制的值。它不接受迭代器对,这点和旧式 std::fill 不同——如果你传 begin(v), end(v), val 会编译失败。
- 正确写法:
std::ranges::fill(v, 42)(v是容器或数组) - 错误写法:
std::ranges::fill(begin(v), end(v), 42)(这不是std::ranges::fill的重载) - 支持 C 风格数组:
int a[5]; std::ranges::fill(a, 0); - 不支持只传首尾指针构成的“半开区间”,哪怕类型是
int*—— 它需要能推导出range的完整概念
填充子范围:用 views::subrange 或容器切片
想填 [2, 5) 这样的子范围?std::ranges::fill 本身不直接支持索引切片,得先构造一个子视图。最常用的是 std::views::subrange,或者直接用容器的 subspan(std::span)或 std::ranges::subrange。
- 对
std::vector:std::ranges::fill(std::ranges::subrange(v.begin() + 2, v.begin() + 5), 99); - 对原生数组更推荐
std::span:std::span arr{a}; std::ranges::fill(arr.subspan(2, 3), -1); - 注意:不能直接写
v | std::views::drop(2) | std::views::take(3),因为这产生的是一个 lazy view,而std::ranges::fill要求左值 range 或可修改的 view(某些 view 不满足std::ranges::borrowed_range或可写性)
常见编译错误和类型陷阱
报错 “no matching function for call to ‘fill’” 通常是因为传入了非 range 类型,或值类型不匹配。尤其注意 const 容器和 move-only 类型。
-
const std::vector<int> v = {1,2,3}; std::ranges::fill(v, 0);</int>→ 编译失败:v是 const,无法写入 -
std::vector<:unique_ptr>> ptrs(3); std::ranges::fill(ptrs, nullptr);</:unique_ptr>→ 合法,但会移动赋值(ptrs原有元素被销毁) - 如果值类型没有拷贝/移动构造函数,且容器元素是 const-qualified,也会失败
- 使用
auto&& r = ...; std::ranges::fill(r, x);时,确保r是左值引用,避免绑定到临时 view 导致生命周期问题
与 std::fill 的性能和语义差异
底层实现几乎相同,都是循环赋值;区别主要在接口约束和 ADL 友好性。但有一个实际影响:std::ranges::fill 会参与范围定制点查找(customization point objects),如果你为自定义类型特化了 std::ranges::fill,它会被调用;而 std::fill 不会。
立即学习“C++免费学习笔记(深入)”;
- 对标准容器,二者生成的汇编代码通常一致,无性能差别
- 若你用了
std::ranges::fill却意外触发了自定义重载,而该重载没处理边界或效率低,就可能出问题 - 跨平台时注意:MSVC 2022 17.5+、GCC 12+、Clang 15+ 才完整支持
std::ranges::fill;早期版本可能只提供std::fill
arr[2:5] = [x]*3 那样“自然切片”——C++ 的 ranges 操作必须显式构造子范围,且要时刻检查是否可写、是否左值、是否在作用域内有效。


















