本文翻译自:C++11 reverse range-based for-loop
Is there a container adapter that would reverse the direction of iterators so I can iterate over a container in reverse with range-based for-loop? 是否有一个容器适配器可以颠倒迭代器的方向,以便我可以使用基于范围的for循环反向迭代容器?
With explicit iterators I would convert this: 使用显式迭代器,我可以将其转换为:
for (auto i = c.begin(); i != c.end(); ++i) { ...into this: 到这个:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...I want to convert this: 我想将其转换为:
for (auto& i: c) { ...to this: 对此:
for (auto& i: std::magic_reverse_adapter(c)) { ...Is there such a thing or do I have to write it myself? 有这样的事情还是我必须自己写?
参考:https://stackoom.com/question/ZqJj/C-基于反向范围的for循环
This should work in C++11 without boost: 这应该可以在C ++ 11中正常工作而无需增强:
namespace std { template<class T> T begin(std::pair<T, T> p) { return p.first; } template<class T> T end(std::pair<T, T> p) { return p.second; } } template<class Iterator> std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it) { 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) { return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r))); } for(auto x: make_reverse_range(r)) { ... }Actually, in C++14 it can be done with a very few lines of code. 实际上,在C ++ 14中,只需几行代码即可完成。
This is a very similar in idea to @Paul's solution. 这在思想上与@Paul的解决方案非常相似。 Due to things missing from C++11, that solution is a bit unnecessarily bloated (plus defining in std smells). 由于C ++ 11中缺少某些内容,因此该解决方案有点不必要地过大(加上在std气味中定义)。 Thanks to C++14 we can make it a lot more readable. 感谢C ++ 14,我们可以使它更具可读性。
The key observation is that ranged-based for-loops work by relying on begin() and end() in order to acquire the range's iterators. 关键观察是基于范围的for循环通过依靠begin()和end()来获取范围的迭代器。 Thanks to ADL , one doesn't even need to define their custom begin() and end() in the std:: namespace. 多亏了ADL ,甚至不需要在std ::名称空间中定义其自定义begin()和end() 。
Here is a very simple-sample solution: 这是一个非常简单的示例解决方案:
// ------------------------------------------------------------------- // --- Reversed iterable template <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 }; }This works like a charm, for instance: 例如,这就像一个咒语一样工作:
template <typename T> void print_iterable (std::ostream& out, const T& iterable) { for (auto&& element: iterable) out << element << ','; out << '\n'; } int main (int, char**) { using namespace std; // on prvalues print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, })); // on const lvalue references const list<int> ints_list { 1, 2, 3, 4, }; for (auto&& el: reverse(ints_list)) cout << el << ','; cout << '\n'; // on mutable lvalue references vector<int> ints_vec { 0, 0, 0, 0, }; size_t i = 0; for (int& el: reverse(ints_vec)) el += i++; print_iterable(cout, ints_vec); print_iterable(cout, reverse(ints_vec)); return 0; }prints as expected 按预期打印
4,3,2,1, 4,3,2,1, 3,2,1,0, 0,1,2,3,NOTE std::rbegin() , std::rend() , and std::make_reverse_iterator() are not yet implemented in GCC-4.9. 注意 std::rbegin() , std::rend()和std::make_reverse_iterator()在GCC-4.9中尚未实现。 I write these examples according to the standard, but they would not compile in stable g++. 我根据标准编写了这些示例,但是它们无法在稳定的g ++中编译。 Nevertheless, adding temporary stubs for these three functions is very easy. 但是,为这三个功能添加临时存根非常容易。 Here is a sample implementation, definitely not complete but works well enough for most cases: 这是一个示例实现, 肯定还不完整,但在大多数情况下效果很好:
// -------------------------------------------------- template <typename I> reverse_iterator<I> make_reverse_iterator (I i) { return std::reverse_iterator<I> { i }; } // -------------------------------------------------- template <typename T> auto rbegin (T& iterable) { return make_reverse_iterator(iterable.end()); } template <typename T> auto rend (T& iterable) { return make_reverse_iterator(iterable.begin()); } // const container variants template <typename T> auto rbegin (const T& iterable) { return make_reverse_iterator(iterable.end()); } template <typename T> auto rend (const T& iterable) { return make_reverse_iterator(iterable.begin()); }If not using C++14, then I find below the simplest solution. 如果不使用C ++ 14,那么我在下面找到最简单的解决方案。
#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; } template<typename T> struct Reverse { T& m_T; METHOD(begin()); METHOD(end()); METHOD(begin(), const); METHOD(end(), const); }; #undef METHOD template<typename T> Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }Demo . 演示 It doesn't work for the containers/data-types (like array), which doesn't have begin/rbegin, end/rend functions. 它不适用于没有begin/rbegin, end/rend功能的容器/数据类型(如数组)。
eg: 例如:
int main(int argc, const char * argv[]) { std::vector<int> arr{1, 2, 3, 4, 5}; int arr1[] = {1, 2, 3, 4, 5}; for (auto i : r_wrap(arr)) { printf("%d ", i); } printf("\n"); for (auto i : r_wrap(arr1)) { printf("%d ", i); } printf("\n"); return 0; }You could simply use BOOST_REVERSE_FOREACH which iterates backwards. 您可以简单地使用向后迭代的BOOST_REVERSE_FOREACH 。 For example, the code 例如,代码
#include <iostream> #include <boost\foreach.hpp> int main() { int integers[] = { 0, 1, 2, 3, 4 }; BOOST_REVERSE_FOREACH(auto i, integers) { std::cout << i << std::endl; } return 0; }generates the following output: 生成以下输出:
4 3 2 1 0