c++のstlの基本:c++をもっと楽に書くために @ ふわっふわ勉強会(2015.3.14)

54
ふわっふわ勉強会(2015.3.14) C++のSTLの基本: C++をもっと 楽に書くために H.Hiro Twitter: @h_hiro_ http://hhiro.net/about/

Upload: hiro-h

Post on 18-Jul-2015

394 views

Category:

Technology


0 download

TRANSCRIPT

ふわっふわ勉強会(2015.3.14)

C++のSTLの基本:C++をもっと

楽に書くために

H.HiroTwitter: @h_hiro_

http://hhiro.net/about/

自己紹介

H.Hiro●情報系の研究員やってます(アルゴリズムを作ったりするのが仕事です)●趣味でもプログラム書いてます●4月から名古屋に引っ越します(別の仕事が決まりました)

よろしくお願いします

今回話す内容

C++のSTL

STL(StandardTemplateLibrary)

想定する聴講者層

●STL使い始めたばかり●C++は書いてはいるがBetter Cとしてしか使えてない●C++はそこまで慣れてないけど他にある程度使い込んでるプログラム言語がある

●STL使い始めたばかり●C++は書いてはいるがBetter Cとしてしか使えてない●C++はそこまで慣れてないけど他にある程度使い込んでるプログラム言語がある

もっと楽に書くための一助に!

C++の記法って面倒?そんなことないよ

std::max_elementとかstd::sortとか使ってる?

さて、今回は

STLの形式ばった説明は極力しない

利用例から紹介していく

#include <iostream>#include <string>#include <vector>

void display_party(std::vector<std::string> & party){ std::cout << "[現在のパーティー]" << std::endl; for(auto i = party.begin(); i != party.end(); ++i){ std::cout << *i << std::endl; }}

int main(void){ std::vector<std::string> current_party; current_party.push_back("勇者"); current_party.push_back("魔法使い"); current_party.push_back("遊び人"); display_party(current_party);

}

#include <iostream>#include <string>#include <vector>

void display_party(std::vector<std::string> & party){ std::cout << "[現在のパーティー]" << std::endl; for(auto i = party.begin(); i != party.end(); ++i){ std::cout << *i << std::endl; }}

int main(void){ std::vector<std::string> current_party; current_party.push_back("勇者"); current_party.push_back("魔法使い"); current_party.push_back("遊び人"); display_party(current_party); current_party.erase(current_party.begin()); display_party(current_party);}

何のことはない

配列を操作しているだけ

// 文字列型の配列を定義する// 「大きな枠組み<各個の要素>」と読むstd::vector<std::string> current_party;

// 配列に実際に文字列を追加するcurrent_party.push_back("勇者");

// 配列の先頭を削除するcurrent_party.erase(current_party.begin());

ただ、これだけでは終わらない

#include <iostream>#include <string>#include <vector>

struct Person{ std::string job; int level;};

void display_party(std::vector<Person> & party){ std::cout << "[現在のパーティー]" << std::endl; for(auto i = party.begin(); i != party.end(); ++i){ std::cout << i->job << "(Lv:" << i->level << ")" << std::endl; }}

int main(void){ std::vector<Person> current_party; current_party.push_back({"勇者", 30}); current_party.push_back({"魔法使い", 25}); current_party.push_back({"遊び人", 20}); display_party(current_party);}

好きな型で使うことができる

(なお、いくつか条件はあり)std::vector<std::string>std::vector<int>std::vector<Person>:

#include <iostream>#include <string>#include <map>

int main(void){ std::map<std::string, std::string> member_location; member_location["ろっさむ"] = "札幌"; member_location["ほっと"] = "札幌"; member_location["筒天"] = "札幌"; member_location["nawoyuki"] = "札幌"; member_location["睦月"] = "札幌"; member_location["H.Hiro"] = "札幌"; for(auto i = member_location.begin(); i != member_location.end(); ++i){ std::cout << i->first << ": " << i->second << " から来ました" << std::endl; }}

連想配列など他の構造も

ある

#include <iostream>#include <string>#include <vector>#include <algorithm>

struct Person{ std::string job; int level;};

void display_party(std::vector<Person> & party){ (略) }

