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;
...
}
の代わりにType
、互換性のある任意の型 (const Type
または などType&
) を使用できます。これには、期待される意味 (constness、コピーではなく参照など) があります。
全体の展開は構文的に行われるため、演算子の宣言を少し変更することもできます。たとえば、 *it が参照を返すようにしたりconst IType& rhs
、必要に応じて != を取得したりすることができます。
for (Type& x : iterable)
が参照を返さない場合はフォームを使用できないことに注意してください*it
(ただし、参照を返す場合は、コピー バージョンを使用することもできます)。
また、 は演算子の前置バージョンをoperator++()
定義することに注意してください。ただし、明示的に後置を定義しない限り、後置演算子としても使用されます。範囲指定された for は、 postfix のみを指定するとコンパイルされません。これは btw.can として宣言できます(ダミーの int 引数)。++
++
++
operator++(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
次のマクロを使用して、ranged-for-each (たとえば、古い C++ コンパイラ用) を偽造できます。
#define ln(l, x) x##l // creates unique labels
#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);/* we reach here if the block terminated normally/via continue */ \
goto l(__LINE__,finish);/* we reach here if the block terminated by break */\
} \
else\
l(__LINE__,body): for (T x = *it;_run;_run=false) /* block following the expanded macro */
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
。カスタム制御構造を作成するための C プリプロセッサのハッキングについては、 http://www.chiark.greenend.org.uk/~sgtatham/mp/break
を参照してください。