c++ 主要范围适配器 std::views::a11 ()

438 阅读2分钟

主要范围适配器

C++提供了多个范围适配器,可轻松创建具有最佳性能的视图。

其中一些适配器适用于特定的视图类型。但是,其中一些可能会根据传递范围的特征创建不同的东西。

例如,如果适配器已经具有结果的特征,则它们可能会生成传递的范围。

有几个主要的适配器可以轻松创建视图或将范围转换为具有特定特征(独立于内容)的视图。这些适配器是:

  • std::views::a11 (),它是为传递的范围生成视图的主要适配器

  • std::views::counted(),是将开始和计数转换为视图的主要适配器

  • std::views::common (),它为开始迭代器和 sentinel(结束迭代器)生成具有协调类型的视图,以便能够将范围/视图传递给传统的范围参数

范围适配器 a11()

范围适配器 std::views::a11 () 是将任何尚未成为视图的范围转换为视图的适配器。

al1(rg)yields

  • 如果 rg 已经是视图,则为 rg 的副本
  • 否则,rg 的 std::ranges::ref_view

例如:

std::vector<int> vec;

std::ranges::iota_view iv{1, 10};

...



auto v1 = std::views::al1(vec); 

auto v2=std::views::all(iv);

auto v3 = std::views::al1(std::views::al1(vec));

可以传递给 a11() 的参数必须已经是视图,或者是作为左值传递的范围:

std::vector vec{1,2,3};

std::ranges::iota_view aView{1};


std::views::al1(vec);

std::views: :al1(getVector());

std::views::all(std::move(vec));

std::views::all(aView);

std::views::al1(getIotaView());


C++20 还将类型 std::views::a11_t<> 定义为类型 al1() 生成。此类型反映了 al1() 仅适用于视图或左值范围的事实。它不适用于尚未成为视图的右值范围:

std::views::al1_t<std::vector<int>>;

std::views::al1_t<std::vector<int>&>;

std::views::all_t<std::vector<int>&&>;

std::views::all_t<std::ranges::iota_view<int>>;

因此,如果您需要 a11() 在表达式或名称 urg 的泛型代码中生成的类型,而不是编写:

decltype(std::views::al1(arg))

你可以写

std::views::all_t<decltype(arg)&>;

&在这里很重要(除非你已经知道arg是一个视图)。如果传递 decltype 不是视图的范围对象的名称,则还可以使用其他括号将其转换为表达式。

但是,仅使用名称不会编译:

std::views::all_t<decltype((name))>;

std::views::all_t<decltype(name)>;


这是使用 all_t<> 声明视图时要考虑的问题。

concept viewable_range可用于检查类型是否可以用于all_t<>(因此相应的对象将传递给 al1()):

std: :ranges: :viewable_range<std::vector<int>>

std: :ranges: :viewable_range<std::vector<int>&>

std::ranges: :viewable_range<std::vector<int>&&>

std: :ranges: :viewable_range<std::ranges::iota_view<int>>

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情