c++ template meta programming の紹介@社内勉強会
TRANSCRIPT
C++ Template MetaProgramming
の、さわりだけ...
CORE 北海道カンパニー 勉強会
2013/7/26 松浦
13年7月27日土曜日
C++テンプレートを使ったメタプログラミングについて紹介します!
まあ、そんなのもあるんだー、ふーん、くらいな感じで
今日は、
13年7月27日土曜日
13年7月27日土曜日
メタプログラムとは何か?テンプレートの基礎
テンプレート特殊化
再帰テンプレート
メタ関数
型シーケンスさいごに
目次
13年7月27日土曜日
メタプログラムとは何か?テンプレートの基礎
テンプレート特殊化
再帰テンプレート
メタ関数
型シーケンス
さいごに
13年7月27日土曜日
ロジックを直接コーディングするのではなく、あるパターンをもったロジックを生成する高位ロジックによってプログラミングを行う方法、またその高位ロジックを定義する方法のこと。........wikipedia
13年7月27日土曜日
いみが まったくわからない
いやん♡
13年7月27日土曜日
プログラムを生成するプログラム、ってことでいいと思うぽよ。
ようは
13年7月27日土曜日
例えばYACCexpression : 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日土曜日
YACC
.y YACC .c
13年7月27日土曜日
YACC
.y YACC .c
ドメイン言語(DSL)
ホスト言語
13年7月27日土曜日
boost.spiritexpr = ( 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日土曜日
boost.spirit
.cpp
13年7月27日土曜日
boost.spirit
.cppドメイン言語 ホスト言語
13年7月27日土曜日
boost.spirit
.cppドメイン言語 ホスト言語
EDSL(埋め込みドメイン言語)
13年7月27日土曜日
boost.spirit
.cppドメイン言語 ホスト言語
EDSL(埋め込みドメイン言語)
YACC相当のものは?
13年7月27日土曜日
boost.spirit
.cppドメイン言語 ホスト言語
EDSL(埋め込みドメイン言語)
YACC相当のものは?
テンプレート・メタプログラミング
13年7月27日土曜日
なぜC++でメタプロ?
別の構文規則を学ぶ必要がない
他のメタプロとの相互運用
余分な構築ステップ不要
品質、再利用、可搬性
13年7月27日土曜日
とはいえ
boost.spiritのような究極のメタプログラミングの話は割愛します。
このあとの章では、C++メタプロを支える基本的な部分だけお話します。 (ちゃんと話せる自信がないというのはナイショぽよ
13年7月27日土曜日
メタプログラムとは何か?
テンプレートの基礎テンプレート特殊化
再帰テンプレート
メタ関数
型シーケンス
さいごに
13年7月27日土曜日
普通のジェネリック// C#List<string> list = new List<string>();list.add("hoge"); list.add("page");
// JavaList<String> list = new ArrayList<String>();list.add("hoge"); list.add("page");
//C++list<string> list;list.insert("hoge"); list.insert("page");
13年7月27日土曜日
非型テンプレート
//C++template<int N>struct pow { static const int value = N*N;};
int n = pow<3>::value; // n = 3*3;
13年7月27日土曜日
型の操作 ポインタを追加する
//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日土曜日
C++テンプレート
コンパイル時に計算してしまう(実行時コスト0)。
非型テンプレート
型操作
.....などなど
13年7月27日土曜日
メタプログラムとは何か?
テンプレートの基礎
テンプレート特殊化再帰テンプレート
メタ関数
型シーケンス
さいごに
13年7月27日土曜日
add_pointerの例ん??
// int* p = &n;add_pointer<int>::type p1 = &n;
// これはエラー:int** p2 = &n;add_pointer<int*>::type p2 = &n;
13年7月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日土曜日
テンプレート特殊化
テンプレート特殊化により、コンパイル時に条件分岐を行うことができる。
13年7月27日土曜日
コンパイル時 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日土曜日
コンパイル時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日土曜日
C++テンプレート
コンパイル時に計算してしまう(実行時コスト0)。
非型テンプレート
型操作
特殊化による条件分岐
13年7月27日土曜日
メタプログラムとは何か?
テンプレートの基礎
テンプレート特殊化
再帰テンプレートメタ関数
型シーケンス
さいごに
13年7月27日土曜日
普通に再帰で階乗計算
int factorial(int N) { return N==0 ? 1 : N*factorial(N-1);}
int n = factorial(3); // 6
13年7月27日土曜日
再帰テンプレートで// 階乗を求める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日土曜日
再帰テンプレート
再帰テンプレートにより、コンパイル時に繰り返し処理を行うことができる。
13年7月27日土曜日
余談
C++テンプレートはチューリング完全である(制限:再帰に限界あり)C++ Templates are Turing Complete
http://ubietylab.net/ubigraph/content/Papers/pdf/CppTuring.pdf
13年7月27日土曜日
C++テンプレートコンパイル時に計算してしまう(実行時コスト0)。
非型テンプレート
型操作
特殊化による条件分岐
再帰テンプレートによる繰り返し
13年7月27日土曜日
このへんからちょっとだけ応用な感じです。
ちょっとだけよ♡
13年7月27日土曜日
メタプログラムとは何か?
テンプレートの基礎
テンプレート特殊化
再帰テンプレート
メタ関数型シーケンス
さいごに
13年7月27日土曜日
メタ関数とは
add_pointer<int>::type pi;
関数名
int v = factorial_t<3>::value;
パラメータ 戻り値(型)
関数名 パラメータ 戻り値(値)
13年7月27日土曜日
高階関数を考えてみようまずは普通のテンプレート関数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日土曜日
高階メタ関数
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日土曜日
メタプログラムとは何か?
テンプレートの基礎
テンプレート特殊化
再帰テンプレート
メタ関数
型シーケンスさいごに
13年7月27日土曜日
こんなことしたいそれぞれの型のインスタンスを用意してメソッドを呼び出したい。
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日土曜日
JavaやC#、ObjCあたりのアプローチリフレクションを使う。
Classクラスのようなメタクラスの配列を使って動的生成する、とかね。
C++のリフレクションは貧弱。
どうしよう。
13年7月27日土曜日
C++のアプローチメタプログラミングで型のリスト(型シーケンス)を用意し、各型にアクセスする仕掛けを考えてみる。
TypeList<A,B,C,D>::type;
13年7月27日土曜日
C++のアプローチメタプログラミングで型のリスト(型シーケンス)を用意し、各型にアクセスする仕掛けを考えてみる。
TypeList<A,B,C,D>::type;
このへんをどうするか??
13年7月27日土曜日
型シーケンス
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日土曜日
型シーケンス
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日土曜日
むずくないよ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日土曜日
あとは繰り返す処理// 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日土曜日
ターミネータ忘れてた!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日土曜日
使ってみよう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日土曜日
リフレクションが無くても
テンプレートでいろいろ出来ちゃう。
しかも多くをコンパイル時に静的に。
boost.mpl には型のためのコンテナ、イテレータ、アルゴリズムがある。遅延評価、ラムダなども。正直、あたまおかしい(笑)
13年7月27日土曜日
メタプログラムとは何か?
テンプレートの基礎
テンプレート特殊化
再帰テンプレート
メタ関数
型シーケンス
さいごに13年7月27日土曜日
新たなパラダイムに出会えたね!
構造化
データ指向
オブジェクト指向
ジェネリック
関数型
・・・
メタプログラミング13年7月27日土曜日
余談GoFデザインパターンはオブジェクト指向だけか?
例えば Abstract FactoryパターンやVisitor パターンは、メタプロと相性が良い。
継承でなくポリシとか。
メタプロと関数型?
どちらも状態を持たない
13年7月27日土曜日
まとめ
C++テンプレート機能により、コンパイル時の処理を書くことが出来る。
ライブラリの実装では多用される。
でも、正直読みにくいし難解。C++11ではconstexprにより多少ましになっている。
13年7月27日土曜日
おつかれさま!
もうおわり?♡
ふう...
13年7月27日土曜日