constexprとtemplateでコンパイル時にfizz buzz

38
constexprtemplateでコンパイル時にFizzBuzzする KMC ID:dtyazsk

Upload: -

Post on 05-Jul-2015

1.017 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Constexprとtemplateでコンパイル時にfizz buzz

constexprとtemplateでコンパイル時にFizzBuzzするKMC ID:dtyazsk

Page 2: Constexprとtemplateでコンパイル時にfizz buzz

自己紹介

• KMC ID:dtyazsk

•所属:理学部1回(数学系志望)

•普段やってること:プログラミング/DTM/お絵描き

•趣味:弾幕STG(東方project/怒首領蜂シリーズ)/音ゲー(エニビ/BMS)

• よく使うプログラミング言語:C++

• twitterやってます(@DtYaZsK)

Page 3: Constexprとtemplateでコンパイル時にfizz buzz

今回やること

• templateとconstexprの概略

• FizzBuzz特化型文字列型を作る

• コンパイル時FizzBuzzを実装する

Page 4: Constexprとtemplateでコンパイル時にfizz buzz

templateとconstexprってなんぞや必要事項の確認とか

Page 5: Constexprとtemplateでコンパイル時にfizz buzz

templateとは

• C++の機能の一つ

• クラスと関数で使える

• クラスまたは数値を引数に取る

•数値にはコンパイル時整数型定数のみ• boolは整数型なのでとれる

•静的に展開しそれぞれクラスを作る

•例えば右のようなクラスがある

Page 6: Constexprとtemplateでコンパイル時にfizz buzz

templateとは

• C++の機能の一つ

• クラスと関数で使える

• クラスまたは数値を引数に取る

•数値にはコンパイル時整数型定数のみ• boolは整数型なのでとれる

•静的に展開しそれぞれクラスを作る

•例えば右のようなクラスがある

• Tmp_class<int,5>でこのように

Page 7: Constexprとtemplateでコンパイル時にfizz buzz

templateとは

• C++の機能の一つ

• クラスと関数で使える

• クラスまたは数値を引数に取る

•数値にはコンパイル時整数型定数のみ• boolは整数型なのでとれる

•静的に展開しそれぞれクラスを作る

•例えば右のようなクラスがある

• Tmp_class<double,7>でこのようになる

•明示的に渡してなくとも

推測できるなら推測してくれる

Page 8: Constexprとtemplateでコンパイル時にfizz buzz

templateの特殊化

• templateの引数によって処理を変えることも

• template<hoge>でhogeを可変引数部分にし特殊化

•例えば右のように書く

•特定されてない部分に

template引数を放り込む

•完全に特定された状態の特殊化も

templateは必要(template<>と書く)

Page 9: Constexprとtemplateでコンパイル時にfizz buzz

constexprってなんぞや

• C++11で追加されたキーワード

• コンパイル時に色々するためのキーワードである

•変数と関数につけて使う

•最近VC++でも搭載したらしい• 今回やることはできないようだが

•読み方がよくわからないが

このスライドでは「コンストエクスプラー」で統一する• 私がそう読んでるので

• constexprとわかればどう読んでもいいと思う

Page 10: Constexprとtemplateでコンパイル時にfizz buzz

constexpr定数

• リテラル型(後述)につける

• コンパイル時定数を作る

• template引数に出来たりと嬉しい

• static_assert(今回は省略)もできる

• なお実行時にはconst修飾される• 定数だから当たり前だろって話

• なおC++11までの話らしい

Page 11: Constexprとtemplateでコンパイル時にfizz buzz

constexprによる定数式

• コンパイル時と実行時に使える関数

•引数、返り値はやはりリテラル型

• constexpr定数の初期値に使える

• C++11の段階では関数の実装は

実質return文1つのみ

•条件演算子と再帰を使って色々できる

• チューリング完全であることが示されている

Page 12: Constexprとtemplateでコンパイル時にfizz buzz

リテラル型について

• intとかdoubleのような型はリテラル型の元となる

• ポインタ(全て)や参照型(リテラル型のみ)もリテラル型となる

•以下の条件を満たすクラス(または構造体)はリテラル型となる• trivialデストラクタを持つ

• ユーザー定義デストラクタを作らなければいい話

