constexprとtemplateでコンパイル時にFizzBuzzする
KMC ID:dtyazsk
自己紹介
• KMC ID:dtyazsk
• 所属:理学部1回(数学系志望)
• 普段やってること:プログラミング/DTM/お絵描き
• 趣味:弾幕STG(東方project/怒首領蜂シリーズ)/音ゲー(エニビ/BMS)
• よく使うプログラミング言語:C++
• twitterやってます(@DtYaZsK)
今回やること
• templateとconstexprの概略
• FizzBuzz特化型文字列型を作る
• コンパイル時FizzBuzzを実装する
templateとconstexprってなんぞや
必要事項の確認とか
templateとは
• C++の機能の一つ
• クラスと関数で使える
• クラスまたは数値を引数に取る
• 数値にはコンパイル時整数型定数のみ
• boolは整数型なのでとれる

• 静的に展開しそれぞれクラスを作る
• 例えば右のようなクラスがある
templateとは
• C++の機能の一つ
• クラスと関数で使える
• クラスまたは数値を引数に取る
• 数値にはコンパイル時整数型定数のみ
• boolは整数型なのでとれる

• 静的に展開しそれぞれクラスを作る
• 例えば右のようなクラスがある
• Tmp_class<int,5>でこのように
templateとは
• C++の機能の一つ
• クラスと関数で使える
• クラスまたは数値を引数に取る
• 数値にはコンパイル時整数型定数のみ
• boolは整数型なのでとれる

• 静的に展開しそれぞれクラスを作る
• 例えば右のようなクラスがある
• Tmp_class<double,7>でこのようになる
• 明示的に渡してなくとも
推測できるなら推測してくれる
templateの特殊化
• templateの引数によって処理を変えることも
• template<hoge>でhogeを可変引数部分にし特殊化
• 例えば右のように書く
• 特定されてない部分に
template引数を放り込む
• 完全に特定された状態の特殊化も
templateは必要(template<>と書く)
constexprってなんぞや
• C++11で追加されたキーワード
• コンパイル時に色々するためのキーワードである
• 変数と関数につけて使う
• 最近VC++でも搭載したらしい
• 今回やることはできないようだが

• 読み方がよくわからないが
このスライドでは「コンストエクスプラー」で統一する
• 私がそう読んでるので
• constexprとわかればどう読んでもいいと思う
constexpr定数
• リテラル型(後述)につける
• コンパイル時定数を作る
• template引数に出来たりと嬉しい
• static_assert(今回は省略)もできる
• なお実行時にはconst修飾される
• 定数だから当たり前だろって話
• なおC++11までの話らしい
constexprによる定数式
• コンパイル時と実行時に使える関数
• 引数、返り値はやはりリテラル型
• constexpr定数の初期値に使える
• C++11の段階では関数の実装は
実質return文1つのみ
• 条件演算子と再帰を使って色々できる
• チューリング完全であることが示されている
リテラル型について
• intとかdoubleのような型はリテラル型の元となる
• ポインタ(全て)や参照型(リテラル型のみ)もリテラル型となる
• 以下の条件を満たすクラス(または構造体)はリテラル型となる
• trivialデストラクタを持つ
• ユーザー定義デストラクタを作らなければいい話

• 非staticなメンバの初期化子とコンストラクタ呼び出しが全て定数式
• aggregateであるか
またはコピーでもムーブでもないconstexprコンストラクタが1つ以上
• aggregateとはユーザー定義コンストラクタも非staticメンバに初期化子への初期化子も
基本クラスも仮想関数もなく全てのメンバがpublicな配列またはクラスのこと

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

• constexpr定数にできる
リテラル型の例
• 特に
説明することはない
• 今回は
上のタイプを使う
文字列型(機能限定版)作る
完全版を作る余裕はなかった
注意
• 結構効率の悪い方法でやっております
• 当時私DtYaZsKのC++力がなかったためです
• 今もないだろいいかげんにしろ

• それを考慮に入れて御覧ください
文字列型に必要な物は?
• char型データメンバ
• 文字列結合(operator+)
• 出力関数
• char型やint型から生成するための関数
文字列型に必要な物は?
• char型データメンバ 配列の初期化よくわからなかった(当時)
• 文字列結合(operator+) 使わなくてもFizzBuzzはできる
• 出力関数 定数式にする必要はない
• char型やint型から生成するための関数 定数式である必要がある
配列を使わずに複数の値を保持するには
• template<size_t SIZE>struct contとする
• SIZEは文字数

• コンストラクタにはconst char*型を渡す
• 文字列取得が楽
• 安全性とか知らん

