Ryo Suzuki @Reputeless
2013.9.14 全日本学生ゲーム開発者連合(全ゲ連) 第 14 回交流会
v1.03
Siv3D 開発者 早稲田大学
1
2𝜋𝜎2
𝑒𝑥𝑝 −
𝑥 − 𝜇 2
2𝜎2
正規分布とゲーム
正規分布とゲーム
正規分布とゲーム
正規分布とゲーム
ゲームで現実味のある
ランダムな結果をつくるとき
正規分布が役に立つ
正規分布とゲーム
C++11では正規分布する乱数を
簡単につくる機能が追加
A Proposal to Add an Extensible Random
Number Facility to the Standard Library
(Revision 2) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1452.html
ゲーム開発者にとって
優しく便利になった最新の C++
最新の C++ でゲーム開発を
するための 14 のガイドライン
C++ の進化
C++98
major
C++03
bug fix only
C++11
major
C++14
minor
C++17
major
C++11 は
13 年ぶりのアップデート
C++11/14 での進化
• コードを短く簡単にする
• 間違いやすさを減らす
• 実行時性能を向上させる
• 機能を増やす
Visual Studio は
着実に C++11/14 に対応
2010. 4 2010
auto, move, nullptr
lamdas, <random>
2012. 9 2012
Range-based for, enum class
<chrono> , <ratio>. <thread>
2013. 6 2013 Preview
Variadic templates
initializer_lists, C++14 libs
2013. 9 2013 RC
Non-static data member init
defaulted / deleted functions
2013. 11 2013
2013 Q4 2013 + CTP
constexpr, noexcept
C++14 generic lamdas
Visual Studio 2010/2012/2013
でサポートされている機能を対象
最新の C++ でゲーム開発を
するための 14 のガイドライン
新しい
乱数ライブラリを
使おう
1.
<random> ヘッダの乱数エンジンは高品質
な乱数生成器を提供する
適切な分布クラスを定義することで、乱数
の型、範囲、分散のしかたを簡単にコント
ロールできる
要約
従来の rand() の欠点
• 最大値が 32767 と小さい (Visual Studio)
• 偏りが生じやすい
• 型や分布を柔軟に指定できない
新しい乱数ライブラリ
<random> ヘッダに定義
乱数エンジン
メルセンヌ・ツイスター法や
ハードウェアエントロピーによる乱数生成器
分布クラス
乱数の型と範囲、分散方法を定義
mt19937 rng;
for (int i=0; i<10; ++i)
cout << rng() << '¥n';
乱数エンジン [1/3]
メルセンヌ・ツイスター法による乱数生成
mt19937 rng(123456);
for (int i=0; i<10; ++i)
cout << rng() << '¥n';
乱数エンジン [2/3]
乱数のシード値を指定
random_device rng;
for (int i=0; i<10; ++i)
cout << rng() << '¥n';
乱数エンジン [3/3]
ハードウェア・エントロピー・ソースを
基にした予測不能な乱数生成
乱数生成器の比較
乱数の質 速度
rand() 低い 早い
mt19937 優秀 早い
random_device 真の乱数 遅い
mt19937 rng{ random_device()() };
for (int i=0; i<10; ++i)
cout << rng() << '¥n';
乱数エンジンの工夫
random_device で mt19937 のシード作成
mt19937 rng;
uniform_int_distribution<int> dist(1,6);
for (int i=0; i<10; ++i)
cout << dist(rng) << '¥n';
// 3 1 3 6 5 2 6 ...
整数の一様分布
指定した範囲の整数が等確率で出現
mt19937 rng;
uniform_real_distribution<double>
dist(-100.0,100.0);
for (int i=0; i<10; ++i)
cout << dist(rng) << '¥n';
// 62.9447 -72.90463 81.15846 ...
実数の一様分布
指定した範囲の実数が等確率で出現
ベルヌーイ分布
指定した確率で true が出現
mt19937 rng;
bernoulli_distribution dist(0.5);
if (dist(rng))
cout << "おもて¥n";
else
cout << "うら¥n";
正規分布
平均 μ, 標準偏差 σ の正規分布に
したがって値が出現
mt19937 rng();
normal_distribution<double>
dist(170.0,6.0);
for (int i=0; i<10; ++i)
cout << dist(rng) << '¥n';
0.000…% の
異常値を避けるために
適切にクランプする
正規分布の注意
3m級の巨人
<random> ヘッダの乱数エンジンは高品質
な乱数生成器を提供する
適切な分布クラスを定義することで、乱数
の型、範囲、分散のしかたを簡単にコント
ロールできる
復習
型の宣言は
autoに任せよう
2.
長い型名や、わかりにくい型名は
auto を使って省略しよう
auto を使っていて const や参照型が欲し
い場合は、const や & を記述すること
要約
auto x = 5; // int
auto y = 3.5f; // float
auto z = sin(3.14); // double
// 実際は上記のような単純な場面では
// 読みにくくなるので使うべきでない
auto [1/4]
宣言した変数の型を右辺の
初期化子から静的に推論
vector<int>::iterator i
= max_element(v.begin(),v.end());
map<string,pair<int,string>>::iterator k
= m.find("key");
auto [2/4]
長い型名を省略する
auto [3/4]
長い型名を省略する
auto i = max_element(v.begin(),v.end());
auto k = m.find("key");
const auto x = 5; // const int
vector<vector<int>> vv(10);
auto a = vv[0]; // vector<int>
auto& b = vv[0]; // vector<int>&
const auto& c = vv[0]; // const vector<int>&
auto [4/4]
const 修飾や参照の宣言
長い型名や、わかりにくい型名は
auto を使って省略しよう
auto を使っていて const や参照型が欲し
い場合は、const や & を記述すること
復習
範囲ベースの
ループを使おう
3.
範囲ベースのループを使うと、単純なルー
プを短く記述できる
ループカウンタのような不必要な変数を減
らし、コードの意図をより明確にしよう
要約
int scores[5] = {40,80,90,60,100};
for (auto& score : scores)
score += 10;
for (const auto score : scores)
cout << score << '¥n';
// 50 90 100 70 110
範囲ベース for ループ [1/5]
単純な for ループを短くできる
範囲ベース for ループ [2/5]
イテレーターを返す begin() / end()
メンバ関数を持っていれば使える
vector<int> v;
list<double> li;
string str;
for (auto n : v) cout << n << '¥n';
for (auto x : li) cout << x << '¥n';
for (auto ch : str) cout << ch << '¥n';
vector<Widget> widgets;
for (auto& widget : widgets)
widget.update();
for (const auto& widget : widgets)
widget.draw();
範囲ベース for ループ [3/5]
コピーを避けたい場合は参照で
範囲ベース for ループ [4/5]
二重ループの改善例
double matrix[4][4] = { ... };
for (int i=0; i<4; ++i)
{
for (int k=0; k<4; ++k)
cout << matrix[i][k] << ',';
cout << '¥n';
}
double matrix[4][4] = { ... };
for (const auto& row : matrix)
{
for (const auto elem : row)
cout << elem << ',';
cout << '¥n';
}
範囲ベース for ループ [5/5]
二重ループの改善例
範囲ベースのループを使うと、単純なルー
プを短く記述できる
ループカウンタのような不必要な変数を減
らし、コードの意図をより明確にしよう
復習
ラムダ式を使おう
4.
ラムダ式で関数オブジェクトをローカルに
定義し、アルゴリズムを読みやすくしよう
キャプチャを使うと外部の変数をラムダ式
の中で使用できる
要約
アルゴリズムは便利だ [1/3]
count_if
find_if
remove_if
for_each
generate
sort ...
第 3 引数に関数
bool IsEven(int n) {
return n%2==0;
}
vector<int> v;
// 偶数の要素を数える
size_t x = count_if(v.begin(),v.end(),
IsEven);
アルゴリズムは便利だ [2/3]
struct IsEven : unary_function<int,bool> {
result_type operator()
(argument_type n) const {
return n%2==0;
}}; // 関数オブジェクトは関数ポインタより
// インライン化されやすい
vector<int> v;
size_t x = count_if(v.begin(),v.end(),
IsEven());
アルゴリズムは便利だ [3/3]
述語関数が面倒だ
使う場所と定義する場所が離れている
関数オブジェクトは記述が長い
これを解決するのがラムダ式
size_t x = count_if(v.begin(),v.end(),
[](int n){ return n%2==0; });
ラムダ式 [1/4]
size_t x = count_if(v.begin(),v.end(),
[](int n){ return n%2==0; });
ラムダ式 [2/4]
[] () ->T {} で構成される
[] キャプチャリスト
() 引数
->T 戻り値の型(省略可)
{} 関数の本体
size_t x = count_if(v.begin(),v.end(),
[](int n){ return n%2==0; });
ラムダ式 [3/4]
ラムダ式は、相当する関数オブジェクトを
自動で作る
可読性とパフォーマンスに優れる
auto Square =
[](int n){ return n*n; };
cout << Square(9) << '¥n'; // 81
ラムダ式で遊ぼう [1/7]
auto PrintSquare =
[](int n){ cout << n*n << '¥n'; };
PrintSquare(100); // 10000
ラムダ式で遊ぼう [2/7]
const int ar[4] = { 1, 2, 3, 4 };
for_each(begin(ar),end(ar),
[](int n){ cout << n*n << ' '; });
// 1 4 9 16
ラムダ式で遊ぼう [3/7]
const int ar[4] = { 1, 2, 3, 4 };
const int x = 10;
for_each(begin(ar),end(ar),
[=](int n){ cout << n*x << ' '; });
// [=] により、ラムダ式内の x は
// 外部からコピーキャプチャ
// 10 20 30 40
ラムダ式で遊ぼう [4/7]
const int ar[4] = { 1, 2, 3, 4 };
int sum = 0;
for_each(begin(ar),end(ar),
[&](int n){ sum += n; });
// [&] により、ラムダ式内の sum は
// 外部から参照キャプチャ
cout << sum << '¥n'; // 10
ラムダ式で遊ぼう [5/7]
vector<Vec2> pts;
// 原点に近い順にソート
sort(pts.begin(),pts.end(),
[](const Vec2& a, const Vec2& b)
{ return a.lengthSq()<b.lengthSq(); }
);
ラムダ式で遊ぼう [6/7]
vector<Enemy> enemies;
int threshold = 20;
// HP が threshold 未満の敵を削除
enemies.erase(remove_if(
enemies.begin(),enemies.end(),
[=](const Enemy& enemy)
{ return enemy.hp < threshold; }),
enemies.end()
);
ラムダ式で遊ぼう [7/7]
ラムダ式で関数オブジェクトをローカルに
定義し、アルゴリズムを読みやすくしよう
キャプチャを使うと外部の変数をラムダ式
の中で使用できる
復習
Emplacementの
使い所を知ろう
5.
オブジェクトの構築とコンテナへの追加を
同時に行う場合は Emplacement を使おう
適切な場面で使えば push_back に比べて
要素追加のコストを減らせる
要約
vector<Point> v;
v.push_back(Point(5,10));
push_back() のコスト
5 10
COPY
vector<Point> v;
v.emplace_back(5,10);
emplace_back()
5 10
Emplacement [1/2]
要素のコンストラクタ引数を受け取り、コ
ンテナ内でオブジェクトを構築する
一時オブジェクトのコピーと破棄のコスト
が発生しない
5 10
Emplacement [2/2]
vector, deque, map などのコンテナの
Emplacement 挿入関数
push_back() → emplace_back()
push_front() → emplace_front()
insert() → emplace()
要素追加の使い分け [1/2]
vector<T> などに対して
push_back()
T 型の値 (lvalue / rvalue),
{ initializer-lists }
emplace_back()
それ以外の型,
0 個 もしくは 2 個以上の引数
string GetString();
const string str = "Hello";
vector<string> v;
v.push_back(str);
v.push_back(GetString());
v.push_back({ str[0], 'e'});
v.emplace_back("hello");
v.emplace_back();
v.emplace_back(10,'a');
要素追加の使い分け [2/2]
オブジェクトの構築とコンテナへの追加を
同時に行う場合は Emplacement を使おう
適切な場面で使えば push_back に比べて
要素追加のコストを減らせる
復習
強く型付けされた
enumを使おう
6.
enum class は enum の強化版で、強い型付
けとスコープを持つ
enum class を使えば、整数型への暗黙的な
変換や、列挙子の名前の衝突を防げる
要約
void SetColor(unsigned);
enum Team { Red, White };
const unsigned red = 0xffFF0000;
SetColor(red);
SetColor(Red); // ?
従来の enum の問題点 [1/2]
整数型に暗黙的に変換できるため、
意図しない振る舞いが可能
struct Team {
enum { Red, White };
};
struct Palette {
enum { Red, Green, Blue };
};
従来の enum の問題点 [2/2]
名前の衝突を防ぐために
スコープを作る必要がある
enum class name : type {
enumerator = constexpr,
enumerator = constexpr, ...
};
enum struct name : type {
enumerator = constexpr,
enumerator = constexpr, ...
};
enum class [1/4]
強い型付けとスコープを持つ列挙型
enum class Team { Red, White };
enum class Month {
January = 1, February, ...
};
enum class Align : char {
Left = 'L',
Center = 'C',
Right = 'R',
};
enum class [2/4]
enum class Team { Red, White };
enum class Palette { Red, Green, Blue };
const Team team = Team::Red;
switch (palette) {
case Palette::Red : break;
case Palette::Green : ...
}
enum class [3/4]
列挙型名のスコープを持つ
void SetColor(unsigned);
enum class Team { Red, White };
const unsigned red = 0xffFF0000;
SetColor(red);
SetColor(Team::Red); // error
const int white = Team::White; // error
enum class [4/4]
整数型へ暗黙的に変換されない
enum class は enum の強化版で、強い型付
けとスコープを持つ
enum class を使えば、整数型への暗黙的な
変換や、列挙子の名前の衝突を防げる
復習
arrayを活用しよう
7.
array は通常の配列にオーバーヘッド無し
でコンテナのインタフェースを提供する
array のインタフェースが有効な場面では、
積極的に活用しよう
要約
配列と array [1/2]
配列はインタフェースが貧弱
const int size = 100;
int ar[size];
for (int i=0; i<size; ++i)
ar[i] = 10 * i;
配列と array [2/2]
<array> ヘッダの array を使おう
array<int,100> ar;
for (size_t i=0; i<ar.size(); ++i)
ar[i] = 10 * i;
array [1/2]
通常の配列にコンテナのインタフェースを
与えたラッパー
size(), at(), begin(), end(), fill()
などのメンバ関数を提供
サイズはコンパイル時に決まり、パフォー
マンスは通常の配列と変わらない
array [2/2]
array<int,5> a = { 5, 10, 15, 20, 25 };
array<int,5> b;
b.fill(100); // 要素を全部 100 に
a = b; // 要素数が同じなら代入可能
a[0] = 0;
for (const auto n : a)
cout << n << '¥n';
array は通常の配列にオーバーヘッド無し
でコンテナのインタフェースを提供する
array のインタフェースが有効な場面では、
積極的に活用しよう
復習
NULLをnullptrに
置き換えよう
8.
ヌルポインタを表す NULL と 0 を nullptr
に置き換えよう
ヌルポインタの意図が明確になり、オー
バーロードのトラブルを防げる
要約
ヌルポインタ [1/3]
NULL
#define NULL 0
と定義される、単なる数値の 0
nullptr
あらゆるポインタ型のヌルポインタを
表すポインタ定数のキーワード
整数には変換できない
C++98
ヌルポインタ [2/3]
NULL はトラブルの元
void f(int n);
void f(const char* s);
f(0);
f("hello");
f(NULL); // f(int)
ヌルポインタ [3/3]
nullptr でオーバーロードを正確に
void f(int n);
void f(const char* s);
f(0);
f("hello");
f(nullptr); // f(const char*)
ヌルポインタを表す NULL と 0 を nullptr
に置き換えよう
ヌルポインタの意図が明確になり、オー
バーロードのトラブルを防げる
復習
右辺値参照を
理解しよう
9.
右辺値参照と Move セマンティクスによっ
て、サイズが大きいオブジェクトのコピー
のパフォーマンスが向上する
自分で定義したクラスにも、必要なら
Move セマンティクスを実装できる
要約
vector<int> GetVector();
void GetVector(vector<int>& v);
vector<int> v
= GetVector(); // コピーが発生
GetVector(v); // ok
右辺値参照と Move [1/5]
むかーしむかし、大きなオブジェクトを返
す関数は御法度だった
vector<int> GetVector();
void GetVector(vector<int>& v);
vector<int> v = GetVector(); // ok
GetVector(v); // ok
右辺値参照と Move [2/5]
今はそんなことはない
右辺値参照と Move [3/5]
ptr1
ptr2
コピー完了後に破棄
コピー
これまで
C++98
右辺値参照と Move [4/5]
ptr1
ptr1
所有権を移動
(Move セマンティクス)
これから
nullptr
右辺値参照と Move [5/5]
右辺値
名前のない一時オブジェクト
右辺値参照 (Type&& x)
右辺値を受け取るオーバーロード
std::move() 関数
左辺値を右辺値にキャスト
右辺値参照 実装例 1
struct BigData {
BigData();
BigData(const BigData&);
BigData(BigData && data)
: m_p(data.m_p),m_size(data.m_size) {
data.m_p = nullptr;
data.m_size = 0;
}
~BigData();
int* m_p;
int m_size;
};
右辺値参照 実装例 2
struct BigData {
BigData();
BigData(const BigData&);
BigData(BigData && data)
: m_data(move(data.m_data)) { }
vector<int> m_data;
};
右辺値参照と Move セマンティクスによっ
て、サイズが大きいオブジェクトのコピー
のパフォーマンスが向上する
自分で定義したクラスにも、必要なら
Move セマンティクスを実装できる
復習
スマートポインタは
補助関数で作ろう
10.
オブジェクトのポインタはスマートポイン
タで管理しよう
スマートポインタは補助関数で作って、パ
フォーマンスの利得と、記述の一貫性を得
よう
要約
さらば new と delete [1/5]
new と delete は危険
int* pArray = new int[10000];
delete[] pArray; // 取扱注意
さらば new と delete [2/5]
動的配列は vector か string
vector<int> v(10000);
string str;
さらば new と delete [3/5]
単一のデータのポインタは・・・
Enemy* pEnemy = new Boss;
delete pEnemy;
さらば new と delete [4/5]
スマートポインタを使う
shared_ptr<Enemy> pEnemy = new Boss;
// 自動的に delete してくれる
// まだ最適化可能
unique_ptr<Enemy> pEnemy = new Boss;
// 自動的に delete してくれる
さらば new と delete [5/5]
ポインタをコピーしない場合、
unique_ptr を使えばゼロオーバーヘッド
補助関数 [1/2]
スマートポインタは補助関数で作ろう
make_shared<T>
オブジェクトと管理用データを一緒に
連続領域に new するので効率的
make_unique<T>
名前の一貫性、new の記述が不要に
補助関数 [2/2]
shared_ptr<Enemy> pEnemy
= make_shared<Boss>();
unique_ptr<Enemy> pEnemy2
= make_unique<Boss>();
オブジェクトのポインタはスマートポイン
タで管理しよう
スマートポインタは補助関数で作って、パ
フォーマンスの利得と、記述の一貫性を得
よう
復習
Transparent
operator functors
を使おう
11.
将来起こりそうな問題は?
vector<unsigned> v { 10, 50, 20, 30 };
sort(v.begin(),v.end(),
greater<unsigned>());
将来起こりそうな問題は?
vector<unsigned> v { 10, 50, 20, 30 };
sort(v.begin(),v.end(),
greater<unsigned>());
vector<int> v { -10, 50, 20, 30 };
sort(v.begin(),v.end(),
greater<unsigned>()); // oops!
Transparent operator
functors
vector<unsigned> v { 10, 50, 20, 30 };
sort(v.begin(),v.end(),greater<>());
比較・算術用クラステンプレート
[less, greater, plus, multiplies …] を
テンプレート実引数なしで使える
<functional> ヘッダの関数オブジェクト
をテンプレート実引数なしで使おう
単に記述が短いだけでなく、型を変更した
際のトラブルを防げる
復習
古いイディオムを
捨てよう
12.
これまでのイディオムを新しい C++ の機
能で置き換えられないか再確認しよう
C++11/14 はよりシンプルで、高速、安全
な代替手段を提供しているかもしれない
要約
shrink to fit
vector<int> v;
vector<int>(v).swap(v);
vector<int> v;
v.shrink_to_fit();
配列の範囲
int a[] = { 5, 3, 6, 8, 2 };
const int size = sizeof(a)/sizeof(a[0]);
sort(a,a+size);
int a[] = { 5, 3, 6, 8, 2 };
sort(begin(a),end(a));
Safe bool
/*
Safe bool は operator bool を定義した
オブジェクトの無意味な比較を防ぐ。実装省略
*/
struct Something {
explicit operator bool() const;
};
コンパイル時 assert
#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
#define STATIC_ASSERT(e,m) ¥
enum{ASSERT_CONCAT(static_assert_,__COUNTER__)=1/(!!(e))}
STATIC_ASSERT(sizeof(int)==4,"xxxx");
static_assert(sizeof(int)==4,"xxxx");
これまでのイディオムを新しい C++ の機
能で置き換えられないか再確認しよう
C++11/14 はよりシンプルで、高速、安全
な代替手段を提供しているかもしれない
復習
新しい
アルゴリズムを
知ろう
13.
<algorithm> ヘッダの新しいアルゴリズム
関数を知ろう
ちょっとした操作やループを、これまでよ
り短く、早いコードで書けるようになる
要約
const int a = 5, b = 10, c = 50, d = 20;
const int smallest
= min(min(min(a,b),c),d); // 5
const int largest
= max(max(max(a,b),c),d); // 50
最小/最大値の取得
3 つ以上の変数に対しては
何重もの min() / max() が必要
const int a = 5, b = 10, c = 50, d = 20;
const int smallest
= min({ a, b, c, d }); // 5
const int largest
= max({ a, b, c, d }); // 50
最小/最大値の取得
initializer-list で複数の値を渡す
int a = 25, b = 30;
const int smaller = min(a,b); // 25
const int larger = max(a,b); // 30
最小/最大値を同時に取得
min() と max() で比較演算が 2 回必要
int a = 25, b = 30;
// results は pair<int,int> 型
const auto results = minmax(a,b);
const int smaller = results.first; // 25
const int larger = results.second; // 30
最小/最大値を同時に取得
minmax() で比較演算が 1 回に
int a[100]; // {0,1,2,3,...} で初期化したい
vector<int> v(50); // {1000,1001,...}
for (int i=0; i<100; ++i)
a[i] = i;
for (size_t i=0; i<v.size(); ++i)
v[i] = i + 1000;
配列に連続した値を代入
ループが必要
int a[100]; // {0,1,2,3,...}
vector<int> v(50); // {1000,1001,...}
iota(begin(a),end(a),0);
iota(v.begin(),v.end(),1000);
配列に連続した値を代入
iota() アルゴリズムを使おう
const int maxVal = 500; // 500円まで
bool ruleKept = true;
for (size_t i=0; i<v.size(); ++i) {
if (v[i] > maxVal) {
ruleKept = false;
break;
}
}
全要素の条件チェック
ループが必要
const int maxVal = 500;
const bool ruleKept
= all_of(v.begin(),v.end(),
[=](int n){ return n<=maxVal; });
全要素の条件チェック
all_of() アルゴリズムを使おう
const int maxVal = 500;
const bool ruleBroken
= any_of(v.begin(),v.end(),
[=](int n){ return n>maxVal; });
const bool ruleKept
= none_of(v.begin(),v.end(),
[=](int n){ return n>maxVal; });
全要素の条件チェック
文脈に応じて any_of() ,
none_of アルゴリズムも使おう
vector<int> v { 1, 2, 3, 4, 5, 6, 7 };
shuffle(v.begin(), v.end(),
mt19937(random_device()()));
要素をランダムに並び替え
shuffle() アルゴリズムと
乱数エンジンを使おう
<algorithm> ヘッダの新しいアルゴリズム
関数を知ろう
ちょっとした操作やループを、これまでよ
り短く、早いコードで書けるようになる
復習
新しいライブラリを
知ろう
14.
新しく追加されたライブラリによって、こ
れまで難しかった処理や高速なデータ管理
が可能になる
要約
const auto start = chrono::system_clock::now();
// 何らかの処理
const auto end = chrono::system_clock::now();
const chrono::duration<double> elapsed
= end - start;
cout << "経過時間: " << elapsed.count() << "秒¥n";
<chrono> [1/2]
時間の測定
const chrono::minutes min(5);
const chrono::seconds sec(15);
// 型は std::chrono::seconds
const auto result = min + sec;
cout << result.count() << '¥n'; // 315
<chrono> [2/2]
時間の計算と単位の変換
string s = "Hello C++11, C++14 & C++1y!";
const regex e("C¥¥+¥¥+[0-9][0-9a-z]");
smatch m;
while (regex_search(s,m,e)) {
cout << m[0] << '¥n';
s = m.suffix().str();
} // C++11 C++14 C++1y
<regex> [1/2]
正規表現にマッチする文字列の検索
const string s = "C++11, C++14 and C++1y";
const regex e("¥¥d");
cout << regex_replace(s,e,"[$&]") << '¥n';
// C++[1][1], C++[1][4] and C++[1]y
<regex> [2/2]
正規表現を使った文字列の置換
tuple<string,int,char> GetStudent()
{
return make_tuple("John", 86, 'B');
}
const auto student = GetStudent();
cout << get<0>(student) << '¥n'
<< get<1>(student) << '¥n'
<< get<2>(student) << '¥n';
<tuple>
複数の型をまとめて 1 つの型を作る
unordered_set<string> s = {
"C++", "Java", "Ruby", "PHP"
};
s.emplace("Haskell");
if (s.find("C#") == s.end())
cout << "not found¥n";
<unordered_set>
O(1) で要素にアクセスできる、
ハッシュを使った非順序 set
unordered_map<string,int> m {
{ "C++98", 1998 },
{ "C++11", 2011 }
};
m.emplace("C++14",2014);
cout << m["C++11"] << '¥n'; // 2011
<unordered_map>
O(1) で要素にアクセスできる、
ハッシュを使った非順序 map
新しく追加されたライブラリによって、こ
れまで難しかった処理や高速なデータ管理
が可能になる
復習
今日紹介したのは、
新しい C++ の一部分
追加資料 1
Visual C++ で使える C++11
by @nekko1119 さん
http://www.slideshare.n
et/nekko1119/c11-in-
visual-c
追加資料 2
C++14 Overview
by @cpp_akira さん
http://www.slideshare.n
et/faithandbrave/c14-
overview
追加資料 3
cpprefjp (日本語)
http://cpprefjp.github.io/
cppreference.com (英語)
http://en.cppreference.com/w/
cplusplus.com (英語)
http://www.cplusplus.com/reference/
Question?
1. 新しい乱数ライブラリを使おう
2. 型の宣言は auto に任せよう
3. 範囲ベースのループを使おう
4. ラムダ式を使おう
5. Emplacement の使い所を知ろう
6. 強く型付けされた enum を使おう
7. array を活用しよう
8. NULL を nullptr に置き換えよう
9. 右辺値参照を理解しよう
10. スマートポインタは補助関数で作ろう
11. Transparent operator functors を使おう
12. 古いイディオムを捨てよう
13. 新しいアルゴリズムを知ろう
14. 新しいライブラリを知ろう
2013.9.14
Ryo Suzuki
@Reputeless
reputeless@gmail.com
最新の C++ で設計された
ゲームとメディアアートの
ための C++ ライブラリ Siv3D
http://play-siv3d.hateblo.jp/
更新履歴
2015.1.11 v1.03
p.58 関数名の誤植を修正
p.154 cpprefjp の URL を更新
2013.9.28 v1.02
p.26 コンパイルエラーになるコードを修正
2013.9.17 v1.01
p.42 変数に const をつけていた誤植を修正
p.63 ) が 1 つ多かった誤植を修正

ゲーム開発者のための C++11/C++14