特殊なイテレータを使おう

#はじめに
みなさんこんにちは。

通常イテレータといえば、まず思いつくのはコンテナの要素を順々にたぐるアレだと思いますが、STLにはそうでないイテレータもあります。それはイテレータによってアルゴリズムを汎用的に書けるようになったことで可能になった応用的なイテレータですが、非常に有用な反面とっつきにくいイメージがあります。そこで、この記事ではSTLに存在する特殊なイテレータをSTLに存在する通常のアルゴリズムを使って紹介していきたいと思います。

#reference:
http://en.cppreference.com/w/cpp/iterator
http://en.cppreference.com/w/cpp/algorithm

#通常のイテレータ
イテレータがゲシュタルト崩壊したときに見てください。

``` cpp
std::vector< int > vec { 1, 2, 3, 4, 5 };
typename std::vector< int >::iterator itr = begin(vec);

// output
*itr = 5; // assign value

++itr; // points to the next element.

// input
int n = *itr; // 2
```

#ostream_iterator, ostreambuf_iterator
*category: outputiterator*

ostream_iteratorは出力ストリームの現在位置を指すイテレータです。イテレータに値を設定することはストリームに値を流すことと同義と言えます。また、出力演算子が定義されている型であれば何でも扱うことができます。
streambuf_iteratorはストリームに関連付けられたバッファを指すイテレータです。ストリームイテレータと違い、バッファに直接値を突っ込むため効率はいいですが、当然ながらバッファと同じ型しか与えることができません。

``` cpp
std::ostream_iterator< int > itr(std::cout);
*itr = 123; // std::cout << 123;
++itr; // nop

std::vector< int > vec{4, 5, 6};
std::copy(begin(vec), end(vec), itr); // outputs 456

std::ostreambuf_iterator< char > bufitr(std::cout.rdbuf()); // typeof the cout's buffer is char.
*bufitr = 'h'; // std::cout.rdbuf()->sputc('h');
std::string str = "ello world";
std::copy(begin(str), end(str), bufitr); // outputs ello world
```

http://ideone.com/Jk27Qn

#istream_iterator, istreambuf_iterator
*category: inputiterator*

入力ストリームの現在位置を指すイテレータです。イテレータから値を読み出すことはストリームから値を読むことと同義です。また、イテレータを進めることはストリームの現在位置を進めることと同義です。
コンストラクタに何も与えないと、終端を意味するイテレータを作成できます。

``` cpp
std::istringstream iss("1 2 3 4 5 6");
std::istream_iterator< int > itr(iss);
int n = *itr; // 1
std::cout << n << std::endl; // outputs 1
++itr; // points to the next element

int m = std::accumulate(itr, {}, 0); // 0 + 2 + 3 + 4 + 5+ 6
std::cout << m << std::endl; // outputs 20

std::istream_iterator< int > itr2(iss); // points end
int l = std::accumulate(itr2, {}, 0); // 0
std::cout << l << std::endl; // outputs 0
```

http://ideone.com/OqcKEv

#reverse_iterator
言わずと知れたリバースイテレータなので説明不要かと思います。
C++14からはヘルパ関数を使うことができます。
[make_reverse_iterator(C++14)](http://en.cppreference.com/w/cpp/iterator/reverse_iterator)

#move_iterator
*category: depends on the argument*

読み取り専用のイテレータです。このイテレータから読み込まれる値はムーブされて渡されます。
ヘルパ関数の[make_move_iterator](http://en.cppreference.com/w/cpp/iterator/make_move_iterator)が用意されています。
異なるコンテナ間で内容をムーブするのに便利ですね。

``` cpp
std::vector< std::string > vec {"hello", "beautiful", "world"};

std::list< std::string > list(
    std::make_move_iterator(begin(vec)),
    std::make_move_iterator(end(vec)));
 
// output nothing
std::copy(begin(vec), end(vec),
    std::ostream_iterator< std::string >(std::cout, " "));
 
// outputs hello beautiful world 
std::copy(begin(list), end(list),
    std::ostream_iterator< std::string >(std::cout, " "));
```

#back_insert_iterator
*category: outputiterator*

通常であればoutputiteratorが必要とされるところでも、出力先のコンテナには予め領域が確保されてなければなりません。容量が足りずに出力先のコンテナのend()の指す場所に突入した時点でバッファオーバーフローが起こってしまうからです。

``` cpp
std::vector< int > vec1 {1, 2, 3};
std::vector< int > vec2;
// vec2.resize(vec1.size());
std::copy(begin(vec1), end(vec1), begin(vec2)); // oops!
```

このイテレータは割り当てられた値をpush_backで追加してくれるので、そのような心配はありません。
ただし、コンテナがpush_back関数を持っている必要があります。
また、便利なヘルパ関数[back_inserter](http://en.cppreference.com/w/cpp/iterator/back_inserter)を使うことができます。

``` cpp
std::vector< int > vec1 {1, 2, 3, 4, 5};
std::vector< int > vec2;

std::copy(begin(vec1), end(vec1), std::back_inserter(vec2));
// outputs 12345
std::copy(begin(vec2), end(vec2), std::ostream_iterator< int >(std::cout));
```

#front_insert_iterator
*category: outputiterator*

back_insert_iteratorと基本的に同じものですが、back_insert_iteratorがpush_backで要素を追加するのに対して、push_frontを使って要素を追加してくれます。よって、コンテナはpush_frontを持っている必要があります。
back_insert_iterator同様にヘルパ関数が用意されています。[front_inserter](http://en.cppreference.com/w/cpp/iterator/front_inserter)

``` cpp
std::list < int > list1 {1, 2, 3, 4, 5};
std::list < int > list2;

std::copy(begin(list1), end(list1), std::front_inserter(list2));
// outputs 54321
std::copy(begin(list2), end(list2), std::ostream_iterator< int >(std::cout));
```

#insert_iterator
*category: outputiterator*

お察しの通り、insertを使って要素を追加してくれるイテレータです。やはりお察しの通り、コンテナはinsertを持っている必要があります。
ヘルパ関数は[inserter](http://en.cppreference.com/w/cpp/iterator/inserter)を使うことができます。

``` cpp
std::list < int > list1 {3, 4, 5, 6};
std::list < int > list2 {1, 2, 7, 8};

auto itr = begin(list2);
std::advance(itr, 2);
std::copy(begin(list1), end(list1), std::inserter(list2, itr));
// outputs 12345678
std::copy(begin(list2), end(list2), std::ostream_iterator< int >(std::cout));
```


#おわりに
いかがだったでしょうか。紹介したのは嫌われやすいイテレータたちですが、アルゴリズムヘッダに入っているアルゴリズムをフル活用できるようになるのでぜひ使ってあげてくださいね。
また使用する際は、カテゴリに注意してください。彼らは基本的に（カテゴリとして）低機能なイテレータですから、自分より高機能なイテレータを求めているアルゴリズムに突っ込むことはできません。

間違いなど気付いた点がございましたらコメントの方へよろしくお願いします。