C++ Template Meta Programming の紹介@社内勉強会

5,440 views

Published on

Published in: Technology
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,440
On SlideShare
0
From Embeds
0
Number of Embeds
46
Actions
Shares
0
Downloads
31
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

C++ Template Meta Programming の紹介@社内勉強会

  1. 1. C++ Template Meta Programming の、さわりだけ... CORE 北海道カンパニー 勉強会 2013/7/26 松浦 13年7月27日土曜日
  2. 2. C++テンプレートを使ったメタプロ グラミングについて紹介します! まあ、そんなのもあるんだー、ふー ん、くらいな感じで 今日は、 13年7月27日土曜日
  3. 3. 13年7月27日土曜日
  4. 4. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 目次 13年7月27日土曜日
  5. 5. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  6. 6. ロジックを直接コーディングするの ではなく、あるパターンをもったロ ジックを生成する高位ロジックによ ってプログラミングを行う方法、ま たその高位ロジックを定義する方法 のこと。........wikipedia 13年7月27日土曜日
  7. 7. いみが まったくわからない いやん♡ 13年7月27日土曜日
  8. 8. プログラムを生成する プログラム、ってことで いいと思うぽよ。 ようは 13年7月27日土曜日
  9. 9. 例えばYACC expression : term | expression ‘+’ term {$$=$1+$2;} | expression ‘-’ term {$$=$1-$2;} ; term : factor | term ‘*’ factor { $$ = $1 * $2; } | term ‘/’ factor { $$ = $1 / $2; } ; factor : INTEGER | group ; group : ‘(’ expression ‘)’ ; 13年7月27日土曜日
  10. 10. YACC .y YACC .c 13年7月27日土曜日
  11. 11. YACC .y YACC .c ドメイン言語 (DSL) ホスト言語 13年7月27日土曜日
  12. 12. boost.spirit expr = ( term[expr.val = _1] >> '+' >> expr[expr.val += _1]) | ( term[expr.val = _1] >> '-' >> expr[expr.val -= _1]) | term[expr.val = _1] ; term = ( factor[term.val = _1] >> '*' >> term[term.val *= _1]) | ( factor[term.val = _1] >> '/' >> term[term.val /= _1]) | factor[term.val = _1] ; factor = integer[factor.val = _1] | ( '(' >> expr[factor.val- _1] >> ')' ) ; 13年7月27日土曜日
  13. 13. boost.spirit .cpp 13年7月27日土曜日
  14. 14. boost.spirit .cppドメイン言語 ホスト言語 13年7月27日土曜日
  15. 15. boost.spirit .cppドメイン言語 ホスト言語 EDSL(埋め込みドメイン言語) 13年7月27日土曜日
  16. 16. boost.spirit .cppドメイン言語 ホスト言語 EDSL(埋め込みドメイン言語) YACC相当のものは? 13年7月27日土曜日
  17. 17. boost.spirit .cppドメイン言語 ホスト言語 EDSL(埋め込みドメイン言語) YACC相当のものは? テンプレート・メタプログラミング 13年7月27日土曜日
  18. 18. なぜC++でメタプロ? 別の構文規則を学ぶ必要がない 他のメタプロとの相互運用 余分な構築ステップ不要 品質、再利用、可搬性 13年7月27日土曜日
  19. 19. とはいえ boost.spiritのような究極のメタプロ グラミングの話は割愛します。 このあとの章では、C++メタプロを 支える基本的な部分だけお話します。 (ちゃんと話せる自信がないというのはナイショぽよ 13年7月27日土曜日
  20. 20. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  21. 21. 普通のジェネリック // C# List<string> list = new List<string>(); list.add("hoge"); list.add("page"); // Java List<String> list = new ArrayList<String>(); list.add("hoge"); list.add("page"); //C++ list<string> list; list.insert("hoge"); list.insert("page"); 13年7月27日土曜日
  22. 22. 非型テンプレート //C++ template<int N> struct pow { static const int value = N*N; }; int n = pow<3>::value; // n = 3*3; 13年7月27日土曜日
  23. 23. 型の操作 ポインタを追加する //C++ template<class T> struct add_pointer { typedef T* type; }; int n = 10; // int* p = &n; add_pointer<int>::type p = &n; 13年7月27日土曜日
  24. 24. C++テンプレート コンパイル時に計算してしまう(実行 時コスト0)。 非型テンプレート 型操作 .....などなど 13年7月27日土曜日
  25. 25. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  26. 26. add_pointerの例 ん?? // int* p = &n; add_pointer<int>::type p1 = &n; // これはエラー:int** p2 = &n; add_pointer<int*>::type p2 = &n; 13年7月27日土曜日
  27. 27. そこで特殊化 template<class T> struct add_pointer { typedef T* type; }; // そもそもポインタだったらこっち template<class T> struct add_pointer<T*> { typedef T* type; }; int n = 10; // int* p = &n; add_pointer<int>::type p1 = &n; // めでたし add_pointer<int*>::type p2 = &n; 13年7月27日土曜日
  28. 28. テンプレート特殊化 テンプレート特殊化により、 コンパイル時に条件分岐を行 うことができる。 13年7月27日土曜日
  29. 29. コンパイル時 if文 template<bool b, class T1, class T2> struct If_; template<class T1, class T2> struct If_<true,T1,T2> { typedef T1 type; // 条件が真ならT1を使用する }; template<class T1, class T2> struct If_<false,T1,T2> { typedef T2 type; // 条件が偽ならT2を使用する }; If_<sizeof(long) > sizeof(char), char, long>::type x; // char x; 13年7月27日土曜日
  30. 30. コンパイル時assert // 宣言だけ template<bool b> struct Static_assert; // true版のみ定義しfalse版は定義しない template<> struct Static_assert<true>{}; #define STATIC_ASSERT(b) { sizeof( Static_assert<b> ); } void foo() { STATIC_ASSERT(sizeof(long) == 4); char dest[32]; char src[16]; STATIC_ASSERT(sizeof(dest) >= sizeof(src)); ::memcpy(dest,src,sizeof(src)); } 13年7月27日土曜日
  31. 31. C++テンプレート コンパイル時に計算してしまう(実行 時コスト0)。 非型テンプレート 型操作 特殊化による条件分岐 13年7月27日土曜日
  32. 32. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  33. 33. 普通に再帰で階乗計算 int factorial(int N) { return N==0 ? 1 : N*factorial(N-1); } int n = factorial(3); // 6 13年7月27日土曜日
  34. 34. 再帰テンプレートで // 階乗を求める template <int N> struct factorial_t { static const int value = N*factorial_t<N-1>::value; }; // N==0の場合は特殊化する template <> struct factorial_t<0> { static const int value = 1; }; int n2 = factorial_t<3>::value; // n2 = 6; 13年7月27日土曜日
  35. 35. 再帰テンプレート 再帰テンプレートにより、コ ンパイル時に繰り返し処理を 行うことができる。 13年7月27日土曜日
  36. 36. 余談 C++テンプレートはチューリング 完全である(制限:再帰に限界あり) C++ Templates are Turing Complete http://ubietylab.net/ubigraph/content/ Papers/pdf/CppTuring.pdf 13年7月27日土曜日
  37. 37. C++テンプレート コンパイル時に計算してしまう(実行時コ スト0)。 非型テンプレート 型操作 特殊化による条件分岐 再帰テンプレートによる繰り返し 13年7月27日土曜日
  38. 38. このへんから ちょっとだけ応用な感じです。 ちょっとだけよ♡ 13年7月27日土曜日
  39. 39. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  40. 40. メタ関数とは add_pointer<int>::type pi; 関数名 int v = factorial_t<3>::value; パラメータ 戻り値(型) 関数名 パラメータ 戻り値(値) 13年7月27日土曜日
  41. 41. 高階関数を考えてみよう まずは普通のテンプレート関数 f(f(x)) の結果を返すtwice template<class F, class X> struct twice { static int value(const X& x ){ return F::apply(F::apply(x)); } }; struct div2 { static int apply(int x) { return x/2; } }; std::cout << twice<div2,int>::value(8); // 2 13年7月27日土曜日
  42. 42. 高階メタ関数 template<class F, int N> struct twice { static const int value = F::template apply< F::template apply<N>::value >::value; }; struct div2 { template<int N> struct apply { static const int value = N/2; }; }; std::cout << twice<div2,8>::value; // 2 13年7月27日土曜日
  43. 43. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  44. 44. こんなことしたい それぞれの型のインスタンスを用意してメソ ッドを呼び出したい。 struct A { std::string name() const { return "A!"; } }; struct B { std::string name() const { return "B!"; } }; struct C { std::string name() const { return "C!"; } }; struct D { std::string name() const { return "D!"; } }; /* こんなことしたい A a; a.name(); B b; b.name(); C c; c.name(); D d; d.name(); とか for( v : [A,B,C,D] ) print( v.name() ); // 擬似コードです */ 13年7月27日土曜日
  45. 45. JavaやC#、ObjC あたりのアプローチ リフレクションを使う。 Classクラスのようなメタクラスの配 列を使って動的生成する、とかね。 C++のリフレクションは貧弱。 どうしよう。 13年7月27日土曜日
  46. 46. C++のアプローチ メタプログラミングで型のリスト(型シーケ ンス)を用意し、各型にアクセスする仕掛け を考えてみる。 TypeList<A,B,C,D>::type; 13年7月27日土曜日
  47. 47. C++のアプローチ メタプログラミングで型のリスト(型シーケ ンス)を用意し、各型にアクセスする仕掛け を考えてみる。 TypeList<A,B,C,D>::type; このへんをどうするか?? 13年7月27日土曜日
  48. 48. 型シーケンス template<class First, class Rest> struct Cons { typedef First first; typedef Rest rest; }; struct ConsNil {}; // 型シーケンス TypeList<T1,T2,T3,T4> template<class T1, class T2, class T3, class T4> struct TypeList { typedef Cons<T1,Cons<T2,Cons<T3,Cons<T4,ConsNil> > > > type; }; 13年7月27日土曜日
  49. 49. 型シーケンス template<class First, class Rest> struct Cons { typedef First first; typedef Rest rest; }; struct ConsNil {}; // 型シーケンス TypeList<T1,T2,T3,T4> template<class T1, class T2, class T3, class T4> struct TypeList { typedef Cons<T1,Cons<T2,Cons<T3,Cons<T4,ConsNil> > > > type; }; このへんがキモ 13年7月27日土曜日
  50. 50. むずくないよ template<class First, class Rest> struct Cons { typedef First first; typedef Rest rest; }; struct ConsNil {}; template<class T1, class T2, class T3, class T4> struct TypeList { typedef Cons<T1,Cons<T2,Cons<T3,Cons<T4,ConsNil> > > > type; }; // typedef First first; : T1 // typedef Rest rest; : Cons<T2,Cons<T3,Cons<T4,ConsNil> > > // typedef First first; : T2 // typedef Rest rest; : Cons<T3,Cons<T4,ConsNil> > // typedef First first; : T3 // typedef Rest rest; : Cons<T4,ConsNil> // typedef First first; : T4 // typedef Rest rest; : ConsNil ← ターミネータ 13年7月27日土曜日
  51. 51. あとは繰り返す処理 // typedef First first; : T1 // typedef Rest rest; : Cons<T2,Cons<T3,Cons<T4,ConsNil> > > // typedef First first; : T2 // typedef Rest rest; : Cons<T3,Cons<T4,ConsNil> > // typedef First first; : T3 // typedef Rest rest; : Cons<T4,ConsNil> // typedef First first; : T4 // typedef Rest rest; : ConsNil ← ターミネータ template<class CONS> struct for_each { template<class FUNC> static void apply( const FUNC& f ) { typename CONS::first v; f( v ); for_each<typename CONS::rest>::apply(f); } }; 13年7月27日土曜日
  52. 52. ターミネータ忘れてた! template<class CONS> struct for_each { template<class FUNC> static void apply( const FUNC& f ) { typename CONS::first v; f( v ); for_each<typename CONS::rest>::apply(f); } }; // ターミネータ用に特殊化 template<> struct for_each<ConsNil> { template<class FUNC> static void apply( const FUNC& ){ } }; 13年7月27日土曜日
  53. 53. 使ってみよう struct A { std::string name() const { return "A!"; } }; struct B { std::string name() const { return "B!"; } }; struct C { std::string name() const { return "C!"; } }; struct D { std::string name() const { return "D!"; } }; struct Printer { template<class T> void operator()(const T& v) const { std::cout << v.name() << std::endl; } }; void foo() { for_each<TypeList<A,B,C,D>::type>::apply( Printer() ); } // for( v : [A,B,C,D] ) print( v.name() ); ↑ 似てる // A! // B! // C! // D! 13年7月27日土曜日
  54. 54. リフレクションが無くても テンプレートでいろいろ出来ちゃう。 しかも多くをコンパイル時に静的に。 boost.mpl には型のためのコンテナ、 イテレータ、アルゴリズムがある。遅 延評価、ラムダなども。正直、あたまおかしい(笑) 13年7月27日土曜日
  55. 55. メタプログラムとは何か? テンプレートの基礎 テンプレート特殊化 再帰テンプレート メタ関数 型シーケンス さいごに 13年7月27日土曜日
  56. 56. 新たなパラダイムに出会えたね! 構造化 データ指向 オブジェクト指向 ジェネリック 関数型 ・・・ メタプログラミング 13年7月27日土曜日
  57. 57. 余談 GoFデザインパターンはオブジェクト指向だ けか? 例えば Abstract FactoryパターンやVisitor パタ ーンは、メタプロと相性が良い。 継承でなくポリシとか。 メタプロと関数型? どちらも状態を持たない 13年7月27日土曜日
  58. 58. まとめ C++テンプレート機能により、コン パイル時の処理を書くことが出来る。 ライブラリの実装では多用される。 でも、正直読みにくいし難解。 C++11ではconstexprにより多少ましになっている。 13年7月27日土曜日
  59. 59. おつかれさま! もうおわり?♡ ふう... 13年7月27日土曜日

×