• 非staticなメンバの初期化子とコンストラクタ呼び出しが全て定数式

• aggregateであるか

またはコピーでもムーブでもないconstexprコンストラクタが1つ以上• aggregateとはユーザー定義コンストラクタも非staticメンバに初期化子への初期化子も

基本クラスも仮想関数もなく全てのメンバがpublicな配列またはクラスのこと

• 非staticメンバと基底クラスが全てリテラル型

• constexpr定数にできる

Page 13: Constexprとtemplateでコンパイル時にfizz buzz

リテラル型の例

•特に

説明することはない

•今回は

上のタイプを使う

Page 14: Constexprとtemplateでコンパイル時にfizz buzz

文字列型(機能限定版)作る完全版を作る余裕はなかった

Page 15: Constexprとtemplateでコンパイル時にfizz buzz

注意

•結構効率の悪い方法でやっております

•当時私DtYaZsKのC++力がなかったためです• 今もないだろいいかげんにしろ

• それを考慮に入れて御覧ください

Page 16: Constexprとtemplateでコンパイル時にfizz buzz

文字列型に必要な物は?

• char型データメンバ

•文字列結合(operator+)

•出力関数

• char型やint型から生成するための関数

Page 17: Constexprとtemplateでコンパイル時にfizz buzz

文字列型に必要な物は?

• char型データメンバ 配列の初期化よくわからなかった(当時)

•文字列結合(operator+) 使わなくてもFizzBuzzはできる

•出力関数 定数式にする必要はない

• char型やint型から生成するための関数 定数式である必要がある

Page 18: Constexprとtemplateでコンパイル時にfizz buzz

配列を使わずに複数の値を保持するには

• template<size_t SIZE>struct contとする• SIZEは文字数

• コンストラクタにはconst char*型を渡す• 文字列取得が楽

• 安全性とか知らん

• cont<SIZE-1>型はSIZE-1文字の要素を持つ• SIZE-1…?

Page 19: Constexprとtemplateでコンパイル時にfizz buzz

再帰的及び特殊化による定義

• とりあえず右のように定義する

• char型のポインタを引数に渡し

先頭を自分のメンバとして持ち

それ以降の要素をnextに渡す

• cont<1>で特殊化しないと

•無限ループに陥る

• マトリョーシカを想像すると

わかりやすいか• 一番外側の人形が先頭の文字を持って次の人形が次の文字を持って…

Page 20: Constexprとtemplateでコンパイル時にfizz buzz

出力関数を作る

•やはり再帰を用いる

• SIZEは型推論でもとめる

• 1で特殊化する必要性• そもそもcont<1>に

nextなんてメンバないし

Page 21: Constexprとtemplateでコンパイル時にfizz buzz

文字列生成関数を作るその1

•現状ではcont<4> str(“test”)と定義する必要がある

• ユーザーに文字数書かせるのはいかがなものか

• constexpr auto使いたい

•外部関数として提供されてないとFizzBuzzができない• もしかしたらできるかもしれないが私には思いつかない

Page 22: Constexprとtemplateでコンパイル時にfizz buzz

文字列生成関数を作るその1

•文字数取得はどうするか• 文字リテラルはconst char[SIZE]型

• 配列の要素数は参照を使えば求めれるらしい• 例えば右の関数

• そもそも配列の参照型が

右のように定義しないといけない

• それに加え要素数も一致しないといけない• したがってSIZEの値が確定する→template引数として推測される

Page 23: Constexprとtemplateでコンパイル時にfizz buzz

文字列生成関数を作るその1

•文字リテラルだと末端が¥0のためそれは省略する

• すると右のようになる

•配列の名前だけ書くと

ポインタになるという基本事項を利用

• constexpr autoで書けるようになった• そもそも今回constexpr auto使わないというのは言ってはいけない

Page 24: Constexprとtemplateでコンパイル時にfizz buzz

文字列生成関数を作るその2

•数字からも文字列を作りたい

• to_cont(“FizzBuzz”)はcont<8>型なのでそれで合わせる

•例えばto_cont(10)でto_cont(“00000010”)と同等にしたい

•現状ではすぐには思い浮かばない

