首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解zip在range-v3中的工作原理

理解zip在range-v3中的工作原理
EN

Stack Overflow用户
提问于 2020-04-21 19:38:44
回答 2查看 3K关注 0票数 0

我试图了解range::view::zip是如何在range-v3中工作的。我理解这是一个范围,它允许在一个循环中迭代多个范围,方法是在不同范围内创建元素的元组。

代码语言:javascript
复制
std::vector<int> v1 = {0, 1, 2};
std::vector<char> v2 = {'a', 'b', 'c'};


auto zip = ranges::views::zip(v1,v2);
// zip(v1,v2) = [(0,a), (1,b), (2,c)]

ranges::actions::sort(zip);
std::sort(std::begin(zip), std::end(zip));

使用ranges::actions的排序很好,但是std::sort没有编译,并给出了以下错误

代码语言:javascript
复制
/usr/include/c++/9.3.0/bits/stl_algobase.h:151: error: no matching function for call to ‘swap(concepts::return_t<ranges::common_pair<int&, double&>, void>, concepts::return_t<ranges::common_pair<int&, double&>, void>)’
  151 |       swap(*__a, *__b);
      |       ~~~~^~~~~~~~~~~~

为什么会发生这种情况?

我还试图同时删除两个容器中的元素。ranges::actions::unique编译时没有出现以下错误:

代码语言:javascript
复制
/home/jjcasmar/projects/cpfsofaplugin/src/CPFSofaPlugin/minimalExample.cpp:27: error: no match for call to ‘(const ranges::actions::action_closure<ranges::actions::unique_fn>) (ranges::zip_view<ranges::ref_view<std::vector<int, std::allocator<int> > >, ranges::ref_view<std::vector<double, std::allocator<double> > > >&)’
   27 |     ranges::actions::unique(v1Andv2);
      |                                    ^

但是auto lastIt = std::unique(std::begin(v1Andv2), std::end(v1Andv2))编译find,虽然我不知道如何让zip的内部迭代器能够擦除结束元素。

我真的不明白这在引擎盖下是如何工作的,为什么在某些情况下,std算法工作得很好,但在某些情况下却没有。有人能解释一下吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-21 22:59:13

看看这些类型:

代码语言:javascript
复制
auto zip = ranges::views::zip(v1, v2);
// ranges::zip_view<
//   ranges::ref_view<std::vector<int>>
//   ranges::ref_view<std::vector<char>>
// >

auto begin = std::begin(zip);
// ranges::basic_iterator<
//   ranges::iter_zip_with_view<
//     ranges::detail::indirect_zip_fn_,
//     ranges::ref_view<std::vector<int>>,
//     ranges::ref_view<std::vector<char>>
//   >::cursor<false>
// >

using traits = std::iterator_traits<decltype(begin)>;
static_assert(std::is_same_v<traits::value_type, std::pair<int, char>>);
static_assert(std::is_same_v<traits::reference, ranges::common_pair<int&, char&>>);

value_type类型是值的std::pairreference类型是引用的ranges::common_pair

std::sort使用std::iter_swap,这是通过取消迭代器和调用std::swap来指定的。因此,std::sort将尝试交换两个引用的ranges::common_pair。另一方面,ranges::actions::sort使用自定义的ranges::iter_swap来处理引用的对和元组。

引用的对和元组是标准库中的二等公民。

ranges::actions::unique需要一个可擦除的范围,显然这是不满足的。

添加了

range-v3的文档很少。要查找上述信息,当然需要查看range-v3的源代码、对godbolt.org的快速实验(range-v3是可用的库),以及查找变量类型的“标准”C++技巧(例如,使用变量的类型作为模板参数,调用声明但未定义的函数模板,并查看调用了哪些实例化)。

要对unique进行更多的评论,ranges::action::unique不返回迭代器。它擦除非唯一元素并返回一个范围(请参阅来源)。在被省略的编译器错误的一部分中,错误引用了范围不可擦除的事实(隐藏在一个巨大的错误中)。

ranges::unique返回一个迭代器,可以在没有错误的情况下调用。这是一个basic_iterator<...>。一种选择是使用ranges::distance查找与begin zip迭代器的距离,并使用它获取底层迭代器:

代码语言:javascript
复制
auto zip_uniq_iter = ranges::unique(zip);
auto first_uniq_iter = std::next(v1.begin(), ranges::distance(ranges::begin(zip), zip_uniq_iter));
票数 4
EN

Stack Overflow用户

发布于 2020-04-23 21:09:03

不能使用std::排序视图。但是您可以将视图转换为向量,然后它就可以工作了:FvCdD

有关范围的更多信息,我可以推荐以下网站:

v3.php https://mariusbancila.ro/blog/2019/01/20/cpp-code-samples-before-and-after-ranges/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61351815

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档