ことの発端
最近、 paiza で求人をしているのですが、C++ の回答で rep
というマクロを多用するコードを見かける。
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
で、よくよく調べてみると AtCorder のサイトで公開されているコードということが分かった。
AtCorder は競プロの世界なので、コーディングの速度だったり、実行速度だったりが目的なので、これはこれでアリかと思う。
ただ、個人的には次の理由でマクロは採用できないかなぁ。
- 型チェックが行われない
- デバッガでステップ実行時に、行ズレが発生するケースがある
- 過去の経験ですっげ~痛い目にあっている(苦笑)
そうは言っても、効率化という大義のためにマクロが登場することがある(5~10年に1回くらい)けど、局所的に、且つ背徳感に苛まれながらマクロを書いてます。
まぁ、正解・不正解がある話じゃないし、マクロの善悪の話じゃなくて、今回はこいつを型安全な関数にできんのかと書いてみたという話です。(処理速度は落ちるであろうことは予測できますが、私は型安全にしたんだ!)
んで、書いてみようと思ったきっかけは、STL
の algorithm
における反復処理は iterator
が登場することが多いので、今回の rep
マクロ的なの無かったんじゃないかというのが動機です。 1
書いてみた
#include <iostream>
#include <functional>
void rep(int n, std::function<void(int)> fn){
for(int i = 0; i < n; i++) fn(i);
}
int main(void){
rep(5, [](int i){
std::cout << i << std::endl;
});
}
そのまま書くとこんな感じかな。。。
あ!!でも
-
break
ができない - 型をちゃんと渡したい
とか考えて。。。
#include <iostream>
#include <functional>
template <typename T> bool rep(
T start, /* 初期値 */
std::size_t count, /* 回数 */
std::function<bool(T)> fn, /* false を返却したら break */
std::function<T(T)> stepper = [](T value) {return value + 1;} /* デフォルトは +1 */
){
T& value = start; /* rename */
for(std::size_t i = 0; i < count; i++){
if(!fn(value)) return false;
value = stepper(value);
}
return true;
}
int main(void){
rep<int>(1, 10, [](auto value){
std::cout << value << std::endl;
return true;
});
rep<std::string>("abc", 10, [](auto value){
std::cout << value << std::endl;
return true;
}, [](auto value){return value + "z";});
}
型推論が効かないのが残念ポイントですが、数値だけじゃなくて文字列も渡せるようになった~
。。。けど、そんなことやるのか? やらないな。
それに、「もう、もはや for
文で良くね?」という感じになったけど、 この関数は break
した情報を伝搬する仕様にしたことで、多重ループ時の脱出が楽になった気がする。
int main(void){
rep<int>(1, 10, [](auto value){
return rep<int>(value, 10, [](auto value){
std::cout << value << std::endl;
if(value == 14) return false; /* 14 が登場したらループ終了 */
return true;
});
});
}
多重ループって、抜けるのが結構面倒だったりするんだけど、これならすんなり抜けられるな。
これはこれで収穫じゃ~
それに、 for
文で範囲指定じゃなくて回数指定というのも地味面倒だったりするので、作ってみたら案外アリかも。
もうちょい煮詰めれば使い物になるかも知れない。
-
探せば
stl
とかboost
であるかもだけど、こいういうパーツ作るのを楽しむタイプなので、暫くは探さないことにしよう。メモリ確保しないrange
的なのがありそう。 ↩