第7章 范围和视图的工具¶
7.1 范围作为视图的实用工具¶
7.1.1 std::views::all()
¶
std::views::all(rg)
:
+ 如果rg
已经是视图, 则为rg
的副本
+ 否则, rg
的std::ranges::ref_view
是一个左值
+ 否则, 若rg
的std::ranges::owned_view
是右值(未命名的临时对象或用std::move
标记的范围对象)
7.1.1.1 std::views::all_t<>类型¶
std::vector<int> v{0, 8, 15, 47, 11, -1, 13};
std::views::all_t<decltype(v)> a1{v}; // ERROR
std::views::all_t<decltype(v)&> a2{v}; // ref_view<vector<int>>
std::views::all_t<decltype(v)&&> a3{v}; // ERROR
std::views::all_t<decltype(v)> a4{std::move(v)}; // owning_view<vector<int>>
std::views::all_t<decltype(v)&> a5{std::move(v)}; // ERROR
std::views::all_t<decltype(v)&&> a6{std::move(v)}; // owning_view<vector<int>>
7.1.2 std::views::counted()
¶
std::views::counted(beg, sz)
创建一个以beg
开头的范围的前sz
个元素, 由开发者保证beg
和sz
是有效的.
注意, 为了性能, std::views::counted()
的返回类型有所不一样:
+ contiguous_itertor
则返回 std::span
, 其实就是内存连续的的容器,适用于std::vector
,std::array
, 原始指针, 原始数组, 迭代器
+ std::random_access_iterator
则返回std::views::subrange
且迭代器是std::random_access_iterator
,适用于std::deque
+ 否则返回std::views::subrange
, 以std::default_sentinel_t
类型的哨兵作为结束
7.1.3 std::views::common()
¶
范围适配器std::views::common()
为传递的范围生成一个**具有统一类型**的视图, 用于开始迭代器和哨兵(结束迭代器). 其行为类似于范围适配器 std::views::all()
,若其迭代器具有不同的类型,则会从传递的参数创建std::ranges::common_view
template<typename BegT, typename EndT>
void callAlgo(BegT beg, EndT end) {
auto v = std::views::common(std::ranges::subrange(beg, end));
algo(v.begin(), v.end());
}
7.2 新迭代器类别¶
概念 | 约束 | 供应者 |
---|---|---|
std::input_iterator | 可读取,可递增,支持解引用 | istream 迭代器,单向输入流 |
std::output_iterator | 可写入,可递增,支持赋值 | ostream 迭代器,插入器 |
std::forward_iterator | 继承 input_iterator,支持多次遍历 | std::forward_list<>,无序容器迭代器 |
std::bidirectional_iterator | 继承 forward_iterator,支持双向移动 | std::list<>,std::set<>,std::map<> |
std::random_access_iterator | 继承 bidirectional_iterator,支持随机访问 | std::deque<>,支持 +,-,<,> 运算 |
std::contiguous_iterator | 继承 random_access_iterator,元素在连续内存中 | std::vector<>,std::array<>,原始指针 |
新增一个iterator_concept
, 并定义可以设置该属性来表示一个不同于传统类别的C++20类别.
std::vector vec{1, 2, 3, 4};
auto pos1 = vec.begin();
decltype(pos1)::iterator_category // type std::random_access_iterator_tag
decltype(pos1)::iterator_concept // type std::contiguous_iterator_tag
auto v = std::views::iota(1);
auto pos2 = v.begin();
decltype(pos2)::iterator_category // type std::input_iterator_tag
decltype(pos2)::iterator_concept // type std::random_access_iterator_tag
有效的 C++20 输入迭代器可能根本不是 C++17 迭代器 (例如,不提供复制)。对于这些迭代器, 传统的迭代器特性不起作用。由于这个原因,从 C++20 开始: • 使用 std::iter_value_t 代替 iterator_traits<>::value_type. • 使用 std::iter_reference_t 代替 iterator_traits<>::reference. • 使用 std::iter_difference_t 代替 iterator_traits<>::difference_type.
7.3 新增迭代器和哨兵类型¶
• std::counted_iterator 用于迭代器,该迭代器本身有一个计数来指定范围的结束 • std::common_iterator 用于公共迭代器类型,可用于不同类型的两个迭代器 • std::default_sentinel_t 用于结束迭代器,强制迭代器检查其结束 • std::unreachable_sentinel_t 表示永远无法到达的 end 迭代器,表示无限范围 • std::move_sentinel 用于将副本映射到 move 的 end 迭代器
7.3.1 std::counted_iterator¶
7.3.1 std::common_iterator¶
7.3.1 std::default_sentinel_t¶
7.3.1 std::unreachable_sentinel_t¶
7.3.1 std::move_sentinel¶
7.4 处理范围的新函数¶
函数 | 意义 |
---|---|
std::ranges::empty(rg) | 生成的范围是否为空 |
std::ranges::size(rg) | 生成范围的大小 |
std::ranges::ssize(rg) | 将范围的大小作为 signed 类型的值 |
std::ranges::begin(rg) | 生成指向该范围的第一个元素的迭代器 |
std::ranges::end(rg) | 生成范围哨兵(一个迭代器) |
std::ranges::cbegin(rg) | 生成指向范围第一个元素的常量迭代器 |
std::ranges::cend(rg) | 生成范围的一个常量哨兵(一个到末尾的常量迭代器) |
std::ranges::rbegin(rg) | 生成范围内第一个元素的反向迭代器 |
std::ranges::rend(rg) | 生成范围的反向前哨(一个迭代器到末尾) |
std::ranges::crbegin(rg) | 生成指向范围第一个元素的反向常量迭代器 |
std::ranges::crend(rg) | 生成范围的反向常量哨兵(一个到末尾的常量迭代器) |
std::ranges::data(rg) | 生成该范围的原始数据 |
std::ranges::cdata(rg) | 生成具有 const 元素的范围的原始数据 |
表 7.3 用于处理范围元素的泛型函数