C++ C++;11基于倒车档的for循环

C++ C++;11基于倒车档的for循环,c++,c++11,ranged-loops,C++,C++11,Ranged Loops,是否有一个容器适配器可以反转迭代器的方向,以便我可以使用基于范围的for循环反向迭代容器 使用显式迭代器,我将转换为: for (auto i = c.begin(); i != c.end(); ++i) { ... for (auto& i: c) { ... 为此: for (auto i = c.rbegin(); i != c.rend(); ++i) { ... 我想将其转换为: for (auto i = c.begin(); i != c.end(); ++i) {

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

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

for (auto i = c.begin(); i != c.end(); ++i) { ...
for (auto& i: c) { ...
为此:

for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
我想将其转换为:

for (auto i = c.begin(); i != c.end(); ++i) { ...
for (auto& i: c) { ...
为此:

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

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

这对你有用吗:

#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>

int main(int argc, char* argv[]){

  typedef std::list<int> Nums;
  typedef Nums::iterator NumIt;
  typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
  typedef boost::iterator_range<NumIt> irange_1;
  typedef boost::iterator_range<RevNumIt> irange_2;

  Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
  irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
  irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );


  // prints: 1 2 3 4 5 6 7 8 
  for(auto e : r1)
    std::cout << e << ' ';

  std::cout << std::endl;

  // prints: 8 7 6 5 4 3 2 1
  for(auto e : r2)
    std::cout << e << ' ';

  std::cout << std::endl;

  return 0;
}
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[]){
typedef std::list Nums;
typedef Nums::迭代器NumIt;
typedef boost::range\u reverse\u迭代器::type RevNumIt;
typedef boost::迭代器范围irange_1;
typedef boost::iterator_range irange_2;
Nums n={1,2,3,4,5,6,7,8};
irange_1 r1=boost::make_iterator_range(boost::begin(n),boost::end(n));
irange_2 r2=boost::make_iterator_range(boost::end(n),boost::begin(n));
//印刷品:12345678
用于(自动e:r1)

实际上Boost确实有这样的适配器:

#包括
#包括
#包括
int main()
{
std::列表x{2,3,5,7,11,13,17,19};
用于(自动i:boost::Adapters::reverse(x))

std::cout在没有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))
{
    ...
}
名称空间std{
模板
T开始(标准::对p)
{
返回p.first;
}
模板
T端(标准::对p)
{
返回p.second;
}
}
模板
std::reverse_迭代器make_reverse_迭代器(迭代器it)
{
返回std::reverse_迭代器(it);
}
模板
std::配对反向范围(范围和r)
{
返回std::make_pair(make_reverse_迭代器(begin(r)),make_reverse_迭代器(end(r));
}
用于(自动x:使_反向_范围(r))
{
...
}

实际上,在C++14中,只需几行代码就可以完成

这与@Paul的解决方案非常相似。由于C++11中缺少一些东西,该解决方案有点不必要的臃肿(加上在std气味中定义)。多亏了C++14,我们可以使其更具可读性

关键的观察结果是,基于范围的for循环通过依赖于
begin()
end()
来获取范围的迭代器来工作。由于,人们甚至不需要在std::命名空间中定义自定义的
begin()
end()

下面是一个非常简单的示例解决方案:

// -------------------------------------------------------------------
// --- 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 }; }
注意
std::rbegin()
std::rend()
,和
std::make_reverse_iterator()
尚未在GCC-4.9中实现。我根据标准编写了这些示例,但它们不会在稳定的g++中编译。不过,为这三个函数添加临时存根非常容易。下面是一个示例实现,肯定不完整,但在大多数情况下都能很好地工作:

// --------------------------------------------------
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());
}
//--------------------------------------------------
模板
反向迭代器生成反向迭代器(I)
{
返回std::reverse_迭代器{i};
}
// --------------------------------------------------
模板
自动注册(T&iterable)
{
返回make_reverse_迭代器(iterable.end());
}
模板
自动渲染(T&iterable)
{
返回make_reverse_迭代器(iterable.begin());
}
//常量容器变量
模板
自动校准(常数和可校准)
{
返回make_reverse_迭代器(iterable.end());
}
模板
自动渲染(常量和可编辑)
{
返回make_reverse_迭代器(iterable.begin());
}

如果不使用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}; }
#define METHOD(NAME,…)auto NAME uu VA_uargs uu->decltype(m_T.r#NAME){返回m_T.r#NAME;}
模板
结构反转
{
T&m;
方法(begin());
方法(end());
方法(begin(),const);
方法(end(),const);
};
#未定义方法
模板
反向MakeReverse(T&T){返回反向{T};}
.
它不适用于容器/数据类型(如数组),因为它没有
begin/rbegin、end/rend
函数。

模板
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);
}
结构反向包装器{ C&C; 反向包装(C&C):C(C){} typename C::reverse_迭代器begin(){return C_u.rbegin();} typename C::reverse_迭代器end(){return C_u.rend();} }; 模板 结构反向包装{ C&C_[N]; 反向包装器(C(&C)[N]):C(C){ typename std::reverse_迭代器begin(){return std::rbegin(c);} typename std::reverse_迭代器end(){return std::rend(c);} }; 模板 反向包装(C&C){ 返回反向包装(c); }
例如:

int main(int argc,const char*argv[]{
std::向量arr{1,2,3,4,5};
int arr1[]={1,2,3,4,5};
用于(自动i:r_包裹(arr)){
printf(“%d”,i);
}
printf(“\n”);
用于(自动i:r_包裹(arr1)){
printf(“%d”,i);
}
printf(“\n”);
返回0;
}

您可以简单地使用向后迭代的
BOOST\u REVERSE\u 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;
}
如果可以使用,可以使用反向范围适配器
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;
}
请参见

从中获得此示例。它适用于:

GCC 10.1+,带标志-std=c++20

#包括
#包括
int main()
{
静态constexpr auto il={3,1,4,1,5,9};
std::ranges::reverse_view rv{il};
用于(int i:rv)

STD::CUT< P>对不起,但是用当前C++(除了C++ 20),所有这些解决方案似乎都不如使用基于索引的方法。这里没有什么只是“几行代码”。因此,是的:通过一个简单的int循环进行迭代。这是最好的解决方案。

一个反向容器适配器,听起来很有趣,但我认为你必须自己编写。如果标准委员会加快速度,采用基于范围的算法而不是显式的迭代器,我们就不会有这个问题。@deft_code:“而不是?”为什么要放弃基于迭代器的算法?对于不从
begin
end
进行迭代的情况,或者对于处理流迭代器之类的情况,它们会更好,也不会太冗长。Ran
#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}; }
4

3

2

1

0
#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;
}
for (auto const& e : view::reverse(intVec)) {
       std::cout << e << " ";   
}