jjc*_*mar 0 c++ iterator range-v3
我试图了解 range::views::zip 在 range-v3 中如何工作。据我所知,它是一个范围,允许通过创建不同范围中的元素元组来在一个循环中迭代多个范围。
\n\nstd::vector<int> v1 = {0, 1, 2};\nstd::vector<char> v2 = {'a', 'b', 'c'};\n\n\nauto zip = ranges::views::zip(v1,v2);\n// zip(v1,v2) = [(0,a), (1,b), (2,c)]\n\nranges::actions::sort(zip);\nstd::sort(std::begin(zip), std::end(zip));\nRun Code Online (Sandbox Code Playgroud)\n\n使用排序ranges::actions工作正常,但std::sort无法编译并给出以下错误
/usr/include/c++/9.3.0/bits/stl_algobase.h:151: error: no matching function for call to \xe2\x80\x98swap(concepts::return_t<ranges::common_pair<int&, double&>, void>, concepts::return_t<ranges::common_pair<int&, double&>, void>)\xe2\x80\x99\n 151 | swap(*__a, *__b);\n | ~~~~^~~~~~~~~~~~\nRun Code Online (Sandbox Code Playgroud)\n\n为什么会发生这种情况?
\n\n我还尝试同时删除两个容器中的元素。ranges::actions::unique无法编译并出现以下错误:
/home/jjcasmar/projects/cpfsofaplugin/src/CPFSofaPlugin/minimalExample.cpp:27: error: no match for call to \xe2\x80\x98(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> > > >&)\xe2\x80\x99\n 27 | ranges::actions::unique(v1Andv2);\n | ^\nRun Code Online (Sandbox Code Playgroud)\n\n但是auto lastIt = std::unique(std::begin(v1Andv2), std::end(v1Andv2))编译 find,尽管我不知道如何让 zip 的内部迭代器能够擦除末尾元素。
我真的不明白这在幕后是如何工作的,以及为什么在某些情况下 std 算法工作正常,但在某些情况下却不能。有人可以对此做出一些解释吗?
\n看类型:
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&>>);
Run Code Online (Sandbox Code Playgroud)
该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定制的来处理引用对和元组。
引用对和元组是标准库中的二等公民。
ranges::actions::unique需要一个可擦除范围,这显然不能满足。
添加
range-v3 的文档很少。要查找上述信息,当然可以查看 range-v3 的源代码,在 godbolt.org 上进行快速实验(range-v3 是一个可用的库),以及查找变量类型的“标准”C++ 技巧(例如,调用已声明但未定义的函数模板,以变量的类型作为模板参数,并查看调用了哪个实例化)。
要对 进行更多评论unique,ranges::action::unique不返回迭代器。它删除非唯一元素并返回一个范围(请参阅源代码)。在被省略的编译器错误的一部分中,该错误引用了该范围不可擦除的事实(埋藏在一个巨大的错误中)。
ranges::unique返回一个迭代器并且可以无错误地调用。这是一个basic_iterator<...>。一种选择是使用ranges::distance来查找距 zip 迭代器的距离begin,并使用它来获取底层迭代器:
auto zip_uniq_iter = ranges::unique(zip);
auto first_uniq_iter = std::next(v1.begin(), ranges::distance(ranges::begin(zip), zip_uniq_iter));
Run Code Online (Sandbox Code Playgroud)