我需要严格按照元素被推回到它的顺序迭代一个向量。对于我的特殊情况,最好使用迭代器,而不是迭代for-each循环,如下所示:
std::vector<int> vector;
for(int i = 0; i < vector.size(); i++)
//not good, but works
我的问题是,是否可以通过迭代器迭代迭代器:
std::vector<int> v;
for(typename std::vector<int>::iterator i = v.iterator(); i != v.end(); i++)
//good, but I'm not strictly sure about the iterating order.
那么,我可以根据我的要求安全地使用迭代器吗?它是否是标准化的?
答案 0 :(得分:3)
如果您可以访问C ++ 11,则可以使用基于范围的for循环
for (auto i : v)
否则您应该使用begin()
和end()
for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i)
您还可以使用std::begin
和std::end
(这些也需要C ++ 11)
for (std::vector<int>::iterator i = std::begin(v); i != std::end(v); ++i)
begin
会将迭代器返回向量中的第一个元素。 end
会将迭代器返回到超过向量结尾的一个元素。因此,以这种方式迭代元素的顺序既安全又定义。
答案 1 :(得分:2)
如果你想使用迭代器,你的方法很好
for(auto it = v.begin(); it != v.end(); ++it)
迭代顺序实际上取决于容器和实际使用的迭代器。 对于std :: vector,此代码始终在向量中按顺序迭代元素。如果您使用v.rbegin()或v.rend()代替,则订单将被颠倒。 对于另一个容器,顺序是不同的,对于std :: set,相同的代码将按照排序标准的升序迭代元素。
答案 2 :(得分:1)
这是一个过于复杂的解决方案。
首先,我们从index
类型开始。它可以存储任何模拟迭代器和/或积分的东西(基本上,支持+标量,delta到标量,复制,破坏和相等):
template<class T,
class Category=std::random_access_iterator_tag,
class Delta=decltype(std::declval<T>()-std::declval<T>())
>
struct index:
std::iterator<Category, T, Delta, T*, T>
{
T t;
T operator*()const{ return t; }
index& operator++(){++t; return *this;}
index operator++(int){index tmp = *this; ++t; return tmp;}
index& operator--(){--t; return *this;}
index operator--(int){index tmp = *this; --t; return tmp;}
T operator[](size_t i)const{return t+i;}
friend bool operator<(index const& lhs, index const& rhs) {
return rhs.t-lhs.t>0;
}
friend bool operator>(index const& lhs, index const& rhs) {
return rhs<lhs;
}
friend bool operator<=(index const& lhs, index const& rhs) {
return !(lhs>rhs);
}
friend bool operator>=(index const& lhs, index const& rhs) {
return !(lhs<rhs);
}
friend bool operator==(index const& lhs, index const& rhs) {
return lhs.t==rhs.t;
}
friend bool operator!=(index const& lhs, index const& rhs) {
return lhs.t!=rhs.t;
}
friend Delta operator-(index const& lhs, index const& rhs) {
return lhs.t-rhs.t;
}
friend index& operator+=(index& lhs, Delta rhs) {
lhs.t+=rhs;
return lhs;
}
friend index& operator-=(index& lhs, Delta rhs) {
lhs.t-=rhs;
return lhs;
}
friend index operator+(index idx, Delta scalar) {
idx+=scalar;
return idx;
}
friend index operator+(Delta scalar, index idx) {
idx+=scalar;
return idx;
}
friend index operator-(index idx, Delta scalar) {
idx-=scalar;
return idx;
}
};
大部分都不需要,但我想完成。请注意,默认情况下,它声称是一个随机访问迭代器,但它的位置,因为它的引用类型不是引用。我觉得谎言值得。
使用index
,我们都可以创建迭代器迭代器和迭代器迭代器。以下是我们如何创建迭代器迭代器:
using it_category=typename std::iterator_traits<It>::iterator_category;
template<class It, class Category=it_category<It>>
index<It, Category> meta_iterator( It it ) { return {it}; }
接下来,我们希望能够获取一些迭代器,并迭代范围。这意味着我们需要一个范围类型:
template<class It>
struct range {
It b, e;
range(It s, It f):b(s),e(f){}
range():b(),e(){}
It begin()const{return b;}
It end()const{return e;}
bool empty()const{return begin()==end();}
template<class R>
range(R&& r):range(std::begin(r),std::end(r)){}
};
这是一个特征,它采用可迭代范围(不仅是range
,而且还有任何容器)并获取迭代器类型。请注意,一个优秀的ADL启用将是一个好主意:
template<class R>
using iterator=decltype(std::begin(std::declval<R&>()));
随机助手:
template<class R,class It=iterator<R>>
range<It> make_range(R&&r){ return {std::forward<R>(r)}; }
template<class It
range<It> make_range(It s, It f){return {s,f};}
这是一个有用的助手,可以解决我们的问题:
template<class R>
range<meta_iterator<iterator<R>> iterators_into( R&& r ){
return {meta_iterator(std::begin(r)), meta_iterator(std::end(r))};
}
我们完成了:
std::vector<int> v;
for(auto it: iterators_into(v)) {
}
为v
的每个元素返回一个迭代器。
对于工业质量,你想要ADL改进的东西。此外,处理输入范围的右值存储使您可以在for(:)
循环中更好地链接范围适配器。