5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

競技プログラミングで頻繁に使用されるrepマクロの問題点と解決案

Last updated at Posted at 2022-04-26

そもそもrepマクロとは

競技プログラミングで入力文字数を減らすためにしばしば使われる、以下のようなマクロである。

#define REP(i, n)    for (int i = 0; i < (n); i++)

repマクロのなにが問題か

そもそもC++ではマクロの使用自体が推奨されていない

現行のC++においてマクロは本当に必要でない限り利用すべきでない機能とされており、他の記法を使用できる限りそちらを使用するべきである。

C/C++のマクロの変換処理は構文を考慮しない

C/C++のマクロは、単に引数をテキスト置換した上で実コードに変換される。

重要な点として、マクロの変換処理はスコープを一切考慮しないため、例えばnamespaceなどのステートメントで適用範囲を束縛することが出来ない。

本来C/C++のfor文は宣言からループ処理の記述を含めて一つのステートメントとされているが、構文規則を無視することで宣言部分のみを無理やり分割して変換しているため、注意しないと構文の整合性を損なう恐れがある。
引数nをカッコで括っているのはこれを防ぐためである。

意地悪な例としては以下のようなものがある。

void solve() {
 	int a = 8;
 
   	REP(i = a, 3)
   		std::cout << i << std::endl;
 
    std::cout << "Out: " << a << std::endl;
}

この関数の実行結果は以下のようになる。

1
1
1
Out: 3

この関数のループカウンタは正しく動作せず、変数aは代入されているはずの8ではなく、3を返す。
マクロが以下のように変換されるからである。

for (int i = a = 0; i = a < (3); i = a++)   // aの値が変更されている!

このfor文はループカウンタ変数iの代わりに変数aをインクリメントし、条件式を含む全ての式を実行するごとに、ループカウンタに値を代入してしまう。1

代わりになりそうな方法

boost::irangeを使う

Boost Libraryの中にirangeというループを処理するためのクラスがある。

for (int i : boost::irange(0, n)) {
    // 0からn-1までのループ
}

第一引数に0以外を指定すれば0以外で始まるループも指定可能。

C++のラムダ式を使う

template<typename F> constexpr void rep(int n, F function) {
    for (int i = 0; i < n; i++)
        function(i);
}

以下のように書けるようになる。

rep(n, [&](int i) {
    // do something
});

std::for_eachとほとんど同じように使えるので、タイプ数を減らすなら多分この方法が一番実用的。

クローリング中に見つけたのですが…

良記事です。ループの途中抜けに対応していたりと色々すごい。

番外編:while (n--)

古い環境でミリ秒単位の高速化をするために、C時代から使われていたループ。
元の変数そのものをループカウンタとして使用するため、値が変わってしまうのがネック。
当然ながら、値がマイナスだった場合は(実質的に)無限ループしてしまう。

while (n--) {
    // do something
}

確かにタイプ量は少ないが…

最後に

多分そろそろRustに乗り換えたほうがいいです。

参考文献

  • プログラミング言語C++ 第4版 - Bjarne Stroustrup, 柴田望洋, SBクリエイティブ
  1. iにカッコをつければ抑制できるが、GCCの場合、カッコが必要ないケースでwarningが出る。int{i}と書けばwarningを抑制できます。

5
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?