用語というのは分野が違えば違う意味をもつことがある。 情報分野の場合、プログラミング言語ごとで異なることもしばしばだ。 もちろんそれぞれ違う理念で設計されているプログラミング言語であるから、似て非なる概念もあるだろう。 微妙に違うものに同じ用語を当て嵌めるのは混乱のもとであるし、ほとんど同じなのに別の名前が付いているというのも理解の妨げになるかもしれない。 どっちもどっちでもどかしいことだ。
そんなことを思ったのは、 Ruby の外部イテレータは他の言語でジェネレータと呼ばれる (こともある) ものに似ていると思ったからだ。 どちらの用語が正しいというわけではない。 この機能が「繰返すもの」なのか「生成するもの」なのかは多分に感覚的なものでしかない。 あらためて利用例を探してみると、ジェネレータという名前の言語機能でコンテナを走査する (イテレータ的に使う) ような場面もあれば、その逆も見られるので、一方がもう一方の特殊な場合というよりは同じものの別側面なのだろう。
そんなことを考えていたとき、階乗を計算するプログラムについての記事が Qiita に投稿されたのを見た。
これは明らかに std::accumulate を使えるパターンだ。 自然数がイテレータとしてのインターフェイスを持てばよいと考えてこんなコードを書いた。
#include <iostream> #include <numeric> #include <functional> template<class T> class elem { private: T raw; public: elem(T x) : raw(x) {} elem& operator++(void){ raw++; return *this; } T operator*(void) const { return raw; } bool operator!=(elem& x) const { return x.raw != raw; }; }; class natural_numbers { private: const int end_num; public: typedef elem<int> iterator; natural_numbers(const int x=0); iterator begin(void) const; iterator end(void) const; }; natural_numbers::natural_numbers(const int x) : end_num(x) {} natural_numbers::iterator natural_numbers::begin(void) const { return elem<int>(1); } natural_numbers::iterator natural_numbers::end(void) const { return elem<int>(end_num); } int factorial(int k) { natural_numbers nn(k+1); return std::accumulate(nn.begin(), nn.end(), 1, std::multiplies<int>()); } int main(void) { int number; std::cout << "何の階乗を計算しますか?" << std::endl; std::cin >> number; std::cout << factorial(number) << std::endl; }
私は C++ のイテレータはコンテナのインターフェイスという風にしか認識していなかったので、ジェネレータ的に使えるというのは新しい発見であった。
と思ったのだけど、 boost.range には counting_range という、まさにこういう場面に使えるものがあるという指摘をもらった。
http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/range/reference/ranges/counting_range.html
まあ私ごときが考えることは闇の軍団の人々が考えてないはずがないか。
Document ID: 19320ed0deaed1687c26043ca010280c