&size(30){&color(darkblue,#c0c0ff){''C++(14) Enumerateユーティリティ''&br;};};
#counter

*はじめに [#x761471e]

[[C++AdventCalender2014>http://qiita.com/advent-calendar/2014/cpp]] 22日目の記事です。

21日目の記事は、yohhoyさんによる[[メモリモデル?なにそれ?おいしいの?>http://yohhoy.hatenablog.jp/entry/2014/12/21/171035]]です。~
23日目の記事は、ボレロ村上さんによる[[コンパイル時Brainfuckコンパイラ ――C++14 constexpr の進歩と限界――>http://boleros.hateblo.jp/entry/2014/12/24/065155]]です。~
21日目の記事は、Yuki Maria Miyatakeさんによる[[boost.Asioを半年使っわかったこと>http://qiita.com/YukiMiyatake/items/5be12ea35894071d8de1]]です。~

AdventCalenderに参加するのも今年で3回目になりました。~
ゲームプログラミングにC++11を導入して約1年半経過しましたので、その間に気がついたことをまとめました。~
長くなってしまい、書きたいことの半分ぐらいしか書けませんでいたが、続編を次の機会ということでお許しください。~
23日目の記事は、on_origami さんによる MATLABとC++の奇妙な関係 です。

ゲームプログラミングの開発環境が変化してきました。~
かつてアセンブラやCで書かれていたゲームプログラムは、C++での開発が主流になったといえるでしょう。~
C#やJavaでのゲームプログラミングも現実的になってきましたが、本格的なゲーム開発言語はC++が多いと思います。~
なぜならば、ゲームは処理速度、メモリ効率、レスポンス、いずれも高い次元で動作することが要求されるからです。
Advent Calendarに参加するのも今年で4年目になりました。~
ゲームプログラミングにC++11を導入して約2年半あまり。最近はC++14でコーディングするようになり、シンタックスシュガー漬けの甘い日々を過ごしています。~

C++11の登場で、C++でのゲームプログラミングも大幅に進化しました。~
それは、アセンブラからCへ、CからC++へと変遷していったときと同じぐらい、大きなインパクトがあります。
C++11により、C++のウイークポイントが解消され、実行速度、メモリ効率、開発効率、ともに大幅な改善がされたためです。
痒いところに手がとどくようになってきたC++14ですが、便利になった反面、enumerateの書式は大きく進化しておらず、相対的に使い勝手が悪いと感じることが増えてきました。~

さらに、C++は14,17とこれからも進歩を遂げ、ますます効率的で使い易い言語になっていきます。~
ビャーネさんの言葉を借りると、C++は理解している者にとってはとても優しい言語です。
ゲームプログラミング特有のコーディングを踏まえて、まとめてみました。
そこで、以前から自前で作成していたenumerateツールをC++14対応にし、ブラッシュアップいたしましたので、ここで発表したいとおもいます。~

なお、Chapter-1とChapter-2はムーブ(右辺値参照)とラムダ式のおさらいなので、C++11を熟知している方は読み飛ばしてください。

-----
* もくじ [#md950fd7]
- [[Chapter-1 moveの活用>#se0884ad]]
-- [[1-1 ムーブセマンティクスのおさらい>#w470c8e3]]
-- [[1-2 ムーブコンストラクタとムーブ代入演算子(operator =)を実装>#e79b2ab6]]
-- [[1-3 ムーブの落とし穴(地雷)>#d5297a36]]
--- [[1-3-1 右辺値参照引数のムーブ>#forward]]
--- [[1-3-2 std::swapの違い>#u367b8ee]]
--- [[1-3-3 move後のクラスオブジェクトへのアクセス>#z2f97230]]
--- [[1-3-4 継承クラスのmoveコンストラクタ>#k34d6cf5]]
--- [[1-3-5 VisualStudioはmoveコンストラクタを自動生成してくれない>#v2b4d8f6]]
- [[Chapter-2 ラムダ式の活用>#b1ba22c5]]
-- [[2-1 コールバックの活用>#b7b82b67]]
-- [[2-2 遅延評価>#wcae6356]]
-- [[2-3 遅延実行>#chap2_3]]
-- [[2-4 ラムダ式の注意点>#y96adffe]]
--- [[2-4-1 キャプチャのパフォーマンス>#ycae0541]]
--- [[2-4-2 shared_ptrのキャプチャ問題>#kba68e9e]]
- [[Chapter-3 コピーコンストラクタの廃止によるパフォーマンスアップ>#k512d924]]
-- [[3-1 コピーコンストラクタをムーブコンストラクタに置き換える>#sd4fcc08]]
-- [[3-2 shared_ptrをunique_ptrに置き換える>#j6d280b8]]
- [[Chapter-4 応用編 描画ループの処理>#t0585e51]]
-- [[4-1 スレッドを使用しない遅延実行関数>#k6a2857f]]
-- [[4-2 タスクマネージャの紹介>#e5377937]]
- [[Chapter-1 enumの走査を便利にする>#w3909b06]]
--[[1-1 enumrateの走査>#f1d8f37b]]
--[[1-2 EnumListの定義>#f1d8f37b]]
- [[Chapter-2 enumをフラグとして使いたい>#w3909b06]]
--[[2-1 従来の方法の問題点>#f1d8f37b]]
--[[2-2 EnumListを利用したenumerateのフラグ化>#ve9131f4]]
--[[2-3 EnumList::Flagsの実装>#ve9131f4]]
- [[Chapter-3 enumをboost::adaptorsから使いたい>#w3909b06]]
--[[3-1 boost adaptorsでenumを便利に使う>#i3ccf435]]
--[[3-3 構造体のメンバ変数を型から取得するためのgetter定義>#lcbdd3ed]]
--[[3-4 EnumAdapterの実装>#m3f00e59]]

- [[おわりに>#end]]
-----
* CHAPTER-1 moveの活用 [#w3909b06]

moveの活用による恩恵は計り知れません。
とくに、速度とメモリ効率、そしてデバッグ効率を重視するゲームプログラミングにおいて、
moveセマンティクスの導入は大きな効果がありました。
* Chapter-1 enumの走査を便利にする[#w3909b06]

なお、moveに関して十分な知識のある方ば、Chapter-1は読み飛ばしてください。
-----
** 1-1 moveのおさらい [#f1d8f37b]
** 1-1 enumrateの走査 [#f1d8f37b]

moveを使う前に、右辺値参照について知っておく必要があります。
国籍を表すenumerate定義

このプログラムを見てください。

#sh(cpp){{
string a = "1";
string b = "2";
string c = a + b;
//         ~~~~~
//         右辺値
}}

この"a + b"の部分が右辺値です。~
右辺値とは、名前のない一時的に生成されるオブジェクトのことです。~
この場合、string型で値が"12"の一時オブジェクトが生成されます。
わかりやすくC++03の書式で置き換えると、

#sh(cpp){{
string a = "1";
string b = "2";
string tmp(a + b);
string c = tmp;
}}

このような動作になります。~
tmpは式の外では不要になる、一時オブジェクトです。

最後の"c = tmp"で行われるコピーが無駄な動作ということは明白ですね。~
C++03では、右辺値を変数に代入する時点で、コピーが発生してメモリと処理速度の無駄が発生していました。

コピーの無駄を省くにはtmpをcにエイリアスしてしまえはば解決しますが、

#sh(cpp){{
string& c = a + b; // コンパイルエラー!
}}

これはエラーになります。"a + b"は右辺値なので、参照型として使うことができません。
C++03では、メモリ上の何処かに生成された一時オブジェクトを、式の外へ持ち出す手段がありませんでした。

C++11では、右辺値参照という新しい機能が追加されました。

#sh(cpp){{
string&& c = a + b; // 右辺値への参照をGET!
}}

これで、C++03で記述する以下の動作とほぼ等しくなります。

#sh(cpp){{
string tmp = a + b;
string& c = tmp;
}}

C++03では、右辺値として生成されたオブジェクトを使う場合、いったんコピーする必要がありました。

では、moveはどこで使うかというと、
#sh(cpp){{
string&& c = a + b;
}}
とするかわりに、
#sh(cpp){{
string c = move(a+b);
}}
とすることで、"a + b"の一時オブジェクトをcに移動することが可能になります。
最初の例と大きな違いがないように見えますが、前者は(右辺値)参照、後者は移動(move)という違いがあります。

一般的には、moveのコストはcopyよりもずっと小さく、stringならばバッファのポインタとサイズをコピーするだけで終わります。
メモリ上にアロケートされた実体はコピーされずにそのまま使われます。

なお、上記の例はわかりやすくするために move(a+b)と書きましたが、a+bは明らかに右辺値なのでmoveは省略できます。
moveを明示的に使うのは、左辺値を右辺値に変換するときに使用します。

#sh(cpp){{
string a = "1";
string c = move(a); // cにaのインスタンスが移動する。
// これ以降はaにアクセスしてはならない。
// aは、ヌケガラ、デガラシ、捨てられたバナナの皮のようなもの。
// アクセスすると、未定義動作の洗礼を受けることになる。
}}

この例だと、aをcに移動させているだけで、なんのメリットもないコードです。
しかし、moveは後述するコンストラクタや代入演算子で必要になります。

-----
*** 1-2 ムーブコンストラクタとムーブ代入演算子を実装 [#gc7f8f9e]

下記のプログラムは、C++03とC++11では動作が大きく異なります。
#sh(cpp){{
string c = a + b;
}}

先ほど解説したとおり、C++11では、"a + b"の一時オブジェクトはcにmoveされます。

なぜmoveされるのか? それは、stringにムーブ代入演算子とムーブコンストラクタがあるからです。
もし、自前のクラスで、ムーブコンストラクタやムーブ代入演算子が定義されていなかったら、moveされません。

#sh(cpp){{
Hoge a = 1;
Hoge b = 2;
Hoge c = a + b;
}}

この、3行目の"c = a + b"の動作は、Hogeクラスにムーブコンストラクタが実装されているか否かできまります。

Hogeにムーブ代入演算子がなくても、ビルドはとおります。プログラムは何事もなかったかのように、*COPY*を行ってゆっくりと動作するでしょう。
目に見えにくいので注意が必要です。

moveを使うには、ムーブコンストラクタとムーブ代入演算子を定義する必要があります。

#sh(cpp){{
struct Hoge {
  string str_;
  Hoge(const Hoge& hoge) : str_(hoge) {} // コピーコンストラクタ
  Hoge(Hoge&& hoge) : str_(move(hoge)) {} // ムーブコンストラクタ
  Hoge& operator = (const Hoge& hoge) { str_ = hoge.str_; return *this; } // コピー代入演算子
  Hoge& operator = (Hoge&& hoge) { str_ = move(hoge.str_); return *this; } // ムーブ代入演算子
enum class Nationality {
	Japanese, // 日本
	American, // アメリカ
	German,   // ドイツ
	French,   // フランス
	Russian,  // ロシア
};
}}
これでOKです。~
インスタンスに対する操作が標準的な実装ならば、以下のように省略することができます。
#sh(cpp){{
struct Hoge {
  string str_;
  Hoge(const Hoge& hoge) = default;
  Hoge(Hoge&& hoge) = default;
  Hoge& operator = (const Hoge& hoge) = default;
  Hoge& operator = (Hoge&& hoge) = default;
};
}}

コードの例~
http://melpon.org/wandbox/permlink/OHFJkkmV7XZllqL7 ~
http://melpon.org/wandbox/permlink/7v7e0TFsorASaOzQ ~
-----
** 1-3 ムーブの落とし穴(地雷) [#q46eccd9]
すべてのNationalityを走査するには?

moveを活用することで速度とメモリ効率を同時に向上できますが、いくつか落とし穴があります。
実際に私が踏んでしまた地雷について解説します。
-----
*** 1-3-1 右辺値参照引数のムーブ [#f6f3fab7]

右辺値参照で受け取った引数を、別の関数の右辺値参照の引数として呼び直す場合、

#sh(cpp){{
void hoge(string&&);

void foo(string&& str) {
     hoge(move(str)); // このmoveを忘れるとコピーされてしまう
for (int n = 0; n <= static_cast<int>(Nationality:: Russian); ++n) {
	auto nationality = static_cast<Nationality>(n);
	hoge(nationality); // Natioanlityを使用した処理
}
}}

このように、hogeにstrをムーブしたければ、move指定が必要です。~
なぜならば、右辺値参照引数のstrは左辺値だからです。ややこしいですが、&&で宣言した変数も、&で宣言した変数と同じように振る舞います。
static_castが''冗長でイヤ''ですね

では、可変長引数の場合はどうでしょう?

#sh(cpp){{
template<typename... ARGS>
void hoge(ARGS&&... args) {
}
こんな風に書けたら便利です~

template<typename... ARGS>
void foo(ARGS&& ...args) {
     hoge(move(args...)); // コンパイルエラー
}
}}

残念ながら、このプログラムはコンパイルエラーです。このような場合は、std::forwardを使用します。

#sh(cpp){{
template<typename... ARGS>
void hoge(ARGS&&... args) {
}

template<typename... ARGS>
void foo(ARGS&& ...args) {
     hoge(forward<ARGS>(args)...); // OK
}
NationalityList::eachEnum([](auto nationality) { 
         hoge(nationality); // Natioanlityを使用した処理
});
}}

右辺値参照の変数を使って他の関数を呼ぶ場合、
うっかりmoveやforwardを忘れるとせっかくの右辺値参照の値がコピーされてしまうので注意が必要です。

-----
*** 1-3-2 std::swapの違い [#n514651b]
EnumListというヘルパークラスを作りました

C++03でのstd::swapは、以下のような実装でした。
#sh(cpp){{
template<typename T>
void swap(T& a, T& b) {
     T tmp = a;
     a = b;
     b = tmp;
}
using NationalityList = EnumList<Nationality, Nationality::End>;
}}
このように、代入を3回行うことでaとbを入れ替えています。~
これが、C++11になると以下のような実装に変わりました。
#sh(cpp){{
template<typename T>
void swap(T& a, T& b) {
     T tmp = move(a);
     a = move(b);
     b = move(tmp);
}
}}
コピー3回から、move3回に変わっています。~
通常のクラスなら気にすることはないのですが、バッファやリソースの管理を行っているクラスで、コピーやswapに特殊な操作が必要な場合は要注意です。

std::swapは、コピーコンストラクタの有無、ムーブコンストラクタの有無、代入演算子の有無などで、以下のような動作になります。
これでOK~
終端を定義するために、列挙体の最後に'End'を追加してあります。

|	|copy constructor|move constructor|operator= const&|operator= &&|copyされる回数|moveされる回数|
|C++03	|      なし      |        なし    |     なし      |      なし     |CENTER: 3回 |CENTER: 0回 |
|C++11	|      なし      |        なし    |     なし      |      なし     |CENTER: 0回 |CENTER: 3回 |
|C++11(VS2013)|  なし    |        なし    |     なし      |      なし     |CENTER: 3回 |CENTER: 0回 |
|C++11	|      both      |        なし    |     both      |      なし     |CENTER: 3回 |CENTER: 0回 |
|C++11	|      both      |        あり    |     both      |      あり     |CENTER: 0回 |CENTER: 3回 |
|C++11	|      あり      |        あり    |     both      |      なし     |CENTER: 2回 |CENTER: 1回 |
|C++11	|      あり      |        なし    |     both      |      あり     |CENTER: 1回 |CENTER: 2回 |

C++03で書かれたソースをビルドすると、コピーコンストラクタが無いクラスはムーブされ、コピーコンストラクタが定義されているクラスはコピーされます。~
(VisualStudioではいずれもコピーになります)

C++11では、ムーブコンストラクタとムーブ代入演算子をセットで定義しておかないと、std::swapが期待通りの動作をしてくれないようです。

-----
*** 1-3-3 ムーブ後のクラスオブジェクトへのアクセス [#s3a49108]

以下のプログラムは、何の問題もなく動くはずでした。すくなくともC++03までは。

#sh(cpp){{
void foo(string&);
void func() {
     string a = "hoge";
     foo(a);
     cout << a << endl;
}
}}
しかし、ムーブセマンティクスが導入されたC++11では、foo()の実装次第では安全でなくなります。
#sh(cpp){{
void foo(string& a) {
     string b = move(a);
     // ここでaはヌケガラとなる
}
void func() {
     string a = "hoge";
     foo(a); // fooの中でaが破壊される
     cout << a << endl; // 未定義動作
}
}}
これを回避するには、関数のAPIをしっかりと設計するしかありません。
参照で受け取った引数を破壊するような関数は設計しないほうが無難です。

この問題のやっかいなところは、ヌケガラとなった変数にアクセスしても、「それなりに」動作してしまうことです。
上記のプログラムも、何事もなかったかのように動作してしまいます。

標準ライブラリのムーブされたオブジェクトへのアクセスは、ランタイムエラーにしてほしいところです。

-----
*** 1-3-4 継承クラスのムーブコンストラクタ [#i3061e17]

以下のプログラムは、潜在的な問題を含んでいます。

#sh(cpp){{
struct BaseClass {
  string baseStr_;
  BaseClass(BaseClass&& bc) : baseStr_(move(bc.baseStr_)) {}
enum class Nationality {
	Japanese, // 日本
	American, // アメリカ
	German,   // ドイツ
	French,   // フランス
	Russian,  // ロシア
	End,      // end of Nationality
};
struct SubClass : BaseClass {
  string subStr_;
  SubClass(SubClass&& sc) : BaseClass(move(sc))
                          , subStr_(move(sc.subStr_)) {}
};
}}

一見して問題のなさそうなプログラムですが、SubClassのムーブコンストラクタが正しく動作しないことがあります。~
問題はココ
#sh(cpp){{
  SubClass(SubClass&& sc) : BaseClass(move(sc))
}}
利用制限として、値が1ずつ増えることと、既存の定義に含まれない終端を定義することです~

BaseClassに、SubClassの引数であるscをmoveして渡しているところです。~
このmoveにより、scのインスタンスはBaseClassの引数に「移動」します。
baseStr_は良いのですが、subStr_も一緒に移動してしまい、受け取り手がいないので闇に葬られてしまいます。

SubClassの次の行で、
#sh(cpp){{
	, subStr_(move(sc.subStr_)) {}	
}}
としていますが、このときすでにscはヌケガラなので、subStr_も空っぽです。
したがって、このプログラムは意図した動作をしない可能性があります。
** 1-2 EnumListの定義 [#f1d8f37b]

「可能性があります」と書いたのは、実はこのケースはほとんどの場合、意図した動作をします。
BaseClassのmoveコンストラクタの引数の評価が遅延されると、subStr_のmove動作は行われません。
引数の評価のタイミングに依存したコードとなっています。

実際に試したところ、単純なプログラムでは正常に動作しましたが、比較的大きなクラスをライブラリ化するなどのいくつかのステップを踏むことで、
BaseClassのムーブコンストラクタに渡すmoveでSubClassのsubStr_が消失してしまう現象を確認しています。

同じプログラムが環境によって動作したりしなかったりは、デバッグを困難にする困った問題です。
予防的な意味でも、下記のようにベースクラスのムーブコンストラクタを呼ぶ場合はキャストしたほうが良いでしょう。

#sh(cpp){{
struct SubClass : BaseClass {
  string subStr_;
  SubClass(SubClass&& sc) : BaseClass(move(static_cast<BaseCLass&&>(sc)))
                          , subStr_(move(sc.subStr_)) {}
};
}}
    // enumの定義をフラグ化およびスキャンするユーティリティ
    template <typename E, E Last, int FirstEnum = 0> 
    struct EnumList {
        using value_type = typename std::underlying_type<E>::type;
        static const int First = FirstEnum;
        static const int Count = static_cast<int>(Last) - First;

-----
*** 1-3-5 VisualStudioはムーブコンストラクタを自動生成してくれない [#k3511e4e]

以下のようなクラスがあります。

#sh(cpp){{
struct Hoge {
    string name_;
};
        // enumを[First,Last)でなめる
        template <typename Proc>
        static void eachEnum(Proc proc) {
            for (value_type n = First; n < static_cast<value_type>(Last); ++n) {
                proc(static_cast<E>(n));
        }
     }
}}

このHogeというクラスには、コンストラクタ、コピーコストラクタ、代入オペレーターなどが自動生成されます。
これで、EnumList<First,Last>::eachEnum(Proc)という書式で列挙対を走査することがでるようになりました。

C++11になり、ムーブ代入演算子も自動生成されるようになったのですが、VisualStudio 2013は現時点でムーブコンストラクタおよびムーブ代入演算子を生成してくれません。

以下のプログラムを実行した場合、
#sh(cpp){{
Hoge foo() {
     Hoge hoge;
     return hoge;
}
* Chapter-2 enumをフラグとして使いたい [#w3909b06]
** 2-1 従来の方法の問題点 [#f1d8f37b]

Hoge hoge;
hoge = foo();
}}
フラグの定義はいにしえのCの時代から大きく変化していません。~
#defineをenumもしくはconst intに置き換えた程度で、使い勝手はむしろ#defineのマクロを駆使したほうが良いぐらいです。

GCCやClangでは、ムーブコンストラクタと代入演算子が自動生成され、Hogeのインスタンスであるstring name_はムーブされます。~
ところが、VisualStudio 2013で同じプログラムを実行すると、string name_は関数foo()のreturn時にコピーコンストラクタによりコピーされ、
hoge = foo(); でコピー代入演算子によりコピーされます。つまり、stringが2回もコピーされる結果となります。
国情報のフラグ化の例

VisualStudioでは、下記のように明示的にムーブコンストラクタとムーブ代入演算子を定義する必要があります。

#sh(cpp){{
struct Hoge {
   string name_;
   Hoge();
   Hoge(Hoge&& h) : name_(move(h.name_)) {}
   Hoge& operator = (Hoge&& h) { name_ = move(h.name_); return *this; }
enum class Nationality {
	Japanese = 1 << 0, // 日本
	American = 1 << 1, // アメリカ
	German   = 1 << 2, // ドイツ
	French   = 1 << 3, // フランス
	Russian  = 1 << 4, // ロシア
};
}}


-----
* Chapter-2 ラムダ式の活用 [#gcd5592d]
国籍のフラグに日本が含まれているか否かをチェックする関数はこうなります

ラムダ式の導入は、C++11での最大のトピックといっても過言ではありません。~
特に、処理が複雑になりがちなゲームプログラミングにおいて、ラムダ式の活用はコード量を削減し、
パフォーマンスを犠牲にすることなくバグの出にくいプログラムが可能になりました。

本章ではゲームプログラミングにおけるラムダ式の活用例を紹介いたします。

-----
** 2-1 コールバックの活用 [#r7bdb006]

C++03でも、boost::lambdaを活用することで、効率的なプログラミングが可能でした。~
しかし、C++11でのラムダ式の導入は、従来のアプローチをはるかに超える便利さがあります。

例として、ボタンを押された時に指定した関数を呼び出す処理を考えてみましょう。

ボタンが押された判定は、bool buttonClicked(); という関数を使用します。

#sh(cpp){{
template<typename Func>
void buttonCheck(Func f) {
  if (buttonClicked()) f();
bool isJapanese(Nationality n) {
 return (static_cast<int>(n) & static_cast<int>(Nationality::Japanese)) != 0;
}
}}

これでOKです。たとえば、ボタンが押された時に、MyClass::playSound(123); という関数を呼び出す処理を行いたい場合、
''static_castが冗長でイヤですね''

#sh(cpp){{
// 呼び出し時
buttonCheck(bind(&MyClass::playSound, this, 123));
}}
さらに条件が少し複雑(ヨーロッパ限定)になると、

と書けばOKです。ちょっとわかり辛いですが、なんとか1行で書けました。~
(C++03のときは、boost::bindのお世話になりました)

では、playSound(123)の後に続けてplaySound(124)を実行して、音を2回鳴らすように改造するにはどうすれば良いでしょう?
buttonCheckに渡すのはあくまでも「関数のポインタ」なので、手続きを関数のポインタに変換することはできません。
仕方がないので、以下のように書きます。
#sh(cpp){{
class MyClass {
...
void playSound2(int a, int b) {
     playSound(a);
     playSound(b);
bool isEuropean(Nationality n) {
 return (static_cast<int>(n) & (
  static_cast<int>(Nationality::German)|
  static_cast<int>(Nationality::French)|
  static_cast<int>(Nationality::Russian)) != 0;
}
...
buttonCheck(bind(&MyClass::playSound2, this, 123, 124));
}}

MyClassにメソッドを追加することになります。
単独の関数でも構いませんが、いずれにしてもbuttonCheckを呼び出す場所と離れたところに処理を記述する必要がありました。
''とてもイヤな感じですね''

ラムダ式を使うと、以下のようにシンプルにかけます。
いまどきのC++でこんなコードは書きたくないです!~

#sh(cpp){{
buttonCheck([this]{ playSound(123); playSound(124); });
}}
**2-2 EnumListを利用したenumerateのフラグ化 [#ve9131f4]

とても簡単に書けるようになりました。この、「簡単でわかりやすい」というのがラムダ式を使う大きなメリットなのです。
先ほどのEnumListクラスにフラグを扱うクラスを追加して、以下のように記述できるようにしました

従来は、コールバックを要求するAPIに対して関数を追加して対応していましたが、ラムダ式を使うとコードサイズをぐっと減らすことができます。

-----
** 2-2 遅延評価 [#wfa8f6a9]

ラムダ式をうまく使うことで、値の評価を実際に使うときまで引き延ばすことが簡単にできるようになりました。

例として、引数を元になんらかの計算を行う tryCalculationという関数があるとします。
ただし、毎回計算を行うわけではなく、needCalculation()がtrueのときだけ計算する関数です。

この関数を、乱数を計算するrand()というメンバ関数を使って呼び出してみます。

#sh(cpp){{
// needCalculation()がtrueのときに、引数をもとに処理を行う関数
void tryCalculation(int value) {
    if (needCalcucation()) {
        doCalculatoin(value); // 引数を用いてなんらかの計算をする処理
    }
using NationalityFlags = EnumList<Nationality, Nationality::End>::Flags

// 日本人か?
bool isJapanese(Nationality n) {
 return NationalityFlags(n)(Nationality::Japanese);
}

struct MyClass {
    int rand();
    ...
    void func() {
        tryCalculation(rand()); // ここでrand()が呼ばれて乱数が生成される
    }
};
}}

特に問題のないプログラムですが、計算を実行する必要がないときにもrand()による乱数生成の処理を行ってしまうのが欠点です。
必要なときだけ乱数の計算を行うように修正すると、

#sh(cpp){{
// needCalculation()がtrueのときに、引数をもとに処理を行う関数
void tryCalculation(function<int()> func) {
   if (needCalcucation()) {
      doCalculatoin(func()); // ここでfunc()が実行されて値を得る
   }
// ヨーロッパ人か?
bool isEuropean(Nationality n) {
 return NationalityFlags(n)(Nationality::German | Nationality::French | Nationality::Russian);
}

struct MyClass {
 int rand();
 ...
 void func() {
      tryCalculation([this]{return rand()}); // rand()の実行は、doCalculationまで遅延される
 }
};
}}

このように、ほんの少しの修正で遅延評価の処理を書くことができます。
スッキリしました。enumの値を|で結合して簡単に比較ができます。~

パフォーマンスを重視するゲームにおいて、遅延評価は大きな効果を発揮します。
フラグがセットされているものだけ走査することもできます

-----
** 2-3 遅延実行 [#he089f8d]

ゲームプログラムでは、一定時間後に特定の処理を行いたいという事が良くあります。
たとえば、「テキストを表示して1秒後に消す」と言った処理です。

遅延実行はラムダ式を使うことで、簡単に記述することが可能です。

#sh(cpp){{
// テキストを表示して1秒後に閉じる処理
void textOpenAndClose() {
     showText();
     delayedExec(1.0, []{ closeText(); });
}
}}
NationalityFlags euro(Nationality::German | Nationality::French | Nationality::Russian)

もう少し複雑な例として、「テキスト1を表示して1.5秒後にテキスト2を表示し、テキストはそれぞれ2秒表示後に閉じる」
という手順は以下のように記述できます。
#sh(cpp){{
void textOpenAndClose() {
  // 指定されたテキストをsec秒間表示して閉じる関数
  auto show2sec = [](int n, float sec) { 
    showText(n);  // テキストnを表示
    delayedExec(sec, [n]{ closeText(n); }) // sec秒後にテキストnを閉じる
  };
  // テキスト1を表示して、2秒後に閉じる
  show2sec(1, 2.0f);
  // 1.5秒後にテキスト2を表示して2秒後に閉じる
  delayedExec(1.5, [&show2sec]{ show2sec(2, 2.0f); });
}
euro.eachEnum([](auto nationality)  {
    hoge(nationality); // ドイツ、フランス、ロシアが実行される
});
}}

ラムダ式を使うことで、処理を局所的に記述でき、コードが簡潔にかけますね。
複雑な手順もわかりやすくコーディングできます。
**2-3 EnumList::Flagsの実装 [#ve9131f4]

指定された時間後に関数を実行する、deleyedExecの中身も紹介しておきます。~
この例ではスレッドを使用していますが、スレッドを使用しない例はChapter-4で紹介します。
EnumListにFlagsというクラスを追加しました

#sh(cpp){{
// 関数を指定された時間だけ遅延実行する
void delayedExec(float sec, function<void()> func) {
    thread th([sec, func] {
        this_thread::sleep(sec*1000.0); // src秒間スリープ(ミリ秒に変換)
        func(); // 関数を実行
    });
    th.detach(); // thを破棄可能にするため、スレッドを切り離す
}
    // enumの定義をフラグ化およびスキャンするユーティリティ
    template <typename E, E Last, int FirstEnum = 0> // , typename Type = int>
    struct EnumList {
        using value_type = typename std::underlying_type<E>::type;
        static const int First = FirstEnum;
        static const int Count = static_cast<int>(Last) - First;
	// Enumをフラグとして扱うクラス。(32個もしくは64個以内)
        template <typename IntT>
        struct FlagsT {
            IntT flags_ = 0;
            FlagsT() : flags_(0) {}
            FlagsT(IntT flags) : flags_(flags) {}
            FlagsT(E value)  { set(value); }
            // 初期化(すべてオフ)
            void clear() { flags_ = 0; }
            // フラグセット
            void set(E value) {
                flags_ |= static_cast<IntT>(1) << static_cast<int>(value);
            }
			void reset(E value) {
				flags_ &= ~(static_cast<IntT>(1) << static_cast<int>(value));
			}
            // セットされているフラグの数を返す
            uint32_t count() const {
                uint32_t count = 0;
                for (value_type n = First; n < static_cast<value_type>(Last); ++n) {
                    if ((flags_ & (1 << n)) != 0) ++count;
                }
                return count;
            }
            // check
            bool operator() (E value) const {
                return (flags_ & (static_cast<IntT>(1) << static_cast<int>(value))) != 0;
            }
            // フラグの連結
            FlagsT& operator | (E value) {
                set(value);
                return *this;
            }
            // フラグがOnのenumをなめる
            template <typename Proc>
            void eachEnum(Proc proc) const {
                for (value_type n = First; n < static_cast<value_type>(Last); ++n) {
                    if ((flags_ & (1 << n)) != 0) {
                        proc(static_cast<E>(n));
                    }
                }
            }
        };
        using Flags = FlagsT<uint32_t>;
        using Flags64 = FlagsT<uint64_t>;

        // enumを[First,Last)でなめる
        template <typename Proc>
        static void eachEnum(Proc proc) {
            for (value_type n = First; n < static_cast<value_type>(Last); ++n) {
                proc(static_cast<E>(n));
            }
        }
}}

* Chapter-3 enumをboost::adaptorsから使いたい [#w3909b06]

-----
** 2-4 ラムダ式の注意点 [#aa693528]
EnumListでenumの操作が楽になりましたが、現実的にはenum変数の定義は構造体の内部にあり、構造体と一緒に扱われることが多いでしょう。~
クラスオブジェクトのリストを走査する場合に、enum変数を値によって振り分けるといったことが良くあります。

便利で一度使い出すと手放せないラムダ式ですが、私が遭遇したハマりポイントをいくつか紹介します。
** 3-1 boost adaptorsでenumを便利に使う [#i3ccf435]

-----
*** 2-4-1 キャプチャのパフォーマンス [#m014a01c]
名前と国籍から構成されるクラスとそのリストがあります

ラムダ式には、任意の変数を渡すことができますが、渡し方によりオーバーヘッドが発生します。

&による参照渡しの場合はポインタとして4バイトないし8バイト、コピー渡しの場合は変数やクラスのサイズ分のメモリがヒープ上に確保されてコピーされます。

大きなクラスオブジェクトやコピーにコストがかかるものは、コピー渡しにしないほうがよいでしょう。
"[=]"の記述のみによるキャプチャは、思わぬオーバーヘッドを見落としてしまうので、できるかぎり自動にしないで変数を列挙するようにしています。

C++11では、コピー不可のオブジェクトを実体として渡すことはできません。参照として渡すことになるので、生存期間の管理が必要です。

C++14からはmoveによるキャプチャがサポートされる予定です。~
C++14からサポートされるmoveキャプチャの例
#sh(cpp){{
  string hoge = "hoge";
  auto func = [h = move(hoge)]{ //hogeがhにmoveされる
    cout << h << endl;
  };
}}

-----
*** 2-4-2 shared_ptrのキャプチャ問題 [#se8c5f9a]

参照によるキャプチャはオブジェクトの寿命の問題があるため、解決方法としてshared_ptrを使うことが考えられます。

ただし、shared_ptrをそのままキャプチャすると、参照カウントの問題が発生することがあるので注意が必要です。

下の例では、MyClassの参照カウントはゼロにならず、ゾンビオブジェクト化してメモリリークを引き起こします。
#sh(cpp){{
struct MyClass {
  function<void()> callback_;
  ...
  void hoge();
struct Human {
	string name_; // 名前
	Nationality nationality_; // 国籍
};
...
// shared_ptrのインスタンスを作成
auto myptr = make_shared<MyClass>();
// callback_関数に、自分のshared_ptrをキャプチャしてラムダ式を登録
myptr->callback_ = [myptr] { myptr->hoge(); }
//                  ~~~~~
// このmyptrは、callback_にコピーして保存されるため、MyClassは自身の参照を保持することになりゾンビとなる。
}}

単独な循環参照なら比較的気がつきやすいですが、多くのクラスを介した三つ巴の循環参照を引き起こす場合は発見が困難です。
しかも、プログラムはメモリを食いつぶしながらも正常に動作してしまうので、発見が遅れる困ったバグとなります。

この問題は、weak_ptrを利用することで解決できます。
#sh(cpp){{
...
// shared_ptrのインスタンスを作成
auto myptr = make_shared<MyClass>();
// callback_関数に、自分のweak_ptrをキャプチャしてラムダ式を登録
weak_ptr<MyClass> wptr = myptr;
myptr->callback_ = [wptr] { if (auto p = wptr.lock()) p->hoge(); }
//                  ~~~~~
// werk_ptrは自身で保持しても循環参照とならない
vector<Human> people; // Humanのリスト
}}

一行増えてしまいますが、shared_ptrをキャプチャする場合は必ずweak_ptrを利用することをお勧めします。
boost::adaptorsを使用しない場合、peopleにある日本国籍のHumanのみ処理する場合、こうなります

C++14の場合は、以下のように書けるので便利です。
#sh(cpp){{
...
// shared_ptrのインスタンスを作成
auto myptr = make_shared<MyClass>();
// callback_関数に、自分のweak_ptrをキャプチャしてラムダ式を登録
myptr->callback_ = [wptr = weak_ptr<MyClass>(myptr)] { if (auto p = wptr.lock()) p->hoge(); }
//                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//                  c++14ではこのように書ける
for (auto& human : people) {
    if (human.nationality_ != Nationality::Japanese) continue;
    hoge(human); /// 何らかの処理
};
}}

-----
* Chapter-3 コピーコンストラクタの廃止によるパフォーマンスアップ [#ld5a09f6]
boost::adaptors::filteredを使うとこうなります

ゲームプログラムでは処理速度の向上が必要不可欠です。「富豪的プログラミング」は許されません。~
もし、処理速度を全く問題にしないゲームを作るのならば、スクリプトやJava,C#などの他の言語の方が良い選択肢かもしれません。

ムーブセマンティクスの導入で、オブジェクトの無駄なコピーを省くことができるようになりました。
しかし、既存のコードをリファクタリングして無駄なコピーを見つけるのは手間がかかります。

そこで、既存のクラスを簡単にリファクタリングする方法として、コビーコンストラクタの廃止というアプローチを紹介します。

-----
** 3-1 コピーコンストラクタをムーブコンストラクタに置き換える [#wbb67a93]

このような従来のコードがあるとします。
#sh(cpp){{
struct Hoge {
  string ins_; // クラスインスタンス
  Hoge();
  Hoge(const Hoge& h) : ins_(h.ins_) {} // コピーコストラクタ
  Hoge& operator = (const Hoge& h) { ins_ = h.ins_; } // 代入演算子
using boost::adaptors::filtered;
for (auto& human : people | filtered([](auto& human) { return human.nationality_ == Nationality::Japanese; })) {
    hoge(human); /// 何らかの処理
};
}}

ごく一般的なクラスの定義だと思いますが、これを以下のように変えてしまいます。
#sh(cpp){{
struct Hoge {
  string ins_;
  Hoge();
  Hoge(const Hoge&) = delete;                          // コビーコストラクタ廃止
  Hoge(Hoge&& h) : ins_(move(h.ins_)) {}               // ムーブコンストラクタ
  Hoge& operator = (const Hoge&) = delete;             // コピー代入演算子廃止
  Hoge& operator = (Hoge&& h) { ins_ = move(h.ins_); } // ムーブ代入演算子
  // 自分の複製を作るメンバ関数(複製の生成が必須の場合)
  Hoge clone() const {
    Hoge h;
    h.ins_ = ins_; // インスタンスをコピー
    return h;
  }
};
}}
filteredを使用するとちょっとカッコイイですね。
でも、冗長さはあまり変わりません。

コピーコンストラクタと代入演算子を使用禁止にして、代わりにムーブコンストラクタとムーブ代入演算子を定義します。~
クラスオブジェクトの複製が必要な場合、clone()メンバ関数を定義します。

この変更を行った後、ビルドしてエラー箇所を全部直せば、このクラスのコピーはclone()以外では実行されなくなります。~
もし、コピーを嫌ってポインタや参照でやりとりしていた箇所があったとすると、コードをスッキリ直すことができるでしょう。
** 3-2 EnumAdapter [#v0ed8b41]

もちろん、このクラスをvector<>,map<>などSTLのコンテナに格納することも可能です。 
ただし、vectorの場合はpush_backは使用できません。すべてemplace_backに置き換えます。
そこで、boost::adaptoersでenumを扱うためのヘルパークラス EnumAdapter を作りました
こんな具合に書けます

無駄なコピーを行っている箇所をコンパイラが見つけてくれます。
この簡単な変更で、C++03で書かれた従来のゲームプログラムが2割以上高速化したという事例もあります。

-----
** 3-2 shared_ptrをunique_ptrに置き換える [#y412f619]

shared_ptrはとても便利ですが、それなりのオーバーヘッドがあります。
リファレンスカウントを増減する際、スレッド同期を行う為の処理が入るため、ループの内部やタイミングがクリティカルな箇所での使用は要注意です。

ポインタを本当にシェアしたい場合は仕方がないですが、単にオブジェクトの解放を自動化したいだけならば、unique_ptrのほうが断然高速に動作します。

unique_ptrはコピーできないため、従来は使用範囲が制限されていましたが、ムーブセマンティクスの導入で移動が可能になり使い勝手がぐっと向上しました。
vector<>などの標準ライブラリのコンテナにも入れることができます。

シェアしないポインタをすべてunique_ptrに置き換えることでパフォーマンスの向上が図れます。

シェアしないで済みそうなポインタはすべてunique_ptrに置換して、ビルドエラーを修正するといったリファクタリングでも効果があるでしょう。

-----
* Chapter-4 応用編 描画ループの処理 [#uf2480b8]

ほとんどのゲームプログラムは、描画ループというものが存在します。

ハードウエアに依存しますが、一般的に60分の1秒(16.67ms)を周期としてレンダリング処理が行われます。

ゲームプログラムのメインルーチンは、以下のような構造になります。

#sh(cpp){{
int main() {
  // finished()がtureになるまでループ
  while(!finished()) {
    update(); // ゲームの処理
    render(); // 描画処理
  }    		     
}
using boost::adaptors::filtered;
for (auto& human : people | filtered(+Nationality::Japanese)) {
    hoge(human); /// 何らかの処理
};
}}

ゲームのメインルーチンは、毎秒60回コールされるupdate()から呼ばれるので、時間のかかる処理は分割するなどの工夫が必要になります。
スッキリしましたね。 Nationality列挙体の単項演算子'+'がミソです。~
もうおわかりだと思いますが、こんな風にも書けます。

スレッドを利用することで、メインループとは独立した処理を書くことができますが、マルチスレッドのプログラミングにはコストかかります。
ファイルのロードや通信などの時間のかかる処理はスレッド化するとしても、ゲームのメインの部分はメインループで処理を行うのが一般的でしょう。

メインループから呼ばれるメインスレッドでの処理を簡潔に行うため、以下のようなアプローチがあります。

+イベントドリブン型モデル
--長所: プログラムが書きやすい
--短所: 処理時間のかかるプログラムは書けない(スレッドを起こすなどの工夫が必要)
+コルーチンによる擬似マルチタスク
--長所: 処理時間のかかるプログラムもかける
--短所: メモリ管理、スタック領域の管理が難しい。

いずれも一長一短あり併用する場合もありますが、ここではイベントドリブン型の処理を取り上げます。

-----
** 4-1 スレッドを使用しない遅延実行関数 [#ia179242]

Chapter 2-3で紹介した、遅延実行を行う関数delayedExec()を、スレッドを使わないモデルで実装してみます。

#sh(cpp){{
// 遅延実行を登録/実行する関数
// 引数なしで呼ぶと実行処理(通常はメインループのupdate()から呼ぶ)
void delayedExec(float sec = 0.0f, function<void()> func = nullptr) {
  // 遅延実行する関数を保持するコンテナ 要素の追加でイテレータを破壊てほしくないのでlistを使用
  static list<tuple<int, function<void()>>> queue;
  if (sec) {
    // 遅延実行関数の登録
    int frame = sec * 60.0f; // 秒からフレーム数に変換
    queue.emplace_back(make_tuple(frame, move(func)));
    return;
  }
  // 引数を省略した時は実行処理
  for (auto it = begin(queue); it != end(queue); ) {
    int& count = it->get<0>();
    if (--count == 0) { // 時間が来た!
      it->get<1>()();// 遅延実行 この関数の中からdeleydExecを呼んでもOK
      it = queue.erase(it);
    }
    else { // まだまだ
      ++it;
    }
  }
// 特定条件での走査 (日本人とフランス人を対象とする)
for (auto& h : people | filtered(Nationality::Japanese | Nationality::French)){
    hoge(human); /// 何らかの処理
}
}}

この関数は、キューに関数を登録する部分と、キューに溜まっている関数を実行する2つの部分で構成されています。~
もちろん、クラス化してもっとスッキリ記述できますが、あくまでも例ですのでその点は突っ込まないでください。
サッパリしてますね。以下の従来の書き方と比べてみてください

メインループから呼ばれるupdate()の中で、関数を実行するための処理を一行入れます
#sh(cpp){{
...
void update() {
     ...
     delayedExec(); // タイミングの計算と関数の実行
     ...
}}

これだけで、「テキスト1を表示して1.5秒後にテキスト2を表示し、テキストはそれぞれ2秒表示後に閉じる」
という手順をスレッドを使わずに記述できます。
#sh(cpp){{
void textOpenAndClose() {
  // 指定されたテキストを2秒間表示して閉じる関数
  auto show2sec = [](int n, float sec) { 
    showText(n);  // テキストnを表示
    delayedExec(sec, [n]{ closeText(n); }) // sec秒後にテキストnを閉じる
  };
  // テキスト1を表示して、2秒後に閉じる
  show2sec(1, 2.0f);
  // 1.5秒後にテキスト2を表示して2秒後に閉じる
  delayedExec(1.5, [&show2sec]{ show2sec(2, 2.0f); });
// 特定条件での走査 (日本人とフランス人を対象とする)
for (auto& h : people | filtered([](auto& h) { 
	return h.nationality_ == Nationality::Japanese || h.nationality_ == Nationality::French; })){
    hoge(human); /// 何らかの処理
}
}}

** 4-2 タスクマネージャの紹介 [#q906f797]
よく見ると、filterd(+Nationality::Japanese) が、Human構造体の要素である nationality_ をどうやって見つけているのか、不思議になるとおもいます。~
もちろん、これには種も仕掛けもございます。

C++11の新機能を活用したゲーム用タスクマネージャーを作成しましたので、サンプルプログラムとし公開します。
** 3-3 構造体のメンバ変数を型から取得するためのgetter定義 [#lcbdd3ed]

主な特徴は、
種明かしをすると、以下の一行が追加されています

+ タスククラスはコピー不可でムーブ可能なクラスです。
+ タスククラスはヒープを一切使用しません。(new/mallocしている箇所はありません)
+ ゲームの流れを視覚的に記述できます。
+ 名前付きオブジェクトを使用しています。
+ シングルスレッドで動作します。

となっています。

各処理は「タスク」という名前付きオブジェクトで管理され、タスク間の連携をラムダ式とイニシャライザリストを使って局所的に記述できるようになっています。

以下のプログラムが、ゲームの流れ定義する処理部分です。
「タイトルロゴ」「メインメニュー」「ゲーム」「セッテイング」「エンディング」というそれぞれのタスクの流れを定義しています。

#sh(cpp){{
  TaskQueue().run({
              "titleLogo", titleLogo, { 
                  "mainmenu", mainMenu, {
                    { gameMain,    { ending, "mainmenu" } },
                    { settingMenu }
                }
              } });
struct Human {
    string name_; // 名前
    Nationality nationality_; // 国籍
    FSG_MAKE_GETTER(name_, nationality_);
};
}}

'titleLogo', 'mainMenu', 'gameMain', 'ending', 'settingMenu' はクラスオブジェクトではなく関数です。
つまり、この部分にラムダ式を書くことができます。
''悪魔のマクロ定義ですね''

これらの関数をラムダ式で表現すると以下のようになります。
まだ悪魔に魂を売り渡したくない人は、以下のように記述してください

#sh(cpp){{
  TaskQueue().run({
    "titleLogo", [](TaskArgs& args) {
      // titleLogoの処理
    },
    { // titleLogoの引数
      "mainmenu", [](TaskArgs& args) {
        // mainMenuの処理
      },
      { // titleLogoの引数
        { // gameMainタスク
	  [](TaskArgs& args) {
          // gameMainの処理
          }, // gameMainの引数
          { [](TaskArgs&) {
            // endingの処理
            }, 
            {"mainmenu"}
          },
          { // settingMenuタスク
	    [](TaskArgs&){
              // settingMenuの処理
            }
          }
        }
      }
struct Human {
    string name_; // 名前
    Nationality nationality_; // 国籍
    template<typename T> const T& get() const {
        return *boost::fusion::find<const T&>(boost::fusion::vector_tie(name_, nationality_));
    }
  });
};
}}

このように直接処理を記述することができます。
このgetterは、get<型>() からクラス構造体のメンバ変数にアクセスできる、とても便利な関数です。~

このサンプルプログラムは、以下のクラスから構成されています。
** 3-4 EnumAdapterの実装 [#m3f00e59]

+ NamedObject 名前付きオブジェクト基底クラス 
+ Task        タスク処理
+ TaskArgs    タスクの引数 
+ TaskQueue   タスクの実行管理
EnumAdapterの実装です

詳細はソースコードをみてください。

これらのクラスを利用したサンプルプログラムです。

ソースコードは
[[こちら>http://ssa.techarts.co.jp/index.php?plugin=attach&pcmd=open&file=c%2B%2Badvent_sample.zip&refer=C%2B%2B%20Advent%20Calender%202014]]
です

時間の関係で、Clang3.4でのテストしかしていません。以下のコマンドでビルドできます。
 c++ -o t1 -g -Wall -Wunused-variable -std=c++11 TaskTest.cpp


#sh(cpp){{
// C++AdventCalender 2014 22th
// C++11によるゲームプログラミング
// Created by TECHNICAL ARTS h.godai 2014
//
#include <functional>
#include <deque>
#include <vector>
#include <memory>
#include <string>
#include <map>
#include <boost/optional.hpp>
	// Enumlateをorで結合し、条件判定を行うためのアダプタクラス
	template <typename E, typename Pred, typename FlagT = uint32_t>
	struct EnumPredAdapter {
        using value_type = FlagT;
		value_type flags_ = 0;
		// constructor
		EnumPredAdapter(value_type v) : flags_(v) {}
		EnumPredAdapter(E a) : flags_(toFlag(a)) {}
		EnumPredAdapter(E a, E b) : flags_(toFlag(a) | toFlag(b)) {}
 	    // enum値からフラグにする
		static value_type toFlag(E value) { return 1 << static_cast<value_type>(value); }
		
		// operator
		EnumPredAdapter operator | (E a) { return flags_ | toFlag(a); }
		EnumPredAdapter operator | (EnumPredAdapter a) { return flags_ | a.flags_; }
		EnumPredAdapter operator & (EnumPredAdapter a) { return flags_ & a.flags_; }
		template<typename T>
		bool operator == (const T& src) const { return this->operator&() (src); }

#include "NamedObject.hpp"
#include "Task.hpp"
#include "TaskQueue.hpp"

using namespace std;
using namespace ts::namedobj;

// stub関数
bool keyWait();          // キー入力待ち
void initializeScreen(); // 画面を初期化する
int selectedMenu();      // 選択されたメニュー番号を返す
bool gameMainLoop();     // ゲームのメインルーチン

int main() {
  // タイトルロゴを表示するタスク
  auto titleLogo = [](TaskQueue& tq, TaskArgs& ar){
	assert(ar.size() > 0);
	initializeScreen();
	ar.at(0).valid("titlelogo");
	tq.waitPred(ar.at(0), [] { return keyWait(); });
	return TaskStatus::RemoveTask;
  };

  // メインメニューのタスク 
  auto mainMenu = [](TaskQueue& tq, TaskArgs& ar) {
	cerr << "mainMenu" << endl;
	switch (selectedMenu()) {
	default:
	return TaskStatus::ContinueTask;
	case 1:
	  // 引数の最初のタスクを実行する
	  ar.at(0).valid("mainMenu");
	  tq.addTask(ar.at(0).clone());
	  return TaskStatus::RemoveTask;
	case 2:
	  // 引数の二番目のタスクを実行する
	  ar.at(1).valid("mainMenu");
	  tq.addTask(ar.at(1).clone());
	  return TaskStatus::RemoveTask;
	case 3:
	  // 終了する
	  cerr << "finish! ===============" << endl;
	  tq.finish();
	  return TaskStatus::RemoveTask;
	}
  };

  // エンディングのタスク
  auto ending = [](TaskQueue& tq, TaskArgs& ar) {
	// do ending
	cerr << "ending" << endl;
	ar.at(0).valid("ending");
	// keyWait()がtrueを返したら、最初の引数のタスクを実行する
	tq.waitPred(ar.at(0), [] { return keyWait(); });
	return TaskStatus::RemoveTask;
  };

  // ゲームメインルーチンのタスク
  auto gameMain = [](TaskQueue& tq, TaskArgs& ar) {
	// do main
	cerr << "gameMain" << endl;
	// gameMainLoop()がtrueを返したら、最初の引数のタスクを実行する
	tq.waitPred(ar.at(0), [] { return gameMainLoop(); });
	return TaskStatus::RemoveTask;
  };

  // セッティングメニューのタスク
  auto settingMenu = [](TaskQueue& tq, TaskArgs& ar) {
	cerr << "settingMenu" << endl;
	Task ptask(ar.parent_);
	// 何かキーが押されたら、呼び出し元のタスクを実行する
	tq.waitPred(ptask, [] { return keyWait(); });
	return TaskStatus::RemoveTask;
  };

  // タスクマネージャーにタスクを登録
  TaskQueue taskqueue;
  taskqueue.run({
	"titleLogo",
	  titleLogo, {
	  "main", mainMenu,{
		{ // game main
		  gameMain, 
			{ending, {"main"} }
		  
		template<typename T>
		bool operator () (const T& src) const {
			return Pred::comp(toFlag(src.get<E>()), flags_);
		}
	  , { // setting menu
		  settingMenu
		}
	  }
	}
	});
	};
	struct EnumPredAny { template<typename VT> static bool comp(VT a, VT b) { return (a & b) != 0; } };
	struct EnumPredNot { template<typename VT> static bool comp(VT a, VT b) { return (a & b) == 0; } };

  // ゲームのメインループ
  uint32_t frame = 0;
  while(!taskqueue.finished()) {
	cerr << "Frame:" << ++frame << endl;
	taskqueue.update();
	//draw(); // ゲームの場合レンダリングの処理が入る
  }
	template <typename T, typename E, typename Pred, typename VT = int>
	inline bool operator == (const T& src, EnumPredAdapter<E, Pred, VT> v) { return v(src); }
	template <typename T, typename E, typename Pred, typename VT = int>
	inline bool operator != (const T& src, EnumPredAdapter<E, Pred, VT> v) { return !v(src); }
}

// 引数で指定したT型の変数をget<T>()で取得するためのマクロ 
// eg.
// struct { int a; float b, string c; FSG_MAKE_GETTER(a,b,c) };
// get<int>()でa、get<float>()でb、get<string>()でcが取得できる
#define FSG_MAKE_GETTER(...) \
  template<typename T> const T& get() const {\
    return *boost::fusion::find<const T&>(boost::fusion::vector_tie(__VA_ARGS__)); }
}}


* おわりに [#m1e65f32]
* おわりに [#end]

長い文章を最後まで読んでいただいてありがとうございました。

とりとめもない話になってしまい、まとまりがありませんが、少しでも何かのお役に立てれば幸いです。
簡単なクラスですが、enum変数の操作をスッキリかけるようになりました。boost::adaptoresの処理は、C#のLinqライクな感じで好きですが、手軽に使うにはまだまだ知識が追い付かず調べてからでないと使い方が分かりません。~
今回も、boost::fusionの使い方について、高橋晶さんに助けていただきました。ありがとうございます。
fusionもとても便利なクラスなので、機会があればどんどん使っていきたいとおもいます。

今後も、ゲームプログラミングのTIPSとして、ドキュメント化していく作業を続けたいと思います。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS