C++ STL algorithm 書いて覚えるための初心者自己中記事
標準ヘッダファイルのことについて全然知らないので、勉強していく。
テキストの終わりに標準テンプレートライブラリ(STL)の一覧があったから上から見ていく。
algorithm 各種アルゴリズム
どう使うのかさっぱり。
algorithm はあれか、要素に対して何かしらちょっかいが出せる関数の集まりなのか。
アルゴリズムライブラリは、要素の範囲に対して作用するさまざまな目的の (例: 検索、ソート、計数、操作) 関数を定義しています。ひとつの範囲は [first, last)
のように定義され、last
は参照したり変更したりする最後の要素の次の要素を指します。
なるほど。
じゃあ、何でもいいから配列を作ってalgorithmの関数を使ってみればいいのかな?
というかその前に、イテレータってのは何かあれだったような、コンテナなら全員持ってるのか?種類もあったような。
その辺があいまいだからそこからやったほうがいい気がしてきた。
イテレータの種類は以前テキストで習った。
あ、リファレンスのサイト見ると乗ってるのか。
難しな。
ダメだ、情報が多すぎて把握できない。
こんな時は少しずつだな。
とりあえず、vector クラステンプレートで配列を作って、それをalgorithm の関数で操作してみて様子を見よう。
vector単体でもいろいろ出来るけど、それ以上に出来るということかな。
おー、レファレンスのコンストラクタとか見るといろんな引数で作れるとか分かるのか。
ちょいちょい出てくるAIlocatorってなんだ?
STLコンテナがメモリ確保するときには皆Allcator を使っているのか。
Allocator がメモリの確保と解放の役割を一手に担っていると。
なるほど、デフォルト引数になってるけど、自分で用意して引数に渡すこともできるのか。うん、まだ早すぎるな。
vectorのコンストラクタを見ているんだった。
あー、見てたらきりがないな。
今やりたいことは細かい部分じゃなくて全体的な使い方。
std::vector<int> vintA = { 0,1,2,3,4,5,6,7,8,9, };
とりあえず、vectorで配列作った。
で、algorithmの関数でfor_eachってのが面白そう。
指定した範囲内に別の関数を適用できる。で、あってるのかな?
for_each関数の第一第二引数はInputIteratorって書いてある。
ここにさっき作ったvintA のイテレータを渡せばいんだな。
あ、そういうことか、ここでvectorのイテレータはランダムアクセスイテレータだからこの関数は使用できるということか。
typedef std::vector<int>::iterator Iterator; std::vector<int> vintA = { 0,1,2,3,4,5,6,7,8,9, }; Iterator f = vintA.begin(); Iterator e = vintA.end(); std::for_each(f,e,);
関数はどうしよう。
戻り値とか引数とかどうなってるんだ?
template<class InputIt, class UnaryFunction> UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f) { for (; first != last; ++first) { f(*first); } return f; }
これみると、関数の引数には配列の中身をイテレータの*で渡してるから、関数で配列の中身を書き換えることが出来るのか。
戻り値が関数の戻り値をそのまま使ってるけど、配列分繰り返される関数の戻り値の型ってどうなってるんだ・・・?
まずは中身を書き換えてみよう。
ん、第三引数に指定する関数の入れ方がわからないぞ。
void twice(int& n) { n *= n; } int main() { typedef std::vector<int>::iterator Iterator; std::vector<int> vintA = { 0,1,2,3,4,5,6,7,8,9, }; Iterator f = vintA.begin(); Iterator e = vintA.end(); std::for_each(f,e,twice);
カッコはいらないのか。関数名だけでよかった。
count
count_if
bool Under(int& n) { return 5 > n; } int main() { typedef std::vector<int>::iterator Iterator; std::vector<int> vintA = { 0,1,2,3,4,5,6,7,8,9, }; Iterator f = vintA.begin(); Iterator e = vintA.end(); std::cout << count(f, e, 5) << std::endl; std::cout << count_if(f, e, Under) << std::endl;
count_ifはbool返す関数でtrue の数を数えるのか。
関数を引数にするときに別で引数渡したいときはどうするのかな。
struct test { test(int i):i(i){} bool operator()(int& n) { return i > n; } int i; };
std::cout << count_if(f, e, test(7)) << std::endl;
なるほど。演算子オーバーロードを使って構造体を一つの関数のようにしてしまうのか。
関数を引数にとるalgorithm関数内部で
p(*first)
この状態になるから出来るのか。
count_ifに指定するときはコンストラクタとして()が使われて、
count_if内部の処理の時は()がオーバーロードされた状態のやつってのが。
初期化されるまではオーバーロードも有効にならないということなのだろうか。うん、そうだな。きっと。
STL algorithmがどういうものかが少しわかった気がする。
ここまで。