C言語でforeachを書いてみた
Boost.Foreachを参考にした。
Boost.Foreachと違ってbeginとendはループの度に評価されるので、副作用を入れこまないように注意
#define FOREACH_C89( var, begin, end ) \ for( var = (begin); var<(end); var++ ) #define FOREACH_C99( var, begin, end ) \ for( size_t _foreach_i=0,_continue=1; _continue && (((begin) +_foreach_i)< (end)); _continue ? _foreach_i++ : 0 ) \ for(int _foreach_j = (_continue=0); !_foreach_j; _foreach_j=1 ) \ for( var = (begin) + _foreach_i; !_continue; _continue=1 ) #define FOREACH( var, begin, end ) FOREACH_C99( var, begin, end )
C++と違ってCではifを使った局所変数宣言ができないので、ダミーのfor文で代用している。
C89とC99の違いは、for文中で変数宣言ができるか否か
void test_foreach{ // C89版は値を受ける変数を事前に宣言しておく必要がある。 int i; FOREACH_C89( i, 0, 12 ){ printf("c89:\d\n", i ); } // C99版はその必要なし FOREACH_C99( int j, 0, 12 ){ printf("c99:\d\n", j ); } }
配列(ポインタ)の繰り返しもできる
#define SIZEOF_ARRAY(ary) (sizeof(ary)/sizeof(ary[0])) #define ARRAY_END(ary) (ary + (SIZEOF_ARRAY(ary))) void test_foreach(){ short s_array[] = {1,2,3,4,5,6,7,8}; FOREACH( short *n, s_array, ARRAY_END(s_array) ){ printf("val: %d\n",*n ); } }
おまけ
#define FOREACH_ARRAY( var, ary ) FOREACH( var, ary, ARRAY_END(ary) ) #define TIMES( count, var ) FOREACH(var, 0, count ) #define RANGE(type) struct { type begin; type end; } #define FOREACH_RANGE( var, range ) FOREACH( var, range.begin, range.end ) void test_foreach(){ int array[] = { 2,4,5,6,12,7 }; FOREACH_ARRAY( int *n, array ){ printf( "%d\n", *n ); } TIMES( 5, int n ){ printf("times:%d\n", n ); } RANGE(int) rng = {0,12}; FOREACH_RANGE(int n, rng ){ printf("range :%d\n", n ); }