是否有一种容器适配器可以反转迭代器的方向,以便我可以使用基于范围的for-loop反向迭代容器?

使用显式迭代器,我将转换如下:

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)) { ...

有这样的东西吗,还是我必须自己写?


当前回答

抱歉,但是在当前的c++(除了c++ 20)中,所有这些解决方案似乎都不如仅仅使用基于索引的for。这里没有什么只是“几行代码”。所以,是的:通过一个简单的内循环进行迭代。这是最好的解决办法。

其他回答

如果您可以使用范围v3,那么您可以使用反向范围适配器ranges::view::reverse,它允许您反向查看容器。

一个最小的工作示例:

#include <iostream>
#include <vector>
#include <range/v3/view.hpp>

int main()
{
    std::vector<int> intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    for (auto const& e : ranges::view::reverse(intVec)) {
        std::cout << e << " ";   
    }
    std::cout << std::endl;

    for (auto const& e : intVec) {
        std::cout << e << " ";   
    }
    std::cout << std::endl;
}

参见演示1。

注意:根据Eric Niebler的说法,这个特性将在c++ 20中可用。这可以与<experimental/ranges/range>标头一起使用。然后for语句看起来像这样:

for (auto const& e : view::reverse(intVec)) {
       std::cout << e << " ";   
}

参见演示2

您可以简单地使用向后迭代的BOOST_REVERSE_FOREACH。例如,代码

#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;
}

生成如下输出:

4

3

2

1

0

抱歉,但是在当前的c++(除了c++ 20)中,所有这些解决方案似乎都不如仅仅使用基于索引的for。这里没有什么只是“几行代码”。所以,是的:通过一个简单的内循环进行迭代。这是最好的解决办法。

如果不使用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}; }

演示。 它不适用于容器/数据类型(如数组),因为容器/数据类型没有begin/rbegin, end/rend函数。

这应该在没有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))
{
    ...
}