[英]understanding how zip in range-v3 works
我试图了解 range::views::zip 如何在 range-v3 中工作。 我知道这是一个范围,它允许通过在不同范围内创建元素的元组来在一个循环中迭代多个范围。
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
无法编译并给出以下错误
/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
无法编译并出现以下错误:
/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 算法可以正常工作,但在某些情况下却不行。 有人可以对此给出一些解释吗?
查看类型:
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::pair
值。 reference
类型是一个ranges::common_pair
引用。
std::sort
使用std::iter_swap
,它是根据取消引用迭代器和调用std::swap
来指定的。 所以std::sort
将尝试交换两个ranges::common_pair
引用。 另一方面, ranges::actions::sort
使用了ranges::iter_swap
,它是为处理引用的对和元组而定制的。
引用对和元组是/是标准库中的第二个 class 公民。
ranges::actions::unique
需要一个可擦除的范围,这显然不满足。
添加
range-v3的文档很少。 要查找上述信息,当然可以查看 range-v3 的源代码,在 godbolt.org 上进行快速实验(range-v3 是一个可用的库),以及查找变量类型的“标准”C++ 技巧(例如,调用已声明但未定义的 function 模板,变量类型作为模板参数,并查看调用了哪个实例化)。
要对unique
进行更多评论, ranges::action::unique
不会返回迭代器。 它擦除非唯一元素并返回一个范围(参见源代码)。 在省略的编译器错误的一部分中,该错误引用了该范围不可擦除的事实(隐藏在一个巨大的错误中)。
ranges::unique
返回一个迭代器,并且可以正确调用。 这是一个basic_iterator<...>
。 一种选择是使用ranges::distance
来查找与begin
zip 迭代器的距离,并使用它来获取底层迭代器:
auto zip_uniq_iter = ranges::unique(zip);
auto first_uniq_iter = std::next(v1.begin(), ranges::distance(ranges::begin(zip), zip_uniq_iter));
您不能在视图上使用 std::sort 。 但是您可以将视图转换为矢量,然后它可以工作: https://godbolt.org/z/_FvCdD
我可以推荐以下网站以获取有关范围的更多信息:
https://www.walletfox.com/course/quickref_range_v3.php https://mariusbancila.ro/blog/2019/01/20/cpp-code-samples-before-and-after-ranges/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.