C++11/14でrange based forで指定回数Loopする

for (int i = 0; i < 10; i++) { ... }

って何度も書くのがだるいので、range based forを使って楽にしたい。要するに、

for (auto i : 10_) { ... }

で10回ループできるようにしたいね、という話。他の変数の回数分ループするなら

int x = 3;
for (auto i : Loop(x)) { ... }

などとする。


なお、ループ変数を途中で書き換えたいという不届きな向きには

for (auto& i : 10_) { ...; i += 2; }

などとすれば良い。auto&&でも良い。


なおあまり複雑なオブジェクトをrangeに渡してしまうと最適化が効きにくくなるという弊害が出てしまうので、最初の表現とほぼ等価に展開されるようなものを渡したい。どうやって実現するかというと、range based for

for ( range_declaration : range_expression ) loop_statement

において、range_expression が begin(), end()メソッドを持つ場合は

{
  auto && __range = range_expression;
  for (auto __begin = range_expression.begin(), __end = range_expression.end(); __begin != __end; ++__begin) {
    range_declaration = *__begin;
    loop_statement
  }
}

と等価ということになっている。まずカウンタが取れるように、operator*がループ変数の参照を返すようにすれば良いだろう。終了判定は __begin != __end の部分なので、operator!=を適当に書き換えてやればよさそうである。あとoperator++(&)でインクリメント。


というわけでこんな感じになった。Apple clang-703.0.31(-std=c++14)とg++5.1(-std=c++14)で確認。
clangの方で確認した限り、一応STLを使ったりしても、-O2あたりの結果をディスアセンブルしてみると普通にfor loopを書いた時と同等の最適化がされるようである(もっと複雑な場合だと変わってくるのかもしれないが未確認)。


http://ideone.com/n9zYGV

template <typename T>
class LoopTemplate {
	T max, cnt;
public:
	LoopTemplate(T max) : max(max), cnt(0) {}
	LoopTemplate(T min, T max) : max(max), cnt(min) {}
	LoopTemplate& begin() {
		return *this;
	}
	LoopTemplate& operator++() {
		cnt++;
		return *this;
	}
	T& operator*() {
		return cnt;
	}
	bool operator!=(LoopTemplate&) {
		return cnt < max;
	}
	LoopTemplate& end() {
		return *this;
	}
};
typedef LoopTemplate<long> Loop;
LoopTemplate<unsigned long long> operator "" _(unsigned long long n)
{
	return LoopTemplate<unsigned long long>(n);
}


/* Exapmle usage */
#include <iostream>

void f(unsigned long long i)
{
	std::cout << i << std::endl;
}

int main()
{
	for (auto i : 10_) {
		f(i);
	}

	int x  = 3;
	for (auto&& i : Loop(x)) {
		f(i);
	}

	return 0;
}