C++勉強会in広島プレゼン資料
Upcoming SlideShare
Loading in...5
×
 

C++勉強会in広島プレゼン資料

on

  • 1,607 views

C++勉強会in広島の発表スライドです

C++勉強会in広島の発表スライドです

Statistics

Views

Total Views
1,607
Views on SlideShare
1,552
Embed Views
55

Actions

Likes
4
Downloads
4
Comments
0

1 Embed 55

https://twitter.com 55

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

C++勉強会in広島プレゼン資料 C++勉強会in広島プレゼン資料 Presentation Transcript

  • TMPライブラリの設計と実装 C++勉強会in広島 @PG_nonen 2014/01/11
  • 概要 ● ● ● ● ● 自己紹介 はじめに Template Meta Programming(TMP)とは TMPライブラリの設計と実装 質疑応答
  • 自己紹介 ● 名前:北原真一 ○ HNは南山まさかず ○ 顔本は本名、その他はHN ● 棲息地 ○ 広島は魔界 ● その他 ○ 平凡な大学生 ○ C++、Haskell、女優の能年玲奈さんなどに興味・関心 があります
  • 自己紹介 ● Twitter ○ @PG_nonen ● Github ○ minamiyama1994 ● 公開しているライブラリ ○ FTMP ○ parser_combinator
  • はじめに ● 本日は ○ ○ ○ ○ 「C++」って名前は知ってる C++怖い Template怖い C++わかる ● ……等様々な人に来て頂いています
  • はじめに ● 初心者の人 ○ 「こんな世界もあるんだな~」ぐらいの気軽な気持ちでど うぞ ● ガチ勢の人 ○ お手柔らかにお願いします
  • Templateとは ● N3337 ○ 14 ○ A template defines a family of classes or functions or an alias for a family of types.
  • Templateとは ● コンパイル時に型や値を引数として渡す機能 ● クラス、関数、型エイリアスなどに指定できる ● 以下の様な構文 template < Template仮引数リスト > 宣言
  • Template仮引数に指定できるもの ● 型 ● 非型 ● テンプレート
  • Template仮引数に指定できるもの ● 型 ○ ○ ○ ○ 型が指定できます 以上 以下の様な構文 typenameとclassで意味は変わらない template < typename Template仮引数名 > 宣言 template < class Template仮引数名 > 宣言
  • Template仮引数に指定できるもの ● 非型 ○ N3337の14.1.4に記載されている ■ ■ ■ ■ ■ ■ ■ ■ 整数定数値 enum オブジェクトポインタ 関数ポインタ オブジェクトへの左辺値参照 関数への左辺値参照 メンバへのポインタ std::nullptr
  • Template仮引数に指定できるもの ● 非型 ○ 以下の様な構文 template < 型名 Template仮引数名 > 宣言
  • Template仮引数に指定できるもの ● テンプレート ○ クラステンプレートを指定できる ○ 以下の様な構文 template < template < Template仮引数リスト > class Template仮引数名 > 宣言
  • TMPとは ● Template Meta Programmingの略 ● ……の前に、Templateの使い方から
  • Templateの使い方 template < typename T > struct Hoge { T value ; };
  • Templateの使い方 template < typename T > auto add ( T x1 , T x2 ) -> decltype ( x1 + x2 ) { return x1 + x2 ; }
  • Templateの使い方 ● 本来はこのように「型によらない一般的な処理 を記述する」ためのもの ● ところが…… ● Meta Programmingに使える!!!!! ● ……ところでMeta Programmingって?
  • Meta Programmingとは ● 通常のコーディングの「更に上位」のレベルで行 うプログラミング ● 例 ○ 動的・動的にコードの書き換えを行えるLispのマクロ ○ 動的にクラスの構造などをいじれるRubyやIoなどLL言 語の機能 ○ 静的に構文木などをいじれるTemplate Haskell ○ 静的に型などをいじれるC++のTemplate
  • Meta Programmingとは ● これらを用いて通常のプログラミングの「ワンラ ンク上」のプログラミングを行う ● これがMeta Programming ● 今日はC++のTemplateを用いたTemplate Meta Programmingと、そのライブラリについて 話す
  • C++におけるMeta Programming ● C++のソースコードを書いて実行するまでには いくつかのステップが存在する ○ プリプロセス ○ コンパイル ○ 実行 ● 通常のプログラミングは実行時処理 ● プリプロセス時及びコンパイル時プログラミング は「ワンランク上」のプログラミング
  • Template Meta Programmingとは ● Templateはコンパイル時に処理を行う ● Templateを用いてコンパイル時に行える「ワン ランク上」の処理とは? ○ 型及びコンパイル時整数定数などの操作 ○ 「コンパイル時に型やコンパイル時定数を操作する」の がTemplate Meta Programming
  • Template Meta Programmingの例 #include<ostream> #include<iostream> template < unsigned N > struct factorial { static constexpr unsigned value = N * factorial < N - 1 >::value ; }; template < > struct factorial < 0 > { static constexpr unsigned value = 1 ; }; auto main ( ) -> int { std::cout << factorial < 10 >::value << std::endl ; }
  • Template Meta Programmingの例 template < unsigned N > struct factorial { // 整数Nが指定された時、valueの値はN*factorial < N - 1 >::value // N = 5 : value = 5 * factorial < 4 >::value // N = 4 : value = 4 * factorial < 3 >::value // N = 3 : value = 3 * factorial < 2 >::value // ...以下続く static constexpr unsigned value = N * factorial < N - 1 >::value ; };
  • Template Meta Programmingの例 template < > struct factorial < 0 > { // N = 0 の時だけvalue=1に特殊化 static constexpr unsigned value = 1 ; };
  • Template Meta Programmingの例 auto main ( ) -> int { // factorialのNに10を指定する // N = 10 の時 // factorial < 10 >::value = 10 * 9 * 8 * … * 1 = 10! // よって画面には 10! = 3628800 が表示される std::cout << factorial < 10 >::value << std::endl ; }
  • Template Meta Programmingの例 ● factorialは階乗を求める「メタ関数」 ● 階乗は「コンパイル時に」求められる
  • Template Meta Programmingの例 #include<utility> #include<string> template < typename > struct swap ; template < typename T1 , typename T2 > struct swap < std::pair < T1 , T2 > > { using type = std::pair < T2 , T1 > ; }; auto main ( ) -> int { swap < std::pair < int , std::string > >::type pair = std::make_pair ( “Hello” , 1 ) ; }
  • Template Meta Programmingの例 // swapは型を1つ受け取るメタ関数 template < typename > struct swap ; template < typename T1 , typename T2 > // std::pair < T1 , T2 >形式の型だけ受け付けるように特殊化 struct swap < std::pair < T1 , T2 > > { // T1とT2を取り替えたstd::pairをメンバtypedefのtypeに指定する using type = std::pair < T2 , T1 > ; };
  • Template Meta Programmingの例 auto main ( ) -> int { // swap < std::pair < int , std::string > >::typeはstd::pairの1つ目の型と2つ目の型を入れ替えた 新しいstd::pair // 1つ目の型 -> int // 2つ目の型 -> std::string // 従って、swap < std::pair < int , std::string > >::typeはstd::pair < std::string , int > // なので以下のコードはコンパイルが通る swap < std::pair < int , std::string > >::type pair = std::make_pair ( “Hello” , 1 ) ; }
  • Template Meta Programming ● TMPを行うと、このようにコンパイル時に整数定 数値や型を操作することができる
  • TMPライブラリの設計と実装 ● ではいよいよ本題の「TMPライブラリの設計と 実装」について
  • TMPライブラリの設計と実装 ● まず、TMPの際に使われる慣習について ○ メタ関数の「戻り値」としてはtypeメンバが使われる ○ 以上 ● 流石に少し解説 ○ メタ関数は単なるtemplateなstruct/class ○ C++の言語仕様として「戻り値」などが設定されているわ けではない ○ そこで、慣習として、typeメンバがよく使われる
  • TMPライブラリの設計と実装 ● TMPの特徴 ○ 入力(Template仮引数)によって結果(typeメンバ)は決 まる ○ Template仮引数以外に外部からの入力はないし、外部 に影響を与える処理もない ○ つまり、純粋関数型プログラミングとなる
  • TMPライブラリの設計と実装 ● TMPは純粋関数型プログラミング ● 改めてTMP用のライブラリを設計・実装するな ら既存の関数型言語のライブラリに倣った方が いい ● ……と、その前に ● 既存のライブラリは?
  • 既存のTMPライブラリ ● 既存のTMPライブラリ ○ 事実上デファクトスタンダードとなっているライブラリが存 在する ○ Boost.MPL ○ では、肝心のBoost.MPLはどういった設計になっている のか?
  • 既存のTMPライブラリ ● Boost.MPLの設計 ○ データ構造としての各種コンテナ ○ それらに対して作用する各種アルゴリズム ○ データ構造とアルゴリズムを橋渡しするイテレータ ■ →STLに倣った設計に
  • 既存のTMPライブラリ ● Boost.MPLの設計の問題点 ○ STLの設計に倣っている ○ STLは基本的に手続き型のコードで使われるのが前提 ■ 関数型プログラミングであるTMPとは相性が悪い ○ また、各種コンテナは複雑な内部構造を採用 ○ 論理的な等値比較などが面倒くさい ○ 要するにBoost.MPLは使いにくい
  • 既存のTMPライブラリ ● Boost.MPL以外のメジャーなTMPライブラリは あまりない ● では、作ってしまえ!
  • TMPライブラリの設計と実装 ● 設計の方針 ○ Haskellなどの純粋関数型言語のライブラリ設計に倣う ○ →List・Set・Mapなどとそれに対する関数群 ○ 論理的な等値比較などは細かい内部構造を意識しなく ても可能なように設計 ○ →Boost.MPLとは異なり、すべての型に対して論理的な 等値比較を提供 ● というわけで完成しました ○ https://github.com/minamiyama1994/FTMP
  • TMPライブラリの設計と実装 ● FTMPの設計 ○ list,set,dictと言った基礎的なコンテナ ○ ifやeval_ifなどと言ったutilityメタ関数 ○ Haskellのライブラリを参考に作成した、コンテナなどを 引数として受け取るメタ関数
  • TMPライブラリの設計と実装 ● FTMPの設計 ○ list,set,dictと言った基礎的なコンテナ ○ ifやeval_ifなどと言ったutilityメタ関数 ○ Haskellのライブラリを参考に作成した、コンテナなどを 引数として受け取るメタ関数
  • 各種コンテナ ● 型を操作するための各種コンテナ ○ list ○ set ○ dict
  • 各種コンテナ ● list ○ list < T1 , T2 , T3 … TN > ○ 順序付き、重複あり ○ 型のリスト
  • 各種コンテナ ● set ○ set < T1 , T2 , T3 … TN > ○ 順序不定、重複なし ○ 型のセット(集合)
  • 各種コンテナ ● dict ○ dict < list < K1 , T1 > , list < K2 , T2 > , ... list < KN , TN > > ○ 順序不定、キーの重複なし ○ 型の辞書
  • utilityメタ関数 ● ifやeval_if等の各種utilityメタ関数 ○ ○ ○ ○ ○ ○ if_ if_c eval_if eval_if_c print lambda
  • utilityメタ関数 ● if_ ○ if_ < cond , true_case , false_case > ○ cond::type::valueがtrueの場合はtypeはtrue_case ○ cond::type::valueがfalseの場合はtypeはfalse_case
  • utilityメタ関数 ● if_c ○ if_ < cond , true_case , false_case > ○ condがtrueの場合はtypeはtrue_case ○ condがfalseの場合はtypeはfalse_case
  • utilityメタ関数 ● eval_if ○ eval_if < cond , true_case , false_case > ○ cond::type::valueがtrueの場合はtypeはtrue_case:: type ○ cond::type::valueがfalseの場合はtypeはfalse_case:: type
  • utilityメタ関数 ● eval_if_c ○ eval_if_c < cond , true_case , false_case > ○ condがtrueの場合はtypeはtrue_case::type ○ condがfalseの場合はtypeはfalse_case::type
  • utilityメタ関数 ● print ○ ○ ○ ○ ○ print < T > 引数は任意の型 結果はTと等しい ただし強制的にコンパイルエラーを出す TMP途中でどのような型が生成されているのかを確認 するのに便利
  • utilityメタ関数 ● lambda ○ 少し複雑でかつ重要な役割を持っているので、少し詳し く説明する ○ 構成要素 ■ プレースホルダー ■ lambdaによる引数の適用
  • lambda ● プレースホルダー ○ 後々ちゃんとした値に置き換える「仮の値」 ○ arg<N>(Nは0以上の整数値)を指定する
  • lambda ● lambdaによる引数の適用 ○ メタ関数Fがあるとして、lambda < F < arg1 , arg2 … argN > >を考える ○ arg1,arg2...argNの中にはarg<M>形式のプレースホル ダーがある ○ lambda < F < arg1 , arg2 … argN > >::apply < a0 , a1 … aN >::typeで、arg1,arg2...argNの中のarg<M> はaMに置き換えられ、F < arg1 , arg2 … argN >::type がlambdaの結果として求められる
  • lambda lambda < F < double , arg < 2 > , arg < 0 > , long , arg < 1 > > >::apply < char , short , int >:: type lambda < F < double , arg < 2 > , arg < 0 > , long , arg < 1 > > >::apply < char , short , int >:: type lambda < F < double , arg < 2 > , char , long , arg < 1 > > >::apply < char , short , int >::type lambda < F < double , arg < 2 > , char , long , arg < 1 > > >::apply < char , short , int >::type lambda < F < double , arg < 2 > , char , long , short > >::apply < char , short , int >::type lambda < F < double , arg < 2 > , char , long , short > >::apply < char , short , int >::type lambda < F < double , int , char , long , short > >::apply < char , short , int >::type F < double , int , char , long , short >::type
  • TMPライブラリの設計と実装 ● FTMPの設計 ○ list,set,dictと言った基礎的なコンテナ ○ ifやeval_ifなどと言ったutilityメタ関数 ○ Haskellのライブラリを参考に作成した、コンテナなどを 引数として受け取るメタ関数
  • コンテナ用の各種メタ関数 ● list用のメタ関数 ● set用のメタ関数 ● dict用のメタ関数
  • コンテナ用の各種メタ関数 ● list,set,dict用のメタ関数 ○ HaskellのData.List,Data.Set,Data.Mapライブラリを参 考に ○ MaybeなどのHaskellの複雑な機能を使っている関数は 適当に簡略化 ■ Maybeの場合は例えばNothingに該当する場合は その場でコンパイルを失敗させる
  • TMPライブラリの実装 ● TMPライブラリを実装する際のポイントについて ○ 再帰深度 ■ 処理系定義($14.7.1.15) ■ ただし、規格での推奨がある(Annex B) ● 「Recursively nested template instantiations [1024].」 ■ listに対して線形の再帰深度のアルゴリズムを実装 すると、大きなlistなどに対しては容易に再帰深度制 限にぶつかることが考えられる ● 再帰深度を対数オーダーに制限する
  • TMPライブラリの実装 ● 再帰深度を対数オーダーに抑える ○ list操作は主にfoldr,foldlを用いて実装される ○ foldr,foldlの再帰深度を対数オーダーに抑えることを考 える
  • TMPライブラリの実装 ● foldrの素直な実装
  • TMPライブラリの実装 ● foldrの対数再帰深度な実装
  • TMPライブラリの実装 ● foldr,foldlの再帰深度を対数オーダーにするこ とにより、多くの処理の再帰深度を対数オー ダーに抑えることができる ○ →要素数の多いlistなどに対しても適用できる
  • TMPライブラリ ● Boost.MPLと比較して ○ メリット ■ Haskellのライブラリに倣ったことにより、よりスムー ズなTMPが可能に ○ デメリット ■ テストや、機能が充実しておらず、実績がない
  • TMPライブラリ ● 適用例 ○ 自作パーサコンビネータ ■ https://github. com/minamiyama1994/parser_combinator ■ 構文解析表を出力する元になる各種情報をTMPを 用いて求めている
  • TMPライブラリ ● 今後の課題 ○ テストを充実させる ○ 実装を充実させる ○ ドキュメントを充実させる
  • ご清聴ありがとうございました 時間があるようなら質疑応答に入ります