我有一个std::vector<MyClass*> container
指向某个类的对象的指针,并希望使用基于范围的for循环遍历该向量,就像这样
for (MyClass *item : container)
{
// Do stuff, not changing the container
}
在这个循环中,我想再次遍历容器,但是从容器中的下一个元素开始。在没有迭代器的情况下,我无法真正找到这样做的方法,所以我的解决方案就是只使用那些
for (auto item1 = container.begin(); item1 != container.end(); ++item1)
{
for (auto item2 = item1.next(); item2 != container.end(); ++item2)
{
// Do stuff, not changing the container
}
}
我的问题是:有没有办法做到这一点,而不必求助于迭代器?我意识到基于范围的for循环只是语法糖,并且真的使用了迭代器,但我喜欢我的语法糖!
答案 0 :(得分:3)
(请注意下面的编辑)
for-range循环不允许您访问内部迭代器。一方面,这很好,因为你不能搞砸它。另一方面,这可能是不好的,因为您需要迭代器来知道您在容器中的位置。因此,我们不能使用for-range循环作为外部循环,除非您使用线性内存布局迭代某些内容,您可以将项目的地址作为迭代器。
此外,标准库尚未完成以方便的方式处理范围的任务。我使用Boost中的一些实用程序(例如iterator_range
)来获取此代码段:
using boost::make_iterator_range;
using std::next;
for (auto iter1 = container.begin(), ee = container.end(); iter1 != ee; ++iter1) {
auto& item1 = *iter1;
for (auto& item2 : make_iterator_range(next(iter1),ee)) {
// do something with item1 and item2
}
}
不可否认,不是很漂亮。但这显示了在给定一对迭代器的情况下如何使用for-range循环的一种方法。基本上,for-range循环会占用任何提供开始/结束功能的东西。 make_iterator_range
包装一对迭代器并返回一些提供开始/结束函数的东西。
编辑:我最近了解到boost::irange
也可以生成迭代器序列(而不仅仅是数字序列)。考虑到这一点,请查看此程序:
#include <iostream>
#include <vector>
#include <boost/range/irange.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/adaptor/indexed.hpp>
int main()
{
using std::vector;
using std::next;
using boost::irange;
using boost::make_iterator_range;
namespace ba = boost::adaptors;
vector<double> x {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
for (auto iter1 : irange(begin(x),end(x))) {
auto& item1 = *iter1;
for (auto& item2 : make_iterator_range(next(iter1),end(x))) {
// do something with item1 and item2
std::cout << item1 << " < " << item2 << std::endl;
}
}
return 0;
}
我在C ++ 0x模式下使用G ++ 4.6.3和Boost 1.48进行了测试,它确实有效。
答案 1 :(得分:1)
您可以创建一个可以访问范围的简单类:
#include <vector>
#include <iostream>
template<typename I>
struct Sub {
I _begin;
I _end;
Sub(I b, I e): _begin(b), _end(e) {}
I begin() const { return _begin; }
I end() const { return _end; }
};
template<typename I>
Sub<I> sub(I b, I e) { return Sub<I>(b, e); }
int main() {
std::vector<int> a{0,1,2,3,4,5,6,7,8,9};
for (auto i: sub(a.begin() + 3, a.end() - 1)) {
std::cout << i << "\n";
}
}
此代码打印:
3
4
5
6
7
8
答案 2 :(得分:1)
根据OP的要求添加了我的评论作为答案。
如果没有迭代器,你就无法做到这一点。但是你可以避免放弃用于迭代整个集合的语法糖,参见this answer。我没有测试过那段代码,但对该答案的评论表明boost :: counting_range可能更好。
答案 3 :(得分:0)
循环范围迭代容器中的所有元素。这意味着您可以将该循环更改为:
for (auto item1 : container )
{
for (auto item2 = item1.next(); item2 != container.end(); ++item2)
{
// Do stuff, not changing the container
}
}
由于内部循环不会迭代整个容器,因此必须使用normal for循环。