rep マクロ

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

例えば rep(i, k & 1) とすると for (int i = 0; (i < k) & 1; ++i) と等価であるため、意図しない動作を引き起こします: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

これを避けるには #define rep(i, n) for (int i = 0; i < (n); ++i) とすればよいです: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

#define rep(i, l, r) for (int i = (l); i < (r); ++i)

$l$ や $r$ は 32 bit 整数で表せないほど大きな整数かもしれません。

#define rep(i, l, r) for (long long i = (l); i < (r); ++i)

$l$ や $r$ は 64 bit 整数で表せないほど大きな整数かもしれません。

#define rep(i, l, r) for (__int128_t i = (l); i < (r); ++i)

速度的にあまり嬉しくなさそう。

#define rep(i, l, r) for (decltype(r) i = (l); i < (r); ++i)

r は参照型かもしれません: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

#define rep(i, l, r) for (std::remove_reference_t<decltype(r)> i = (l); i < (r); ++i)

rconst 修飾されているかもしれません: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

#define rep(i, l, r) for (std::decay_t<decltype(r)> i = (l); i < (r); ++i)

std::decay_t<decltype(r)>l を表現できない場合にバグります: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

こうすると signedness さえ一致していれば正しく動く: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

signedness が一致していない場合は unsigned の方が選ばれるので、rep(i, -1, 3U) などとするとバグる: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

signedness が一致しない場合にコンパイルエラーを吐かせることもできる: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

追記

上記実装で壊れるケースを頂きました:

r の計算が比較のたびに走って計算量が悪化することがあります。

#define rep(i, l, r) for (rep_int_t<std::decay_t<decltype(l)>, std::decay_t<decltype(r)>> i = (l), end_i = (r); i < end_i; ++i)

r を先に評価することで回避できる: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

ただし、end_i という変数が既に外側で使われていた場合に変数の shadowing が起こる: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

対処として考えられそうなのは次の 2 種類。

  1. 衝突しなさそうな変数名を使う
  2. rep 用の構造体を作る

例えば 2 であれば次のように実装できる: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

この場合、ループ中に i を変更したときの挙動が今までとは異なることに注意する: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

この挙動の違いは非自明なので、iconst で宣言してあげるのがよさそう: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

構造体にする利点

次のように同じ rep マクロで引数の個数によって挙動を使い分けたいとする。

  • rep(i, n) : $i = 0, 1, \ldots, n - 1$ の順に走査
  • rep(i, l, r) : $i = l, l +1, \ldots, r - 1$ の順に走査

c - Overloading Macro on Number of Arguments - Stack Overflow のような方法もあるが、構造体であればコンストラクタを増やして次のように簡単に書ける: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

一番初めに挙げた優先順位の問題は起こらないはず (多分...)

コードがかなり長くなってしまうのが嫌なら l, r の型の一致を強制することで短くできて、次のようになる: [C++] gcc HEAD 14.0.0 20230712 (experimental) - Wandbox

まとめ

この記事の結論としては次の 2 つをおすすめする。