快適なrangeマクロ

僕は普段c++を使って競技プログラミングをしているのですが、その中でrepマクロを使う機会が多くあります。ふと、pythonのrangeのように引数によってその効果が変わるようなrepマクロに近い何かが欲しいなと思ったので記事を参考に作ってみました

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define range(...) GET_MACRO(__VA_ARGS__, range4, range3, range2)(__VA_ARGS__)
#define range2(i, r) for ( int i = 0; i < (int)(r); (i) += 1)
#define range3(i, l, r) for ( int i = (int)(l); i < (int)(r); (i) += 1)
#define range4(i, l, r, inc) for ( int i = (int)(l); i < (int)(r); (i) += (inc))
#define rrange(...) GET_MACRO(__VA_ARGS__, rrange4, rrange3, rrange2)(__VA_ARGS__)
#define rrange2(i, r) for ( int i = (int)(r) - 1; i >= 0; (i) -= 1)
#define rrange3(i, l, r) for ( int i = (int)(r) - 1; i >= (int)(l); (i) -= 1)
#define rrange4(i, l, r, inc) for ( int i = (int)(r) - 1; i >= (int)(l); (i) -= inc)
#include <iostream>
using namespace std;

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define range(...) GET_MACRO(__VA_ARGS__, range4, range3, range2)(__VA_ARGS__)
#define range2(i, r) for ( int i = 0; i < (int)(r); (i) += 1)
#define range3(i, l, r) for ( int i = (int)(l); i < (int)(r); (i) += 1)
#define range4(i, l, r, inc) for ( int i = (int)(l); i < (int)(r); (i) += (inc))
#define rrange(...) GET_MACRO(__VA_ARGS__, rrange4, rrange3, rrange2)(__VA_ARGS__)
#define rrange2(i, r) for ( int i = (int)(r) - 1; i >= 0; (i) -= 1)
#define rrange3(i, l, r) for ( int i = (int)(r) - 1; i >= (int)(l); (i) -= 1)
#define rrange4(i, l, r, inc) for ( int i = (int)(r) - 1; i >= (int)(l); (i) -= inc)

int main() {
  int l, r, inc;
  cin >> l >> r >> inc;
  range(i, r) {
    cout << i << ' ';
  }
  cout << endl;

  range(i, l, r) {
    cout << i << ' ';
  }
  cout << endl;

  range(i, l, r, inc) {
    cout << i << ' ';
  }
  cout << endl;

  rrange(i, r) {
    cout << i << ' ';
  }
  cout << endl;

  rrange(i, l, r) {
    cout << i << ' ';
  }
  cout << endl;

  rrange(i, l, r, inc) {
    cout << i << ' ';
  }
  cout << endl;
}

これを試しに10 20 2(10以上20未満を2ずつ)で実行すると以下のようになります

10 20 2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
10 11 12 13 14 15 16 17 18 19 
10 12 14 16 18 
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 
19 18 17 16 15 14 13 12 11 10 
19 17 15 13 11

[l, r)の半開区間なのでこれで正しいと思います 満足がいく結果となりました

仕組みとしては、引数の数をGET_MACROでrange{引数の個数}を呼び出しているような感じだと思っています(よくわかっていない)

参考

stackoverflow.com