今まだ,私の時間感覚では5/17なのですが,先走って18日の日記を書きます.長くなるので17日の分と分けたほうが良いだろうと思われるからです.
前から思っていたこととして,数値関数を模倣するiteratorがあればなぁ,というのがありました.ここで数値関数とは,0以上の整数に対して何らかの値が対応付けられている関数のことです.例えば,0, 1, 2, 3...に対して偶数列0, 2, 4, 6...が対応する関数なんかが挙げられます.
で,これを模倣するiteratorとはつまり次のような機能を持つ入力反復子です.
numeric_function_iterator it; cout << *it << endl; // *itは0を返す ++it; cout << *it << endl; // *itは2を返す ++it; cout << *it << endl; // *itは4を返す ...
こういうiteratorの実装は,ある程度のレベルのC++プログラマなら容易に想像できるかと思われます.そして,こういうiteratorの実装の内部では,整数を引数に取ってそれに対応した値を返すファンクタを持たせるようにし,このiteratorの利用者がファンクタを指定するような実装が自然になるかと思われます.
で,こういうiteratorを自分で実装しようかと思っていたのですが,boostのiterator_adaptorライブラリを見ていて気が変わりました.理由は「iterator_adaptorを利用して簡単(かつ高機能)に作成できるじゃん」と思ったからです.
改めて,日々自分が感じている教訓「自分が欲しいと思った機能は,大抵ライブラリで実装されているものだ」を痛感します.
閑話休題.
上のようなiteratorを作成するに当たって,boostから2つのiterator_adaptorを使います.一つはcounting_iteratorで,もう一つはtransform_iteratorです.counting_iteratorの方は,数値関数の引数の値(0, 1, 2, 3...)を生成するために用います.transform_iteratorの方は,counting_iteratorに噛ませて,counting_iteratorが生成する整数列を変換する数値関数を表現します.
例示コードを以下に書きます.
#include#include #include #include #include using namespace std; using namespace boost; int main(int argc, char *argv[]) { copy( make_transform_iterator( make_counting_iterator (0), bind2nd(multiplies (), 2)), make_transform_iterator( make_counting_iterator (20), bind2nd(multiplies (), 2)), ostream_iterator (cout, "\n")); return 0; }
以上ですw.
ファンクタを自分で定義してmake_transform_iteratorに渡せば,どんな数値関数でも(返り値がstringの関数でも!)iteratorで表現できてしまいます.