Page 25: Constexprとtemplateでコンパイル時にfizz buzz

contのコンストラクタを追加する

• charとcont<SIZE-1>からcont<SIZE>を作れるようにする• cont<1>はcharのみ

•赤下線部を追加

•一体何のためか

Page 26: Constexprとtemplateでコンパイル時にfizz buzz

補助関数を用いてto_cont(std::size_t)を作る

•直接代入は出来ない

•再帰を使う

• N桁目の数字は「10^(N-1)で割った

商を10で割った余り」に等しい

•右のコードとなる

• ちなみにASCIIで

48は”0”にあたる

Page 27: Constexprとtemplateでコンパイル時にfizz buzz

そしてコンパイル時FizzBuzzへ時間が足りてない気がする

Page 28: Constexprとtemplateでコンパイル時にfizz buzz

コンパイル時FizzBuzzってそもそもなんだ

• コンパイル時にFizzBuzzをする

•当然(static_assert以外で基本的に)コンパイル時に出力ができない• 警告を用いた出力は存在するがよくわからない

•先ほど定義したcontに文字列をコンパイル時に代入する

Page 29: Constexprとtemplateでコンパイル時にfizz buzz

FizzBuzzのルールと代入関数

• FizzBuzzは数字を順に言っていき• 3の倍数の時はFizz

• 5の倍数の時はBuzz

• 両方の時はFizzBuzz

に置き換える遊び

•値を渡しそれによってcont<8>型を返す関数を定義する(上)

Page 30: Constexprとtemplateでコンパイル時にfizz buzz

配列型を作る

• cont型を作った時と

同様の理屈で

fizzbuzz型を作る

• コンストラクタで

this_resultに今の結果

nextに次の数字を渡す

• FizzBuzzOut()は結果を

一気に表示する

Page 31: Constexprとtemplateでコンパイル時にfizz buzz

int main()とその他諸々

• もはや言うまでもない

• ちなみにfizzbuzzの定義が

定義なので

result(hoge)でhogeから

FizzBuzzが開始できたり

Page 32: Constexprとtemplateでコンパイル時にfizz buzz

コンパイル

•通るか?

Page 33: Constexprとtemplateでコンパイル時にfizz buzz

コンパイル

•通った!

Page 34: Constexprとtemplateでコンパイル時にfizz buzz

結果

•見えないかも知れません

Page 35: Constexprとtemplateでコンパイル時にfizz buzz

参考資料その1

• TECHSCORE BLOG

C++で静的配列の要素数を求めるテンプレート関数• http://www.techscore.com/blog/2013/02/08/how-to-calculate-array-length-in-c-

and-cpp/

•本の虫

aggregateと初期化リストの不思議• http://cpplover.blogspot.jp/2010/09/aggregate.html

• ボレロ村上 – EniyGmaA Code

リテラル型クラスの条件、および「中3女子でもわかる constexpr」の訂正• http://d.hatena.ne.jp/boleros/20130718/1374155184

Page 36: Constexprとtemplateでコンパイル時にfizz buzz

参考資料その2

•中3女子でもわかる constexpr• http://www.slideshare.net/GenyaMurakami/constexpr-10458089

•中3女子が狂える本当に気持ちのいい constexpr• http://www.slideshare.net/GenyaMurakami/constexpr-11509325

• Constexpr中3女子テクニックー実践と濫用そしてC++14へ• http://www.slideshare.net/GenyaMurakami/constexpr-23355469

Page 37: Constexprとtemplateでコンパイル時にfizz buzz

今回の反省点と勉強点

• String型の実装が垣間見た気がする• 完全ではないにしろconstexpr力が高まった

• cont型の実装が妥協だらけだった• FizzBuzz特化型でした

• 効率とか何も考えてません

• operator==ぐらい実装すべきだったか• あればコンパイル時にFizzBuzzできていることが確認できる(by static_assert)

• constexprライブラリすごいなぁと

•高校の後輩が出力までコンパイル時に終わらせてて言葉が出ない• templateと警告使ってる

Page 38: Constexprとtemplateでコンパイル時にfizz buzz

ご清聴ありがとうございました今回のコードは

http://melpon.org/wandbox/permlink/sxZm8aNobZwX5baR

で公開してます