此代码:
for (std::list<point>::const_iterator it = controlPoints->begin();
it != controlPoints->end();
++it) {
...
}
对应于:
for (int i = 0; i < controlPoints->size; i++) {
...
}
意思是,如果我每次循环都有一个元素,它会迭代列表中的所有元素。
什么对应于:
for (int i = 0; i < controlPoints->size-1; i++) {
...
}
我的意思是,如何使用迭代器循环大小1次?
答案 0 :(得分:9)
显而易见的方法是将迭代器放到最后并递减它:
auto stop = controlPoints.end();
--stop;
for (std::list<point>::const_iterator it = controlPoints->begin();
it != stop;
++it) {
...
}
如果您愿意,可以使用std::advance
或std::next
,但对于这种情况,可以使用简单的减量。
答案 1 :(得分:6)
controlPoints->end()
也是一个迭代器。
你可以这样做:
std::list<point>::const_iterator it = controlPoints->begin();
std::list<point>::const_iterator stop = controlPoints->end();
if ( it != stop) for ( --stop; it != stop; ++it) {
...
}
更详细,但使用该列表是否包含0个,1个或更多元素是安全的。
这里的关键是迭代器可以递增,并且(对于双向迭代器)递减以提前/后退位置,所以它相当于:
int it = 0;
int stop = list.size();
if (it != stop) for( --stop; it < stop; ++it ) {
...
}
答案 2 :(得分:3)
在C ++ 11中,您应该尽可能多地使用基于范围的for循环。 for(;;)
循环很复杂,并且在您编写它们时容易出错。
使用for(:)
循环需要远离您编写它们的复杂性,但是因为您可以编写该基础结构一次并重复使用它,其中的错误可以解决,而不是在整个代码中被发现。
首先,这是一个简单的range_t
:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
std::size_t size() const { return std::distance(begin(), end()); }
using iterator_tag = typename std::iterator_traits<It>::iterator_category;
private:
static It safe_advance( It in, It bound, std::ptrdiff_t n, std::random_access_iterator_tag ) const {
if (n == 0) return in;
if (n < 0) n = (std::min)( n, -std::distance( bound, in ) );
if (n > 0) n = (std::max)( n, std::distance( in, bound ) );
return std::advance( in, n );
}
static It safe_advance( It in, It bound, std::ptrdiff_t n, ... ) const {
if (n == 0) return in;
while (n < 0 && in != bound) {
in = std::prev(in); --n;
}
while (n > 0 && in != bound) {
in = std::next(in); ++n;
}
return in;
}
public:
range_t without_back( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), -(std::ptrdiff_t)n, iterator_tag{} };
}
range_t without_front( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), n, iterator_tag{} };
}
bool empty() const { return begin() == end(); }
decltype(auto) front() const { return *begin(); }
decltype(auto) back() const { return *std::prev(end()); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
// rvalues blocked:
template<class C, class It = decltype( std::begin(std::declval<C&>()) )>
range_t<It> range( C& c ) { return range( std::begin(c), std::end(c) ); }
它存储一系列迭代器,并且本身是可迭代的。
然后:
auto r = range(*controlPoints).without_back();
是范围对象,controlPoints
没有最后一个元素。
使用基于范围的方法可以做到这一点:
for (auto& x : range(*controlPoints).without_back()) {
}
请注意,上面的代码小心地处理了一个空数组。
我们还可以编写一个类似的适配器,让你通过迭代器迭代。我通常通过编写index_iterator
来存储Index
并将++
和==
等传递给它。除非您*
,否则它只会返回Index
。
这对于在整数上创建迭代器很有用,但也可以在迭代器上创建迭代器。
然后为容器中的迭代器创建一系列索引,并获得如下语法:
for (auto it : iterators_into( *controlPoints) ) {
}
为您提供基于范围的循环,如果需要,还可以为您提供迭代器。