Your SlideShare is downloading. ×
0
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
中3女子でもわかる constexpr
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

中3女子でもわかる constexpr

23,761

Published on

Boost.勉強会 #7 中3女子でもわかる constexpr

Boost.勉強会 #7 中3女子でもわかる constexpr

Published in: Technology
1 Comment
39 Likes
Statistics
Notes
  • スライド内の記述と C++11 の現行規格とに齟齬があったので、訂正記事を付記します。 http://d.hatena.ne.jp/boleros/20130718
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
23,761
On Slideshare
0
From Embeds
0
Number of Embeds
14
Actions
Shares
0
Downloads
93
Comments
1
Likes
39
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 中3女子でもわかる! constexprBoost.勉強会 #7bolero_MURAKAMI2011/12/3
  • 2. ◆⾃⼰紹介• 名前 : 村上 原野 (むらかみ げんや) @bolero_MURAKAMI, id:boleros• 棲息地: ⼤都会岡⼭• 仕事 : 猪⾵来美術館陶芸指導員 ・普段はやきものの修⾏をしたり、 縄⽂⼟器をつくったりしています ・趣味は constexpr です
  • 3. ◆⾃⼰紹介• 好きな C++11 の機能: constexpr• 嫌いな C++11 のキーワード: constexpr• 次期 C++ で強化されてほしい機能: constexpr• 次期 C++ で消えてほしいキーワード: constexpr
  • 4. ◆⾃⼰紹介• 公開しているライブラリ: Sprout C++ Library (constexpr ライブラリ) github.com/bolero-MURAKAMI/Sprout
  • 5. ◆アジェンダ• はじめに• constexpr とは?• constexpr 実装技法• constexpr の3⼤コスト• constexpr ライブラリを使ってみる• まとめ
  • 6. ◆constexpr とは?• N32907.1.5 The constexpr specifier [dcl.constexpr]1 The constexpr specifier shall be applied only to the definition of a variable,the declaration of a function or function template, or the declaration of astatic data member of a literal type (3.9). If any declaration of a function orfunction template has constexpr specifier, then all its declarations shallcontain the constexpr specifier. [ Note: An explicit specialization can differfrom the template declaration with respect to the constexpr specifier. -endnote ] [ Note: Function parameters cannot be declared constexpr.-end note ]
  • 7. ◆constexpr とは?• N3290 7.1.5 constexpr 指定子 [dcl.constexpr] constexpr 指定子は、変数の定義、関数または関数テンプレートの宣言、 またはリテラル型(3.9)の静的データメンバの宣言に適用されるものとする。 (中略) [注:関数のパラメータは constexpr 宣言することはできない。]• C++11 で導⼊されたキーワードである• decl-specifier に分類される – (型修飾⼦ではない)
  • 8. ◆constexpr とは?• constexpr 宣⾔された変数は、コンパイル時定数になるconstexpr int zero = 0; // constexpr 変数using zero_t = std::integral_constant<int, zero>; // テンプレートにも渡せる• constexpr 宣⾔された関数やコンストラクタは、コンパ イル時にも実⾏時にも呼び出すことができるconstexpr int always_zero() { return 0; } // constexpr 関数constexpr int compiletime_zero = always_zero(); // コンパイル時呼出int runtime_zero = always_zero(); // 実行時呼出• リテラル型のオブジェクトは、コンパイル時定数にでき るstruct literal_type { }; // リテラル型のクラスconstexpr auto literal = literal_type{ }; // クラスインスタンスを定数式に
  • 9. ◆constexpr ⼊⾨• プログラミングの魔導書vol.2 の江添さん の記事を読んでください• 読んでなかったら買ってください
  • 10. ◆C++ プログラミングのレイヤー C++03 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング(ライブラリアンが多数棲息) 定数式 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  • 11. ◆C++ プログラミングのレイヤー C++03 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング(ライブラリアンが多数棲息) 定数式 どっちも「値」を 求めるのは同じでも…… わたしたち 離ればなれね…… 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  • 12. ◆C++ プログラミングのレイヤー C++11 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート それ constexpr 型 で出来るよ! コンパイル時の世界 メタプログラミング(ライブラリアンが多数棲息) 定数式 抱いて!! constexpr キャーカッコイー!! 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  • 13. ◆定数も⾮定数も constexpr で• TMP で定数値を計算するtypedef typename mpl::max<A, B>::type value_t;constexpr auto compiletime_value = value_t::value;• 関数で実⾏時に値を計算するauto runtime_value = std::max(a, b);
  • 14. ◆定数も⾮定数も constexpr で• TMP で定数値を計算する typedef typename mpl::max<A, B>::type value_t; constexpr auto compiletime_value = value_t::value;• 関数で実⾏時に値を計算する auto runtime_value = std::max(a, b); ↓• どっちも constexpr で出来るよ! template<class T> // constexpr 関数テンプレート constexpr T max(T const& a, T const& b) { return a < b ? b : a; } auto runtime_value = max(a, b); しかも TMP より⾼速 constexpr auto compiletime_value = max(a, b);
  • 15. ◆コンパイル時⽂字列• TMP でやってみるtypedef mpl::string<’Hell’, ’o, wo’, ’rld! ’> hello_t; – 書きづらい(醜い) – 遅い – 制限が多い – 型の領域だけでは無理がある
  • 16. ◆コンパイル時⽂字列• TMP でやってみる typedef mpl::string<’Hell’, ’o, wo’, ’rld! ’> hello_t; – 書きづらい(醜い) – 遅い – 制限が多い – 型の領域だけでは無理がある ↓ Sprout C++ Library の• 簡単さ。そう、constexpr ならね constexpr string #include <sprout/string.hpp> constexpr auto hello = sprout::to_string(“hello, world!”); ⽂字列リテラルも そのまま使える
  • 17. ◆コンパイル時⽂字列• こんなことも出来るよ! – 例) コンパイル時⽂字列解析 (Boost.Spirit.Qi ⾵){ using namespace sprout; using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p = repeat[lim<16>(hex8f)] | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); std::cout << std::boolalpha << realign_to<uuid>(parsed.attr()) << "¥n";}
  • 18. ◆コンパイル時⽂字列• こんなことも出来るよ! – 例) コンパイル時⽂字列解析 (Boost.Spirit.Qi ⾵){ using namespace sprout; UUID ⽂字列 using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p ブラケット無しの = repeat[lim<16>(hex8f)] UUID にマッチするパーサ | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p ブラケット無し/有り両⽅に = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; マッチするようパーサを合成 constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); パースを実⾏ std::cout << std::boolalpha << realign_to<uuid>(parsed.attr()) << "¥n";} 最後以外全部コンパイル時に 処理される
  • 19. ◆constexpr で扱えるデータ [リテラル型] [スカラ型] [リテラル型の配列] [算術型] LiteralType [N] [整数型] int, unsigned int, char, ... [リテラル型への参照] [浮動⼩数点型] float, double, ... LiteralType const& [ポインタ型] [ポインタ] int const*, int (*)(void), ... 特定の条件を満たす [メンバポインタ] int T::*, int (T::*)(void), ... ユーザ定義クラス [列挙型] enum
  • 20. ◆リテラル型クラスの条件• コンパイラの要求 – trivial コピーコンストラクタを持つ – ⾮ trivial ムーブコンストラクタを持たない – trivial デストラクタを持つ – trivial デフォルトコンストラクタか、コピーでもムーブでもな い constexpr コンストラクタを持つ – ⾮ static データメンバと基本クラスは、全てリテラル型である
  • 21. ◆リテラル型クラスの条件• プログラマの「べからず」 – 仮想関数や仮想基底クラスを書かない – ユーザ定義コピーコンストラクタを書かない • (delete もしない) – ユーザ定義ムーブコンストラクタを書かない • (delete するのはよい) – ユーザ定義デストラクタを書かない – ユーザ定義デフォルトコンストラクタを書くなら原則 constexpr にする • (デフォルトコンストラクタが trivial でも constexpr でもない場 合、別の constexpr コンストラクタを書く) – リテラル型以外の⾮ static データメンバや基底クラスを使わな い
  • 22. ◆リテラル型クラスの条件• リテラル型になれない例struct NonLiteralType 仮想基底クラスは NG! : virtual BaseType : NonLiteralBaseType リテラル型以外の基底クラスは NG!{ };struct NonLiteralType { virtual MemberFunction() const; 仮想関数は NG!}; ユーザ定義コピーコンストラクタは NG!struct NonLiteralType { constexpr LiteralType(LiteralType const&) { } LiteralType(LiteralType const&) = delete;}; コピーコンストラクタの delete も NG!
  • 23. ◆リテラル型クラスの条件• リテラル型になれない例struct NonLiteralType { ユーザ定義デストラクタは NG! ~LiteralType() { }}; デフォルトコンストラクタが⾮ constexpr の場合struct NonLiteralType { 別の constexpr コンストラクタがあれば OK LiteralType() { } // constexpr explicit LiteralType(int) { }}; ユーザ定義ムーヴコンストラクタは NG!struct NonLiteralType { constexpr LiteralType(LiteralType&&) { } // LiteralType(LiteralType&&) = delete;}; ムーヴコンストラクタの delete は OK
  • 24. ◆リテラル型クラスの条件• リテラル型になれない例struct NonLiteralType {private: リテラル型以外のデータメンバは NG! NonLiteralDataType data_member_;};
  • 25. ◆関数を constexpr 化する• 条件分岐• ループ• ローカル変数• エラー通知• シグネチャの constexpr 化• 配列操作 (Variadic function)• 配列操作 (index_tuple イディオム)
  • 26. ◆条件分岐• ⾮ constexpr 関数 template<class T> T max(T const& a, T const& b) { if (a < b) return b; else return a; } if ⽂ ↓• constexpr 関数 条件演算⼦ template<class T> constexpr T max(T const& a, T const& b) { return (a < b) ? b : a; }
  • 27. ◆ループ• ⾮ constexpr 関数 template<class Iter, class T> Iter find(Iter first, Iter last, T const& val) { while (first != last) { if (*first == val) return first; ++first; } return first; ループ構⽂ } ↓ 再帰• constexpr 関数 template<class Iter, class T> constexpr Iter find(Iter first, Iter last, T const& val) { return (first != last) ? (*first == val) ? first : find(first + 1, last, val) : first; ++演算⼦は使えない } (副作⽤があるから)
  • 28. ◆ループ• ⾮ constexpr 関数 template<class Iter, class T> Iter find(Iter first, Iter last, T const& val) { while (first != last) { if (*first == val) return first; ++first; } return first; ループ構⽂ } ↓ 再帰• constexpr 関数 template<class Iter, class T> constexpr Iter find(Iter first, Iter last, T const& val) { return (first == last) || (*first == val) ? first : find(first + 1, last, val); } 式を整理して このようにも書ける
  • 29. ◆ローカル変数• ⾮ constexpr 関数 double heron(double a, double b, double c) { double s = (a+b+c)/2; return std::sqrt(s*(s-a)*(s-b)*(s-c)); ローカル変数 } ↓ 実装⽤関数の引数に• constexpr 関数 constexpr double heron_impl(double a, double b, double c, double s) { return std::sqrt(s*(s-a)*(s-b)*(s-c)); } constexpr double heron(double a, double b, double c) { return heron_impl(a, b, c, (a+b+c)/2); } 実装⽤関数 ※ constexpr std::sqrt は libstdc++ の⾮標準拡張
  • 30. ◆エラー通知• ⾮ constexpr 関数 template<class T> T const* next(T const* p) { if (p) return p + 1; else assert(0); // error } assert / 実⾏時例外 ↓• constexpr 関数 例外 template<class T> constexpr T const* next(T const* p) { return p ? p + 1 : throw std::invalid_argument("p is nullptr"); } コンパイル時にはコンパイルエラー 実⾏時には例外が投げられる
  • 31. ◆エラー通知• ⾮ constexpr 関数 template<class T> T const* next(T const* p) { if (p) return p + 1; else assert(0); // error } assert / 実⾏時例外 ↓• constexpr 関数 × static_assert template<class T> constexpr T const* next(T const* p) { static_assert(p != 0, "p is nullptr"); // NG! return p + 1; } p が実⾏時引数のとき p !=0 は⾮定数式
  • 32. ◆シグネチャの constexpr 化• ⾮ constexpr 関数 template<class T> void inc(T& x) { ++x; } 返値 void → 値を返す• constexpr 関数 引数書換え → 副作⽤無しに template<class T> constexpr T inc(T const& x) { return x + 1; }
  • 33. ◆シグネチャの constexpr 化• ⾮ constexpr 関数 template<class Iter, class Expr, class Attr> bool parse(Iter& first, Iter last, Expr const& expr, Attr& attr); 複数の結果(副作⽤)がある ↓• constexpr 関数 タプルにして返す template<class Attr, class Iter, class Expr> constexpr tuple<bool, Iter, Attr> parse(Iter first, Iter last, Expr const& expr);
  • 34. ◆配列操作 (Variadic function)• reverse アルゴリズムを実装してみる #include <sprout/array.hpp> constexpr array using namespace sprout; template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr); 適⽤結果の配列を返す
  • 35. ◆配列操作 (Variadic function)• reverse アルゴリズムを実装してみる template<class T, size_t N, class... Args> constexpr array<T, N> reverse_impl(array<T, N> const& arr, Args const&... args) { return (sizeof...(Args) >= N) 要素全て Parameter pack に追加されるまで ? array<T, N>{{ args... }} : reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]); } 配列要素のケツから次々 Parameter pack の末尾に挿⼊ template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr) { return reverse_impl(arr); }
  • 36. ◆配列操作 (Variadic function)• reverse アルゴリズムを実装してみる template<class T, size_t N, class... Args> constexpr array<T, N> reverse_impl(array<T, N> const& arr, Args const&... args) { return (sizeof...(Args) >= N) ? array<T, N>{{ args... }} : reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]); } template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr) { return reverse_impl(arr); }• 残念ながら、このコードはコンパイルできない error: template instantiation depth exceeds maximum of 1024 (use -ftemplate-depth= to increase the maximum) テンプレート実体化の深さ限界を超えてしまった
  • 37. ◆配列操作 (Variadic function)• reverse アルゴリズムを実装してみる template<class T, size_t N, class... Args> constexpr array<T, N> reverse_impl(array<T, N> const& arr, Args const&... args) { return (sizeof...(Args) >= N) sizeof...(Args) == N のとき再帰終了する? ? array<T, N>{{ args... }} : reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]); } 「評価」はされないが 「テンプレートの実体化」はされる template<class T, size_t N> → 実体化の再帰は終了しない constexpr array<T, N> reverse(array<T, N> const& arr) { return reverse_impl(arr); } 結果、テンプレートの実体化が 無限再帰になる
  • 38. ◆配列操作 (Variadic function)• reverse アルゴリズムを実装してみる template<class T, size_t N, class... Args> constexpr typename enable_if< (sizeof...(Args) >= N), SFINAE: ここで再帰終了 array<T, N> >::type reverse_impl(array<T, N> const& arr, Args const&... args) { return array<T, N>{{ args... }}; } 再帰条件を template<class T, size_t N, class... Args> SFINAE で書く constexpr typename enable_if< (sizeof...(Args) < N), array<T, N> SFINAE: 再帰を続ける場合 >::type reverse_impl(array<T, N> const& arr, Args const&... args) { return reverse_impl(arr, args..., arr[N-1-sizeof...(Args)]); } template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr) { return reverse_impl(arr); }
  • 39. ◆配列操作 (Variadic function)• Variadic function の再帰はテンプレート実体化の無限 再帰になりやすいので注意する• そうなるケースでは再帰条件を SFINAE にする• (static if ほしいです)
  • 40. ◆配列操作 (index_tuple idiom)• また reverse アルゴリズムを実装してみる #include <sprout/array.hpp> constexpr array using namespace sprout; template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr); 適⽤結果の配列を返す
  • 41. ◆配列操作 (index_tuple idiom)• また reverse アルゴリズムを実装してみる #include <sprout/index_tuple.hpp> for index_tuple, index_range template<class T, size_t N, ptrdiff_t... Indexes> constexpr array<T, N> reverse_impl(array<T, N> const& arr, index_tuple<Indexes...>) { return array<T, N>{{ arr[N-1-Indexes]... }}; } template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr) { return reverse_impl(arr, typename index_range<0, N>::type()); }
  • 42. ◆配列操作 (index_tuple idiom)• また reverse アルゴリズムを実装してみる #include <sprout/index_tuple.hpp> template<class T, size_t N, ptrdiff_t... Indexes> 0..N-1 に推論され constexpr array<T, N> る reverse_impl(array<T, N> const& arr, index_tuple<Indexes...>) { return array<T, N>{{ arr[N-1-Indexes]... }}; } Pack expansion expression によって arr[N-1]..arr[0] に展開される template<class T, size_t N> constexpr array<T, N> reverse(array<T, N> const& arr) { return reverse_impl(arr, typename index_range<0, N>::type()); } index_range<0, N>::type は index_tuple<0..N-1> を返す
  • 43. ◆配列操作 (index_tuple idiom)• index_tuple イディオムは、インデックスアクセス可能 なデータ構造⼀般に適⽤できる – 配列 – タプル – ランダムアクセスイテレータ – 型リスト• constexpr に限らず、通常の関数や TMP にも同じよう に応⽤できる• ただしインデックスアクセス不可なデータ構造には適⽤ できない – ⾮ランダムアクセスなイテレータなど
  • 44. ◆クラスを constexpr 化する• コンストラクタで処理を委譲• 状態を書き換えるメンバ関数の constexpr 化
  • 45. ◆コンストラクタで処理を委譲• Delegating constructor #include <sscrisk/cel/algorithm.hpp> constexpr minmax_element using namespace sscrisk::cel; template<class T> あるイテレータ範囲の min と max を struct minmax_t { 保持するクラス template<class Iter> constexpr minmax_t(Iter first, Iter last); private: constexpr コンストラクタでは T min_, max_; 初期化⼦リストにしか }; 処理を書けない
  • 46. ◆コンストラクタで処理を委譲• Delegating constructor template<class T> struct minmax_t { まず minmax を求めてから template<class Iter> 別のコンストラクタに処理を丸投げ constexpr minmax_t(Iter first, Iter last) : minmax_t(minmax_element(first, last)) {} private: template<class Iter> constexpr minmax_t(pair<Iter, Iter> const& minmax) : min_(*minmax.first) , max_(*minmax.second) minmax を min と max に振り分け {} T min_, max_; };
  • 47. ◆コンストラクタで処理を委譲• C++03 Delegating constructor workaround template<class T> struct minmax_t_impl { protected: template<class Iter> constexpr minmax_t_impl(pair<Iter, Iter> const& minmax) : min_(*minmax.first) , max_(*minmax.second) 実装⽤クラスで minmax を {} min と max に振り分け T min_, max_; }; private 継承 template<class T> struct minmax_t : private minmax_t_impl<T> { template<class Iter> 実装⽤クラスに処理を丸投げ constexpr minmax_t(Iter first, Iter last) : minmax_t_impl<T>(minmax_element(first, last)) {} private: using minmax_t_impl<T>::min_; using minmax_t_impl<T>::max_; }; 実装⽤クラスのメンバを using
  • 48. ◆状態を書き換えるメンバ関数• ⾮ constexpr クラス struct sha1 { void process_byte(unsigned char byte); template<class Iter> 状態を書き換える void process_block(Iter first, Iter last); ↓ }; 「次の状態」を返すように• constexprクラス struct sha1 { constexpr sha1 process_byte(unsigned char byte) const; template<class Iter> constexpr sha1 process_block(Iter first, Iter last) const; };
  • 49. ◆状態を書き換えるメンバ関数• ⾮ constexpr クラス struct random_generator { unsigned int operator()(); 状態を書き換え、 }; かつ処理結果を返す ↓ 処理結果と「次の状態」の タプルを返す• constexprクラス struct random_generator { constexpr pair<unsigned int, random_generator> operator()() const; };
  • 50. ◆constexpr の3⼤コスト• オブジェクトコピーのコスト• 再帰とテンプレートインスタンス化のコ スト• コーディング上のコスト (⼈間のコスト)
  • 51. ◆オブジェクトコピーのコスト• 配列の2つの要素の swap を考えてみる – ⾮ constexpr の場合 (元の配列を書換え)⾼々1回のコピーと 2回の代⼊(またはムーヴ) – constexpr の場合 (別の配列をつくる) 常に全要素の コピー• 単なる要素の交換に線形時間 O(n) を要する
  • 52. ◆オブジェクトコピーのコスト• 状態を書き換えるメンバ関数の呼出しを考えてみる constexpr array<unsigned char, N> src = { /*...*/ }; sha1.process_byte(src[0]) .process_byte(src[1]) 計算量= /*...*/ (計算毎+コピー毎)×要素数 .process_byte(src[N-1]); sha1.process_block(src.begin(), src.end()); 計算量=計算毎×要素数+コピー• 状態を書き換えるメンバ関数を constexpr にすると、 (オブジェクトコピー×呼出し回数)の計算量が余計に かかる
  • 53. ◆オブジェクトコピーのコスト• [回避するには]• 状態を変更する呼出しは可能な限り少なくする – (1つの関数で済ませる)• Variadic function や index_tuple イディオムを活⽤し てオブジェクトコピーが⾏われない処理を書く
  • 54. ◆再帰とテンプレート実体化のコスト• 再帰を途中で打ち切るアルゴリズムを考えてみるtemplate<class T, size_t N, class... Args>constexpr typename enable_if< SFINAE の番兵 (sizeof...(Args) >= N), array<T, N>>::type copy_to_find(array<T, N> const& arr, T const& val, Args const&... args) { return array<T, N>{{ args... }};}template<class T, size_t N, class... Args> 引数 val と等しい要素があったらconstexpr typename enable_if< そこまでを新しい配列にコピーする (sizeof...(Args) < N), array<T, N>>::type copy_to_find(array<T, N> const& arr, T const& val, Args const&... args) { return val == arr[sizeof...(Args)] ? array<T, N>{{ args... }} : find_copy(arr, val, args..., arr[sizeof...(Args)]);}
  • 55. ◆再帰とテンプレート実体化のコスト• 再帰を途中で打ち切るアルゴリズムを考えてみる constexpr auto src_1 = array<int, 10>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }}; constexpr auto copied_1 = copy_to_find(src_1, 5); 再帰は 5 まで 要素数が 20 constexpr auto src_2 = array<unsigned, 20>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }}; constexpr auto copied_2 = copy_to_find(src_2, 5); 再帰は 5 まで• copied_1 の計算量は copied_2 と変わらないはず – ところが、そうはならない (gcc 4.7) – copied_2 のほうが倍近く遅い
  • 56. ◆再帰とテンプレート実体化のコスト• 再帰を途中で打ち切るアルゴリズムを考えてみるconstexpr auto src_1 = array<int, 10>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};constexpr auto copied_1 = copy_to_find(src_1, 5);constexpr auto src_2 = array<unsigned, 20>{{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }};constexpr auto copied_2 = copy_to_find(src_2, 5);• 実際に評価される再帰が何回だったとしても(例え0回 でも)SFINAE で打ち切られるまで全てのテンプレート がインスタンス化されるため – (copied_1 は 10,copied_2 は 20)
  • 57. ◆再帰とテンプレート実体化のコスト• [回避するには]• インデックスアクセス可能かつ線形探索ならば常に index_tuple イディオムを使う – (再帰のオーバーヘッドも深さ制限もない)
  • 58. ◆コーディング上のコスト• コンパイル時だとまともにデバックできない – constexpr をマクロにして on/off オフすれば実⾏時デバッグが できる
  • 59. ◆コーディング上のコスト• 処理フローが増えるたび、別の関数を作って処理を委譲 しなければならない – ループ処理 – ⼀時オブジェクトに名前を付ける
  • 60. ◆コーディング上のコスト• 例) constexpr uniform_int_distribution の実装 template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_3_1_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size, BaseUnsigned result); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, BaseUnsigned bucket_size); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2_4(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType result_increment); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType mult, RangeType result_increment); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned, typename Result> constexpr result<T, Engine> generate_uniform_int_true_2_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType result, RangeType mult, Result const& result_increment_base); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result = RangeType(0), RangeType mult = RangeType(1)); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2_1_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result, RangeType mult); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType limit, RangeType result, RangeType mult); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange); template<typename Engine, typename T, typename BaseResult> constexpr result<T, Engine> generate_uniform_int_true_1_1(random_result<Engine> const& rnd, T min_value, BaseResult bmin); template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> constexpr result<T, Engine> generate_uniform_int_true_1(Engine const& eng, T min_value, T max_value, RangeType range, BaseResult bmin, BaseUnsigned brange); template<typename Engine, typename T> constexpr result<T, Engine> generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type); template<typename Engine, typename T, typename Result> constexpr result<T, Engine> generate_uniform_int_false_1(Result const& rnd); template<typename Engine, typename T>
  • 61. ◆コーディング上のコスト• 実装関数が増殖するtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsignedbrange, BaseUnsigned bucket_size);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_3_1_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange,BaseUnsigned bucket_size, BaseUnsigned result);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsignedbrange, BaseUnsigned bucket_size); これは宣⾔だけ書き出して⼀部省略しているのでtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> 引数コピペの嵐 実際のコードはもっと酷いconstexpr result<T, Engine> generate_uniform_int_true_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange); 元々はたったtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_4(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType 2 個の関数だったresult, RangeType result_increment);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeType 18 個の実装関数result, RangeType mult, RangeType result_increment);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned, typename Result>constexpr result<T, Engine> generate_uniform_int_true_2_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTyperesult, RangeType mult, Result const& result_increment_base);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTypelimit, RangeType result = RangeType(0), RangeType mult = RangeType(1));template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_1_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsignedbrange, RangeType limit, RangeType result, RangeType mult);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTypelimit, RangeType result, RangeType mult);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T, typename BaseResult>constexpr result<T, Engine> generate_uniform_int_true_1_1(random_result<Engine> const& rnd, T min_value, BaseResult bmin);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_1(Engine const& eng, T min_value, T max_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T>constexpr result<T, Engine> generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type);template<typename Engine, typename T, typename Result>constexpr result<T, Engine> generate_uniform_int_false_1(Result const& rnd);template<typename Engine, typename T>
  • 62. ◆コーディング上のコスト• 名前付けが酷いtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsignedbrange, BaseUnsigned bucket_size);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_3_1_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, generate_uniform_int_true_2_1 とかBaseUnsigned bucket_size, BaseUnsigned result);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_3_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsignedbrange, BaseUnsigned bucket_size); generate_uniform_int_true_2_2 とかtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> generate_uniform_int_true_2_3 ...constexpr result<T, Engine> generate_uniform_int_true_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_4(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTyperesult, RangeType result_increment); そもそも意味論でなく単に処理フローでtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> 分割しているだけなので、constexpr result<T, Engine> generate_uniform_int_true_2_3(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTyperesult, RangeType mult, RangeType result_increment); 各関数に意味のある名前を付けるのが難しいtemplate<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned, typename Result>constexpr result<T, Engine> generate_uniform_int_true_2_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTyperesult, RangeType mult, Result const& result_increment_base);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTypelimit, RangeType result = RangeType(0), RangeType mult = RangeType(1));template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2_1_1(random_result<Engine> const& rnd, T min_value, RangeType range, BaseResult bmin, BaseUnsigned constexpr ラムダ式があればbrange, RangeType limit, RangeType result, RangeType mult);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned> 救われる(かもしれない)constexpr result<T, Engine> generate_uniform_int_true_2_1(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange, RangeTypelimit, RangeType result, RangeType mult);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_2(Engine const& eng, T min_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T, typename BaseResult>constexpr result<T, Engine> generate_uniform_int_true_1_1(random_result<Engine> const& rnd, T min_value, BaseResult bmin);template<typename Engine, typename T, typename RangeType, typename BaseResult, typename BaseUnsigned>constexpr result<T, Engine> generate_uniform_int_true_1(Engine const& eng, T min_value, T max_value, RangeType range, BaseResult bmin, BaseUnsigned brange);template<typename Engine, typename T>constexpr result<T, Engine> generate_uniform_int(Engine const& eng, T min_value, T max_value, std::true_type);template<typename Engine, typename T, typename Result>constexpr result<T, Engine> generate_uniform_int_false_1(Result const& rnd);template<typename Engine, typename T>
  • 63. ◆コーディング上のコスト• [回避するには]• 次期 C++1x に期待する• 諦める
  • 64. ◆constexpr なライブラリ• 標準ライブラリ• libstdc++ 独⾃拡張• CEL - ConstExpr Library• Sprout C++ Library
  • 65. ◆標準ライブラリ• <limits> – numeric_limits• <utility> – pair (デフォルトコンストラクタのみ)• <tuple> – tuple (デフォルトコンストラクタのみ)• <bitset> – bitset• <memory> – unique_ptr (デフォルトコンストラクタのみ) – shared_ptr (デフォルトコンストラクタのみ) – weak_ptr (デフォルトコンストラクタのみ) – enable_shared_from_this (デフォルトコンストラクタのみ)
  • 66. ◆標準ライブラリ• <ratio> – ratio• <chrono> – 各種演算 – duration_values – duration – time_point• <string> – char_traits• <array> – array (size, max_size, empty のみ)• <iterator> – istream_iterator (デフォルトコンストラクタのみ) – istreambuf_iterator (デフォルトコンストラクタのみ)
  • 67. ◆標準ライブラリ• <complex> – complex• <random> – 各種⽣成器クラス (min, max のみ)• <regex> – sub_match (デフォルトコンストラクタのみ)• <atomic> – atomic (コンストラクタのみ)• <mutex> – mutex (デフォルトコンストラクタのみ)
  • 68. ◆標準ライブラリ• 標準ライブラリの⽅針としては、「通常 の使⽤において、ほぼ⾃明にコンパイル 時処理にできる」ものだけを constexpr 指定しているようだ – bitset – ratio – chrono など• numeric_limits が使える⼦になった• 保守的な⽅針
  • 69. ◆libstdc++ 独⾃拡張 (GCC 4.7 experimental)• <cmath> – 各種関数• <tuple> – tuple• <utility> – forward, move
  • 70. ◆libstdc++ 独⾃拡張• <cmath> が constexpr 化されてるのが ⼤きい – これに依存する前提なら多くの数学計算の constexpr 化が楽になる• なんで <array> が constexpr じゃない のか……
  • 71. ◆CEL - ConstExpr Library• 作者: RiSK (@sscrisk) さん – https://github.com/sscrisk/CEL---ConstExpr-Library• <algorithm>• <numeric>• <cstdlib>• <cstring>• <iterator> – 各種アルゴリズム (⾮ Mutating な部分)
  • 72. ◆CEL - ConstExpr Library• <cctype> – ⽂字列判定• <functional> – 関数オブジェクト• <array> – array• <utility> – pair
  • 73. ◆CEL - ConstExpr Library• 標準ライブラリの関数の「シグネチャの 変更なしに constexpr 化できるもの」を ほぼ⼀通りカバーしている
  • 74. ◆Sprout C++ Library• constexpr ⽂字列• constexpr タプル• constexpr バリアント• constexpr アルゴリズム• constexpr 範囲アルゴリズム• constexpr コンテナ操作• constexpr 乱数• constexpr ハッシュ関数• constexpr UUID• constexpr 構⽂解析• constexpr レイトレーシング
  • 75. ◆constexpr ⽂字列• Sprout.String #include <sprout/string.hpp> #include <iostream> int main() { using namespace sprout; constexpr string<6> hello = to_string("Hello "); constexpr string<6> world = to_string("world!"); constexpr auto str = hello + world; std::cout << str << "¥n"; // "Hello world!" constexpr auto hell = str.substr(0, 4); std::cout << hell << "¥n"; // "Hell" }
  • 76. ◆constexpr ⽂字列• Sprout.String #include <sprout/string.hpp> #include <iostream> 型には要素数(最⼤⽂字数)が含まれる int main() { using namespace sprout; constexpr string<6> hello = to_string("Hello "); constexpr string<6> world = to_string("world!"); 要素数が増える場合: constexpr auto str = hello + world; string<N> + string<M> std::cout << str << "¥n"; // "Hello world!" → string<N + M> constexpr auto hell = str.substr(0, 4); std::cout << hell << "¥n"; // "Hell" 要素数が減る場合: } string<N>::substr → string<N>
  • 77. ◆constexpr ⽂字列• Sprout.String 実装 namespace sprout { template<class T, size_t N, Traits = char_traits<T> > class basic_string { T elems [N + 1]; ヌル終端を含めた固定⻑バッファ size_t len; }; ⽂字列⻑ (len <= N) }• ⽂字列⻑が変わる操作: – 静的に決定できる場合は型レベルで解決 – そうでなければ len を弄って変更 – あるいはユーザ側に最⼤⻑を指定させる
  • 78. ◆constexpr アルゴリズム• Sprout.Algorithm #include <sprout/algorithm.hpp> #include <iostream> int main() { using namespace sprout; constexpr auto arr = make_array<int>(5, 1, 9, 4, 8, 2, 7, 3, 10, 6); 配列をソート constexpr auto sorted = sort(arr); for (auto i : sorted) { std::cout << i << ; } std::cout << "¥n"; // 1 2 3 4 5 6 7 8 9 10 配列を反転 constexpr auto reversed = reverse(sorted); for (auto i : reversed) { std::cout << i << ; } std::cout << "¥n"; // 10 9 8 7 6 5 4 3 2 1 }
  • 79. ◆constexpr アルゴリズム• Sprout.Algorithm – 主に Mutating sequence operations をカバーする• CEL と合わせれば STL のアルゴリズムはほぼ全てカ バーできる• RandomAccessIterator に対しては index_tuple イ ディオムで効率的に処理する – ユーザ側で sprout::next/prev をオーバーロードすることで InputIterator なども渡せる• それ以外の IteratorCategory は Variadic Function で 実装されている
  • 80. ◆constexpr 乱数• Sprout.Random #include <sprout/random.hpp> #include <sprout/random/unique_seed.hpp> #include <sprout/array.hpp> #include <sprout/algorithm.hpp> #include <iostream> int main() { using namespace sprout; constexpr auto arr = make_array<int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); constexpr std::size_t seed = SPROUT_UNIQUE_SEED; constexpr auto engine = minstd_rand0(seed); constexpr auto distribution = uniform_smallint<int>(1, 6); constexpr auto shuffled = shuffle(arr, random::combine(engine, distribution)); for (auto i : shuffled) { std::cout << i << ; } std::cout << "¥n"; }
  • 81. ◆constexpr 乱数• Sprout.Random #include <sprout/random.hpp> #include <sprout/random/unique_seed.hpp> #include <sprout/array.hpp> #include <sprout/algorithm.hpp> ⽇時とファイル名と⾏の #include <iostream> ⽂字列からハッシュ値を ⽣成するマクロ int main() { using namespace sprout; constexpr auto arr = make_array<int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); constexpr std::size_t seed = SPROUT_UNIQUE_SEED; 線形合同法エンジン constexpr auto engine = minstd_rand0(seed); constexpr auto distribution = uniform_smallint<int>(1, 6); 整数⼀様分布 constexpr auto shuffled = shuffle(arr, random::combine(engine, distribution)); for (auto i : shuffled) { std::cout << i << ; } std::cout << "¥n"; ランダムシャッフル }
  • 82. ◆constexpr 乱数• Sprout.Random – <random> と同じく様々な乱数⽣成器と分布を提供する• 関数型⾔語にならって、乱数⽣成器は「⽣成した値」 「次の状態の⽣成器」のペアを返す仕様• コンパイル時に取得できる値でシードに使えるものが __DATA__ __FILE__ __LINE__ くらいしかないので それを使う
  • 83. ◆constexpr 構⽂解析• Sprout.Weed #include <sprout/weed.hpp> #include <sprout/string.hpp> #include <sprout/uuid.hpp> Int main() { using namespace sprout; using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p = repeat[lim<16>(hex8f)] | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); }
  • 84. ◆constexpr 構⽂解析• Sprout.Weed #include <sprout/weed.hpp> #include <sprout/string.hpp> #include <sprout/uuid.hpp> hex8f : 8bit16進数にマッチ Int main() { using namespace sprout; using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p = repeat[lim<16>(hex8f)] | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); }
  • 85. ◆constexpr 構⽂解析• Sprout.Weed #include <sprout/weed.hpp> #include <sprout/string.hpp> repeat : lim<N>回の繰り返し #include <sprout/uuid.hpp> array<Attr, N * M> Int main() { using namespace sprout; using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p = repeat[lim<16>(hex8f)] | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); }
  • 86. ◆constexpr 構⽂解析• Sprout.Weed #include <sprout/weed.hpp> #include <sprout/string.hpp> >> : パーサの連結 #include <sprout/uuid.hpp> array<Attr, N + M> Int main() { using namespace sprout; using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p = repeat[lim<16>(hex8f)] | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); }
  • 87. ◆constexpr 構⽂解析• Sprout.Weed #include <sprout/weed.hpp> #include <sprout/string.hpp> | : パーサのOR #include <sprout/uuid.hpp> variant<Attr1, Attr2> Int main() { using namespace sprout; using namespace sprout::weed; constexpr auto s = to_string("{550E8400-E29B-41D4-A716-446655440000}"); constexpr auto unbracket_uuid_p = repeat[lim<16>(hex8f)] | repeat[lim<4>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<2>(hex8f)] >> - >> repeat[lim<6>(hex8f)]; constexpr auto uuid_p = (unbracket_uuid_p | { >> unbracket_uuid_p >> }) >> eoi; constexpr auto parsed = parse(s.begin(), s.end(), uuid_p); }
  • 88. ◆constexpr 構⽂解析• Sprout.Weed – Boost.Spirit.Qi のような Expression Template ベースの EDSL 構⽂解析ライブラリ• Expression Template 技法では、処理が細かい単位に 分割されるので、constexpr 化しやすい• constexpr の導⼊によって、コンパイル時⽂字列処理が 相当⼿軽に出来るようになった• おそらく今後 constexpr 正規表現などのライブラリも 出てくると思われる
  • 89. ◆constexpr レイトレーシング• Sprout.Darkroom
  • 90. ◆constexpr レイトレーシング• Sprout.Darkroom #include <sprout/darkroom.hpp> 512×512 pixel #include <iostream> で作成 static constexpr std::size_t total_width = 512; static constexpr std::size_t total_height = 512; static constexpr std::size_t tile_width = 16; static constexpr std::size_t tile_height = 16; static constexpr std::size_t offset_x = 0; static constexpr std::size_t offset_y = 0; using namespace sprout; using namespace sprout::darkroom;
  • 91. ◆constexpr レイトレーシング• Sprout.Darkroom constexpr auto object = make_tuple( objects::make_sphere( coords::vector3d(-1.0, -0.5, 5.0), 1.0, オブジェクトの定義 materials::make_material_image( (2つの球) colors::rgb_f(1.0, 0.75, 0.75), 0.2) ), objects::make_sphere( coords::vector3d(0.5, 0.5, 3.5), 1.0, materials::make_material_image( colors::rgb_f(0.75, 0.75, 1.0), 0.2) ) );
  • 92. ◆constexpr レイトレーシング• Sprout.Darkroom 光源の定義 (点光源) constexpr auto light = lights::make_point_light( coords::vector3d(1.0, 0.5, 1.0), colors::rgb_f(3.0, 3.0, 3.0)); constexpr auto camera = cameras::make_simple_camera(1.0); constexpr auto renderer = renderers::whitted_style(); constexpr auto raytracer = tracers::raytracer<>(); カメラ レンダラ レイトレーサー
  • 93. ◆constexpr レイトレーシング• Sprout.Darkroom ピクセル⽣成 typedef pixels::color_pixels<tile_width, tile_height>::type image_type; constexpr auto image = pixels::generate<image_type>( raytracer, renderer, camera, object, light, offset_x, offset_y, total_width, total_height);
  • 94. ◆constexpr レイトレーシング• Sprout.Darkroom std::cout << "P3" << std::endl << image[0].size() << << image.size() << std::endl << 255 << std::endl ; for (auto const& line : image) { 標準出⼒へ for (auto const& pixel : line) { ppm 形式で出⼒ std::cout << unsigned(colors::r(pixel)) << << unsigned(colors::g(pixel)) << << unsigned(colors::b(pixel)) << std::endl; } } }
  • 95. ◆constexpr レイトレーシング• Sprout.Darkroom – metatrace という TMP ライブラリを元にした constexpr レイ トレーサーライブラリ• レイトレーシングの基本的なアルゴリズムはとてもシン プル• 視点から各ピクセルを通る光線を⾶ばして、ベクトルが オブジェクトと衝突する部分の拡散光と反射光の成分を 得るだけ
  • 96. ◆次期 C++1x に期待すること• いくつかのポインタ演算を定数式扱いにp1 < p2; ポインタの⼤⼩⽐較はできないp1 - p2; ポインタ同⼠の減算はできないstatic_cast<int const*>( static_cast<void const*>(p) ) void* から他の型への読み替えはできない• union の任意のメンバでの初期化を定数式扱いにunion U { X x; Y y; constexpr U() : y() { }}; 先頭メンバ以外での初期化はできない
  • 97. ◆次期 C++1x に期待すること• ラムダ式を定数式扱いにtemplate<class F>constexpr auto call(F f) -> decltype(f()) { return f(); }call( []{ return 0; } ); constexpr 関数にラムダ式を渡せない• new/delete を定数式に出来るように• 標準ライブラリを更に constexpr 化
  • 98. ◆constexpr 化できそうなもの• 正規表現 – Regex / Expressive• 汎⽤ Expression Template – Proto• シリアライズ – Serialization• 画像処理 – GIL• 数学関数 – Math.SpecialFunction• etc...
  • 99. ◆まとめ• constexpr で表現可能な応⽤範囲はとて も広い• コーディング上の制約と落とし⽳は多い ので気をつける• 数値計算が得意分野• constexpr で遊ぼう!
  • 100. ご静聴ありがとう ございました

×