int main(void){ std::vector<Person> current_party; current_party.push_back({"勇者", 30}); current_party.push_back({"魔法使い", 25}); current_party.push_back({"遊び人", 20}); std::sort(current_party.begin(), current_party.end(), [](const Person & a, const Person & b){ return a.level < b.level; }); display_party(current_party);}

検索や並べ替えなどの処理もできる

スクリプト言語だと普通の機能かもしれないけどC++でもちゃんと使えるよ!

だからみんなもっとC++使うといいと思うよ!

もう少し詳しく紹介

STLの構成要素

●コンテナ●イテレータ●アルゴリズム●関数オブジェクト

●コンテナ●イテレータ●アルゴリズム●関数オブジェクト

おそらく、上段ほどよく使われている

コンテナ:値を格納するためのtemplate型※「コンテナアダプタ」というものもあるけど今回は省略

std::vector<型名>std::map<型名, 型名>:

これはよく利用される

イテレータ:「繰り返し」「前(後)の要素」などの処理を抽象化したものfor(auto i = party.begin(); i != party.end(); ++i){ std::cout << *i << std::endl;}

どのコンテナでも記法は基本的に同じ

アルゴリズム:「並べ替え」「最大値取得」など、複数の値に対する処理std::sort(party.begin(), party.end(), [](const Person & a, const Person & b){ return a.level < b.level; // レベルの値が低い順に並べ替え });

イテレータのおかげで、どのコンテナに対しても共通で利用できる!

関数オブジェクト:「関数」を引数として渡したいときのための機構std::sort(party.begin(), party.end(), [](const Person & a, const Person & b){ return a.level < b.level; // レベルの値が高い順に並べ替え });

その場その場で自由に処理を差し替えられる

関数オブジェクト:「関数」を引数として渡したいときのための機構std::sort(party.begin(), party.end(), [](const Person & a, const Person & b){ return a.job < b.job; // 職業名の順に並べ替え });

その場その場で自由に処理を差し替えられる

「コンテナ」「イテレータ」は使ってる人は多そうだが

「アルゴリズム」「関数オブジェクト」

も使ってみよう!

さて、私が思うに

「コンテナ」「イテレータ」はともかく

「アルゴリズム」「関数オブジェクト」は以前は記法が面倒だった

ということで

このあたりで歴史的な話をしておきたい

以前は記法が面倒だったけど今なら大丈夫!

という点を紹介しておきたい

C++11

C++11●現最新規格(C++14)の一つ前●さらにその前の規格(C++03)から大幅に機能を追加●現在はコンパイラもかなり対応が進んでいる

C++11が使えるようになって、STL利用の利便性も大幅に向上

1. コンテナ初期化の記法が導入され、リテラルに近い感覚で利用できるようになった<従来>std::vector<int> hoge;hoge.push_back(9); hoge.push_back(1); hoge.push_back(3);

<C++11>std::vector<int> hoge = {9, 1, 3};

「連想配列のリテラル」も書けるようになった<従来>std::map<int, int> piyo;piyo[3] = 6; piyo[5] = 1; piyo[8] = 9;

<C++11>std::map<int, int> piyo = {{3, 6}, {5, 1}, {8, 9}};

2. イテレータ●auto記法が導入●その関係で、constイテレータを明示的に得る方法が新設された<従来>for(std::vector<int>::const_iterator it = hoge.begin();it != hoge.end(); ++it){ ... }

<C++11>for(auto it = hoge.cbegin(); it != hoge.cend(); ++it){ ... }

3. アルゴリズム/4. 関数オブジェクト●無名関数で非常に便利に<従来>struct SortByLevel{ int operator()(const Person & a, const Person & b){ return a.level < b.level; }};std::sort(party.begin(), party.end(), SortByLevel());<C++11>std::sort(party.begin(), party.end(), [](const Person & a, const Person & b){ return a.level < b.level; });

C++11対応コンパイラを前提にコードを書けば記法が非常にすっきりする

おわりに

C++使っててSTLを使ってないならまずは使ってみよう

STLを使っててもアルゴリズムや関数オブジェクトを

使ってないなら使ってみよう

今なら、C++11が普通に使える環境も

増えてる=記法も楽ですよ

ありがとうございました