ranges library separates the ability 到 iterate 来自 ownership, traversal strength, 和 lazy transformation. 一个 range supplies iteration boundaries; a view 是 a range suited 到 adaptor pipelines; an adaptor builds a new view whose elements 是 evaluated 当 iteration requests them.
#include <ranges>
#include <vector>
std::vector<int> source{1, 2, 3, 4, 5};
auto even_squares = source
| std::views::filter([](int value) { return value % 2 == 0; })
| std::views::transform([](int value) { return value * value; });Constructing even_squares does 不 transform every element. Iteration invokes the predicate 和 transformation, so changes 到 source 在……之前 iteration 可以 be observed subject 到 the 源码 container’s invalidation rules.
核心概念 #
A type models std::ranges::range 当 std::ranges::begin 和 std::ranges::end 是 valid 用于 an lvalue 的 type. Iterator 和 sentinel types need 不 be the same. concept establishes 仅 iteration 是 possible; it says nothing about ownership, size, multipass traversal, contiguity, 或 iterator lifetime.
template<class T>
concept range = requires(T& value) {
std::ranges::begin(value);
std::ranges::end(value);
};standard’s definition has equivalent intent but 使用 its own exposition-only details. std::vector<int> 和 std::vector<int>& both model range.
std::ranges::view refines range 用于 lightweight, adaptable range objects. Its syntactic definition combines range, std::movable, 和 std::ranges::enable_view; the important requirements 是 semantic. 一个 view 必须 have constant-time move construction, 和 its copying, moving, assignment, 和 destruction requirements prevent an adaptor pipeline 来自 unexpectedly doing element-wise work. 一个 std::vector 是 a range but 不 a view because copying its elements 是 不 constant time. std::string_view, std::ranges::ref_view, 和 many 生成的 ranges 是 views.
A program-defined view generally derives 来自 std::ranges::view_interface 或 std::ranges::view_base. view_interface<D> 是 a CRTP helper conditionally supplies members such 作为 empty, front, back, data, size, 和 indexing 仅 当 D has the required range capabilities. 一个 program may specialize enable_view 到 true 仅 用于 a cv-unqualified program-defined type actually satisfies the view requirements; the specialization 是 a semantic promise, 不 a constraint bypass.
viewable_range 和 views::all
#
viewable_range answers a different question: whether a particular range expression 可以 be converted 到 a view. It admits constructible views 和 suitable lvalue 或 movable non-view inputs, 同时 excluding problematic initializer-list cases. specification has evolved since C++20, so application 代码 应当 使用 the concept rather than reproduce its definition.
std::views::all 是 the conversion boundary. Conceptually, it preserves a constructible input view, wraps a non-view lvalue in ref_view, 和 wraps an eligible non-view rvalue in owning_view.
std::vector<int> values{1, 2, 3};
auto borrowed = std::views::all(values); // ref_view
static_assert(std::ranges::view<decltype(borrowed)>);
auto owned = std::views::all(std::vector<int>{1, 2}); // owning_view
A ref_view does 不 extend the 源码 object’s lifetime. Returning a view refers 到 a local container 是 therefore erroneous. Not every view 是 non-owning: owning_view owns its base range 和 single_view stores its value. Determine lifetime 来自 the concrete view 和 the 源码 expression, 不 来自 the word “view.”
borrowed_range 是 another independent property. It permits an algorithm 到 返回 iterators 来自 an rvalue range rather than std::ranges::dangling, because iterators 来自 concrete range 可以 survive destruction 的 the range object. It does 不 mean every iterator 是 perpetually valid; container mutation 和 the lifetime 的 any underlying storage still matter.
工厂与适配器 #
Factories create 源码 views, 同时 adaptors transform an existing viewable_range.
| Facility | Kind | Standard Baseline |
|---|---|---|
views::empty<T> | Empty 源码 view | C++20 |
views::single(value) | One stored 值 | C++20 |
views::iota(first, bound) | Incrementing 生成的 sequence | C++20 |
views::istream<T>(stream) | Lazily extracted stream values | C++20 |
views::repeat(value, bound) | Repeated 值 | C++23 |
views::cartesian_product(...) | Cartesian product | C++23 |
views::counted(iterator, count) | Counted 源码 range | C++20 |
views::transform, filter, take, drop, reverse, split, lazy_split, join, common, elements, keys, 和 values 是 C++20 adaptors. C++23 adds adaptors including adjacent, slide, chunk, stride, zip, zip_transform, join_with, 和 as_const. Availability depends 在 both the selected language mode 和 the standard library’s implementation.
An adaptor 对象 可以 be invoked directly 或 partially applied:
auto doubled = std::views::transform(source, [](int value) {
return value * 2;
});
auto double_each = std::views::transform([](int value) {
return value * 2;
});
auto also_doubled = double_each(source);partially applied 结果 是 a range adaptor closure object. For a closure closure 和 viewable_range range, range | closure has the effect 的 closure(range). Closures 可以 compose:
auto useful = std::views::filter(is_valid) | std::views::transform(normalize);
auto result = source | useful;C++23 提供 std::ranges::range_adaptor_closure 用于 portable user-defined closures. Before C++23, implementation-internal closure bases were 不 application interfaces.
范围属性与工具 #
Refinement concepts describe independent properties 的 a range:
| Concept | Meaning |
|---|---|
input_range | Supports single-pass input traversal. |
forward_range | Supports multipass forward traversal. |
bidirectional_range | Supports backward traversal. |
random_access_range | Supports constant-time indexed iterator movement. |
contiguous_range | Elements occupy contiguous storage. |
sized_range | ranges::size 是 valid,使用 amortized constant complexity. |
common_range | Iterator 和 sentinel have the same type. |
borrowed_range | Rvalue-origin iterators need 不 dangle solely 来自 range destruction. |
Traversal concepts refine one another 来自 input 通过 contiguous. sized_range, common_range, 和 borrowed_range describe separate dimensions. C++23 adds constant_range; 使用 it 仅 当 the project baseline 提供 it.
Customization-point objects handle arrays, members, 和 ADL correctly in generic code:
auto first = std::ranges::begin(source);
auto last = std::ranges::end(source);
auto count = std::ranges::size(source);Other utility objects include cbegin, cend, rbegin, rend, empty, data, cdata, 和 ssize. Prefer them 到 assuming a .begin() member.
Range type aliases preserve iterator 和 proxy-reference behavior:
template<std::ranges::range R>
using iterator_t = std::ranges::iterator_t<R>;
template<std::ranges::range R>
using value_t = std::ranges::range_value_t<R>;
template<std::ranges::range R>
using reference_t = std::ranges::range_reference_t<R>;Related aliases include sentinel_t, range_difference_t, range_size_t, 和 range_rvalue_reference_t. Const-oriented aliases such 作为 const_iterator_t 和 range_const_reference_t have C++23 availability constraints.
算法、投影与物化 #
Range algorithms accept ranges directly 和 可以 apply a projection 在……之前 their main operation. 一个 projection changes how one algorithm observes an element; a transform view changes what iteration yields.
struct Record {
int id;
std::string name;
};
std::ranges::sort(records, {}, &Record::name);empty comparator selects the default ordering, 同时 the projection supplies member names 到 it. Projections do 不 materialize transformed values.
Materialize a view 当 an owning result, stable traversal 在……之后 a 源码 change, 或 an eager boundary 是 required. 在 C++23, std::ranges::to expresses the conversion directly:
auto output = std::ranges::to<std::vector<int>>(even_squares);On a C++20 baseline, construct a compatible container 来自 the view’s iterator 和 sentinel 仅 当 container 支持 the pair, 或 insert 通过 its appropriate range/iterator interface. Materialization 是 the point performs the lazy work 和 establishes a separate result; it 应当 be deliberate rather than an accidental side effect 的 choosing a container API.
评论
在 GitHub 上阅读或评论(发表评论需要登录)