C ++ 11基于反向范围的for循环

是否有一个容器适配器可以颠倒迭代器的方向,以便我可以使用基于范围的for循环反向迭代容器?


使用显式迭代器,我可以将其转换为:


for (auto i = c.begin(); i != c.end(); ++i) { ...

到这个:


for (auto i = c.rbegin(); i != c.rend(); ++i) { ...

我想将其转换为:


for (auto& i: c) { ...

对此:


for (auto& i: std::magic_reverse_adapter(c)) { ...

有这样的事情还是我必须自己写?


catspeake
浏览 1587回答 3
3回答

慕尼黑8549860

实际上,Boost确实具有这样的适配器:boost::adaptors::reverse。#include <list>#include <iostream>#include <boost/range/adaptor/reversed.hpp>int main(){&nbsp; &nbsp; std::list<int> x { 2, 3, 5, 7, 11, 13, 17, 19 };&nbsp; &nbsp; for (auto i : boost::adaptors::reverse(x))&nbsp; &nbsp; &nbsp; &nbsp; std::cout << i << '\n';&nbsp; &nbsp; for (auto i : x)&nbsp; &nbsp; &nbsp; &nbsp; std::cout << i << '\n';}

拉丁的传说

实际上,在C ++ 14中,只需几行代码即可完成。这在思想上与@Paul的解决方案非常相似。由于C ++ 11中缺少某些内容,因此该解决方案有点不必要地过大(加上在std气味中定义)。感谢C ++ 14,我们可以使它更具可读性。关键的观察结果是,基于范围的for循环通过依赖begin()和end()来获取范围的迭代器而工作。由于ADL,一个甚至不需要定义自己的自定义begin(),并end()在的std ::命名空间。这是一个非常简单的示例解决方案:// -------------------------------------------------------------------// --- Reversed iterabletemplate <typename T>struct reversion_wrapper { T& iterable; };template <typename T>auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }template <typename T>auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }template <typename T>reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }例如,这就像一个咒语一样工作:template <typename T>void print_iterable (std::ostream& out, const T& iterable){&nbsp; &nbsp; for (auto&& element: iterable)&nbsp; &nbsp; &nbsp; &nbsp; out << element << ',';&nbsp; &nbsp; out << '\n';}int main (int, char**){&nbsp; &nbsp; using namespace std;&nbsp; &nbsp; // on prvalues&nbsp; &nbsp; print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, }));&nbsp; &nbsp; // on const lvalue references&nbsp; &nbsp; const list<int> ints_list { 1, 2, 3, 4, };&nbsp; &nbsp; for (auto&& el: reverse(ints_list))&nbsp; &nbsp; &nbsp; &nbsp; cout << el << ',';&nbsp; &nbsp; cout << '\n';&nbsp; &nbsp; // on mutable lvalue references&nbsp; &nbsp; vector<int> ints_vec { 0, 0, 0, 0, };&nbsp; &nbsp; size_t i = 0;&nbsp; &nbsp; for (int& el: reverse(ints_vec))&nbsp; &nbsp; &nbsp; &nbsp; el += i++;&nbsp; &nbsp; print_iterable(cout, ints_vec);&nbsp; &nbsp; print_iterable(cout, reverse(ints_vec));&nbsp; &nbsp; return 0;}按预期打印4,3,2,1,4,3,2,1,3,2,1,0,0,1,2,3,注意 std::rbegin(),std::rend()和std::make_reverse_iterator()尚未在GCC-4.9中实现。我根据标准编写了这些示例,但是它们无法在稳定的g ++中编译。但是,为这三个功能添加临时存根非常容易。这是一个示例实现,肯定还不完整,但在大多数情况下效果很好:// --------------------------------------------------template <typename I>reverse_iterator<I> make_reverse_iterator (I i){&nbsp; &nbsp; return std::reverse_iterator<I> { i };}// --------------------------------------------------template <typename T>auto rbegin (T& iterable){&nbsp; &nbsp; return make_reverse_iterator(iterable.end());}template <typename T>auto rend (T& iterable){&nbsp; &nbsp; return make_reverse_iterator(iterable.begin());}// const container variantstemplate <typename T>auto rbegin (const T& iterable){&nbsp; &nbsp; return make_reverse_iterator(iterable.end());}template <typename T>auto rend (const T& iterable){&nbsp; &nbsp; return make_reverse_iterator(iterable.begin());}

子衿沉夜

这应该可以在C ++ 11中正常工作而无需增强:namespace std {template<class T>T begin(std::pair<T, T> p){&nbsp; &nbsp; return p.first;}template<class T>T end(std::pair<T, T> p){&nbsp; &nbsp; return p.second;}}template<class Iterator>std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it){&nbsp; &nbsp; return std::reverse_iterator<Iterator>(it);}template<class Range>std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range&& r){&nbsp; &nbsp; return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r)));}for(auto x: make_reverse_range(r)){&nbsp; &nbsp; ...}
打开App,查看更多内容
随时随地看视频慕课网APP