是否有一种容器适配器可以反转迭代器的方向,以便我可以使用基于范围的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)) { ...
有这样的东西吗,还是我必须自己写?
从cppreference中得到这个例子。它适用于:
GCC 10.1+带标志-std=c++20
#include <ranges>
#include <iostream>
int main()
{
static constexpr auto il = {3, 1, 4, 1, 5, 9};
std::ranges::reverse_view rv {il};
for (int i : rv)
std::cout << i << ' ';
std::cout << '\n';
for(int i : il | std::views::reverse)
std::cout << i << ' ';
}
如果不使用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确实有这样的adaptor: Boost::adaptors::reverse。
#include <list>
#include <iostream>
#include <boost/range/adaptor/reversed.hpp>
int main()
{
std::list<int> x { 2, 3, 5, 7, 11, 13, 17, 19 };
for (auto i : boost::adaptors::reverse(x))
std::cout << i << '\n';
for (auto i : x)
std::cout << i << '\n';
}
template <typename C>
struct reverse_wrapper {
C & c_;
reverse_wrapper(C & c) : c_(c) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
};
template <typename C, size_t N>
struct reverse_wrapper< C[N] >{
C (&c_)[N];
reverse_wrapper( C(&c)[N] ) : c_(c) {}
typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};
template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
return reverse_wrapper<C>(c);
}
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;
}
如果您可以使用范围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