让iterable
成为Iterable
类型。
然后,为了使
for (Type x : iterable)
在编译时,必须存在名为Type
和IType
的类型,并且必须存在相应的函数。
IType Iterable::begin()
IType Iterable::end()
IType
必须提供以下函数:
Type operator*()
void operator++()
bool operator!=(IType)
整个结构实际上是复杂的语法糖,用于类似以下代码的表达:
for (IType it = iterable.begin(); it != iterable.end(); ++it) {
Type x = *it;
...
}
在此处,任何兼容类型(如const Type
或Type&
)都可以用来代替Type
,这将产生预期的影响(如constness、引用而非复制等)。
由于整个扩展是语法上的,因此您还可以稍微更改运算符的声明,例如使*it返回一个引用或者根据需要使用const IType& rhs
作为!=的参数。
请注意,如果*it
不返回引用,则无法使用for (Type& x : iterable)
形式(但如果它返回引用,则也可以使用复制版本)。
还要注意,operator++()
定义了前缀版本的++
运算符--但是除非您明确定义后缀++
,否则它也将用作后缀运算符。如果只提供后缀++
,则范围循环将无法编译,其中btw。可以将其声明为operator++(int)
(虚拟int参数)。
最小工作示例:
#include <stdio.h>
typedef int Type;
struct IType {
Type* p;
IType(Type* p) : p(p) {}
bool operator!=(IType rhs) {return p != rhs.p;}
Type& operator*() {return *p;}
void operator++() {++p;}
};
const int SIZE = 10;
struct Iterable {
Type data[SIZE];
IType begin() {return IType(data); }
IType end() {return IType(data + SIZE);}
};
Iterable iterable;
int main() {
int i = 0;
for (Type& x : iterable) {
x = i++;
}
for (Type x : iterable) {
printf("%d", x);
}
}
输出
0123456789
您可以使用以下宏来模拟范围for循环(例如对于旧的C++编译器):
#define ln(l, x) x##l
#define l(x,y) ln(x,y)
#define for_each(T,x,iterable) for (bool _run = true;_run;_run = false) for (auto it = iterable.begin(); it != iterable.end(); ++it)\
if (1) {\
_run = true; goto l(__LINE__,body); l(__LINE__,cont): _run = true; continue; l(__LINE__,finish): break;\
} else\
while (1) \
if (1) {\
if (!_run) goto l(__LINE__,cont); \
goto l(__LINE__,finish);\
} \
else\
l(__LINE__,body): for (T x = *it;_run;_run=false)
int main() {
int i = 0;
for_each(Type&, x, iterable) {
i++;
if (i > 5) break;
x = i;
}
for_each(Type, x, iterable) {
printf("%d", x);
}
while (1);
}
如果您的编译器甚至没有auto,请使用declspec或传递IType。
输出:
1234500000
正如您所看到的,由于其复杂的结构,continue
和break
可以与此一起使用。请访问http://www.chiark.greenend.org.uk/~sgtatham/mp/了解更多关于C预处理器的黑客技巧,以创建自定义控制结构。
begin()
和一个end()
成员函数以及一个迭代器类型,这样就可以使它与 foreach 兼容。 - yngccc