• cont<SIZE-1>型はSIZE-1文字の要素を持つ
• SIZE-1…?
再帰的及び特殊化による定義
• とりあえず右のように定義する
• char型のポインタを引数に渡し
先頭を自分のメンバとして持ち
それ以降の要素をnextに渡す
• cont<1>で特殊化しないと
• 無限ループに陥る
• マトリョーシカを想像すると
わかりやすいか
• 一番外側の人形が先頭の文字を持って次の人形が次の文字を持って…
出力関数を作る
• やはり再帰を用いる
• SIZEは型推論でもとめる
• 1で特殊化する必要性
• そもそもcont<1>に
nextなんてメンバないし
文字列生成関数を作るその1
• 現状ではcont<4> str(“test”)と定義する必要がある
• ユーザーに文字数書かせるのはいかがなものか
• constexpr auto使いたい
• 外部関数として提供されてないとFizzBuzzができない
• もしかしたらできるかもしれないが私には思いつかない
文字列生成関数を作るその1
• 文字数取得はどうするか
• 文字リテラルはconst char[SIZE]型
• 配列の要素数は参照を使えば求めれるらしい
• 例えば右の関数

• そもそも配列の参照型が
右のように定義しないといけない
• それに加え要素数も一致しないといけない
• したがってSIZEの値が確定する→template引数として推測される
文字列生成関数を作るその1
• 文字リテラルだと末端が¥0のためそれは省略する
• すると右のようになる
• 配列の名前だけ書くと
ポインタになるという基本事項を利用
• constexpr autoで書けるようになった
• そもそも今回constexpr auto使わないというのは言ってはいけない
文字列生成関数を作るその2
• 数字からも文字列を作りたい
• to_cont(“FizzBuzz”)はcont<8>型なのでそれで合わせる
• 例えばto_cont(10)でto_cont(“00000010”)と同等にしたい
• 現状ではすぐには思い浮かばない
contのコンストラクタを追加する
• charとcont<SIZE-1>からcont<SIZE>を作れるようにする
• cont<1>はcharのみ

• 赤下線部を追加
• 一体何のためか
補助関数を用いてto_cont(std::size_t)を作る
• 直接代入は出来ない
• 再帰を使う
• N桁目の数字は「10^(N-1)で割った
商を10で割った余り」に等しい
• 右のコードとなる
• ちなみにASCIIで
48は”0”にあたる
そしてコンパイル時FizzBuzzへ
時間が足りてない気がする
コンパイル時FizzBuzzってそもそもなんだ
• コンパイル時にFizzBuzzをする
• 当然(static_assert以外で基本的に)コンパイル時に出力ができない
• 警告を用いた出力は存在するがよくわからない

• 先ほど定義したcontに文字列をコンパイル時に代入する
FizzBuzzのルールと代入関数
• FizzBuzzは数字を順に言っていき
• 3の倍数の時はFizz
• 5の倍数の時はBuzz
• 両方の時はFizzBuzz

に置き換える遊び
• 値を渡しそれによってcont<8>型を返す関数を定義する(上)
配列型を作る
• cont型を作った時と
同様の理屈で
fizzbuzz型を作る
• コンストラクタで
this_resultに今の結果
nextに次の数字を渡す
• FizzBuzzOut()は結果を
一気に表示する
int main()とその他諸々
• もはや言うまでもない
• ちなみにfizzbuzzの定義が
定義なので
result(hoge)でhogeから
FizzBuzzが開始できたり
コンパイル
• 通るか?
コンパイル
• 通った!
結果
• 見えないかも知れません
参考資料その1
• TECHSCORE BLOG
C++で静的配列の要素数を求めるテンプレート関数
• http://www.techscore.com/blog/2013/02/08/how-to-calculate-array-length-in-cand-cpp/

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

• ボレロ村上 – EniyGmaA Code
リテラル型クラスの条件、および「中3女子でもわかる constexpr」の訂正
• http://d.hatena.ne.jp/boleros/20130718/1374155184
参考資料その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
今回の反省点と勉強点
• String型の実装が垣間見た気がする
• 完全ではないにしろconstexpr力が高まった

• cont型の実装が妥協だらけだった
• FizzBuzz特化型でした
• 効率とか何も考えてません
• operator==ぐらい実装すべきだったか
• あればコンパイル時にFizzBuzzできていることが確認できる(by static_assert)

• constexprライブラリすごいなぁと
• 高校の後輩が出力までコンパイル時に終わらせてて言葉が出ない
• templateと警告使ってる
ご清聴ありがとうございました
今回のコードは
http://melpon.org/wandbox/permlink/sxZm8aNobZwX5baR

で公開してます

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