如何遍历列表,但在size-1处停止
How to iterate through a list but stop at size-1
代码:
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++) {
...
}
我的意思是,如何使用迭代器循环size-1次?
明显的方法是将迭代器移到末尾并自减:
auto stop = controlPoints.end();
--stop;
for (std::list<point>::const_iterator it = controlPoints->begin();
it != stop;
++it) {
...
}
如果您愿意,可以使用std::advance
或std::next
,但对于这种情况,简单的减量就可以了。
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 ) {
...
}
在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
,不包含最后一个元素。
使用range -based for可以这样做:
for (auto& x : range(*controlPoints).without_back()) {
}
注意,上面的代码小心地处理了被输入的空数组。
我们也可以编写一个类似的适配器,允许在迭代器上迭代。我通常通过编写一个index_iterator
来存储Index
,并将++
和==
等传递给它来实现这一点。除非您输入*
,它只返回Index
的副本。
这对于在整数上创建迭代器很有用,但也允许在迭代器上创建迭代器。
然后为容器中的迭代器创建一系列索引,得到如下语法:
for (auto it : iterators_into( *controlPoints) ) {
}
给你基于范围的循环,如果你需要迭代器,也给你迭代器。
相关文章:
- 代码在main()中运行,但在函数中出现错误
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 换位表导致测试失败(但在游戏中运行良好)
- 库标题在标题中不可见,但在 cmake build 下.cpp文件中完全可见.为什么?
- 树莓上的 Libtorch 无法加载 pt 文件,但在 ubuntu 上工作
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- 编译在我的 Mac 上工作,但在集群 (Linux) 上不起作用
- vector.size() 在比较中意外工作
- 我编写了代码将十进制分数转换为其二进制等效数.它编译得很好,但在执行时挂起
- 我的代码运行良好,但在游戏循环中中断
- C++ assigment std::list:<typename>:itrator 在 main 中工作,但在方法中它不起作用
- C++代码在台式机上工作正常,但在笔记本电脑上则不行
- 实现 DFS 在较短的输入下工作正常,但在较大的输入下会抛出分段错误
- 点云库在VS 2019中不起作用,但在VS 2017中确实有效
- C++ Python 模块在 Blender 中崩溃,但在 Python 控制台中不会崩溃
- 字符串回文在String.size()上给出错误答案,但在String.seize()-1上给出正确答案
- 如何遍历列表,但在size-1处停止