中3女子が狂える本当に気持ちのいい constexpr

24,777 views
25,208 views

Published on

Boost.勉強会 #8 中3女子が狂える本当に気持ちのいい constexpr

Published in: Technology
0 Comments
16 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
24,777
On SlideShare
0
From Embeds
0
Number of Embeds
8,614
Actions
Shares
0
Downloads
73
Comments
0
Likes
16
Embeds 0
No embeds

No notes for slide

中3女子が狂える本当に気持ちのいい constexpr

  1. 1. 中3女子が狂える 本当に 気持ちのいい constexprBoost.勉強会 #8bolero_MURAKAMI2012/2/11
  2. 2. ◆⾃⼰紹介• 名前 : 村上 原野 (むらかみ げんや) @bolero_MURAKAMI, id:boleros• 棲息地: ⼤都会岡⼭• 仕事 : 猪⾵来美術館 陶芸指導員 ・普段はやきものの修⾏をしたり、 縄⽂⼟器をつくったりしています ・趣味は constexpr です
  3. 3. ◆⾃⼰紹介• 開催中: – 村上原野 縄⽂⼟器展 『ハロー、縄⽂!』 〜2012/3/4
  4. 4. ◆⾃⼰紹介• 公開しているライブラリ: Sprout C++ Library (constexpr ライブラリ) github.com/bolero-MURAKAMI/Sprout• 前回発表資料: 【中3⼥⼦でもわかる constexpr】 www.slideshare.net/GenyaMurakami
  5. 5. ◆アジェンダ• はじめに• constexpr おさらい• constexpr と TMP の連携• (続)constexpr レイトレーシング• まとめ
  6. 6. ◆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{ }; // クラスインスタンスを定数式に
  7. 7. ◆constexpr とは?• constexpr 関数の制限 template<class T> 関数テンプレートも constexpr T square(T const& n) { constexpr 指定できる static_assert( true, “” ); // static_assert( n != 0, “” ); typedef T t1; using t2 = T; using std::ptrdiff_t; using namespace std; return n * n; } – static_assert, typedef, using, 及び⾼々1つの return ⽂のみ を書くことができる – 引数は定数式にならない
  8. 8. ◆C++ プログラミングのレイヤー C++03 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング(ライブラリアンが多数棲息) 定数式 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  9. 9. ◆C++ プログラミングのレイヤー C++11 [処理されるもの] [プログラマのすること] プリプロセス時の世界 プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング(ライブラリアンが多数棲息) 定数式 constexpr 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  10. 10. ◆C++ プログラミングのレイヤー C++11 [処理されるもの] [プログラマのすること] プリプロセス時の世界 連携したい プリプロセッサ (魔界) ソースコード メタプログラミング テンプレート 型 コンパイル時の世界 メタプログラミング(ライブラリアンが多数棲息) 定数式 constexpr 実⾏時の世界 実⾏時オブジェクト (⼈間界) 通常の プログラミング
  11. 11. ◆Sprout C++ Library• constexpr ⽂字列• constexpr タプル• constexpr バリアント• constexpr アルゴリズム• constexpr 範囲アルゴリズム• constexpr コンテナ操作• constexpr 乱数• constexpr ハッシュ関数• constexpr UUID• constexpr 構⽂解析• constexpr レイトレーシング
  12. 12. ◆Sprout C++ Library• constexpr ⽂字列 #include <sprout/string.hpp> #include <sprout/algorithm.hpp> /* コンパイル時文字列 */ static constexpr auto hello = sprout::to_string("Hello,world!"); static_assert( hello == "Hello,world!", "" ); /* 文字列連結 */ static_assert( hello + "!!!" == "Hello,world!!!!", "" ); /* 文字列切り出し */ static_assert( hello.substr(0, 5) == "Hello", "" ); /* 文字列反転 */ static_assert( sprout::reverse(hello) == "!dlrow,olleH", "" );
  13. 13. ◆Sprout C++ Library• constexpr ⽂字列 #include <sprout/string.hpp> #include <sprout/algorithm.hpp> /* コンパイル時文字列 */ static constexpr auto hello = sprout::to_string("Hello,world!"); static_assert( hello == "Hello,world!", "" ); /* 文字列連結 */ static_assert( hello + "!!!" == "Hello,world!!!!", "" ); /* 文字列切り出し */ static_assert( hello.substr(0, 5) == "Hello", "" ); /* 文字列反転 */ static_assert( sprout::reverse(hello) == "!dlrow,olleH", "" ); このように、constexpr で様々なクラスを とてもわかりやすく簡単に扱うことができる。
  14. 14. ◆constexpr と TMP の連携• クラステンプレートにコンパイル時定数 を渡すには• index_tuple idiom• 型⽂字列と constexpr ⽂字列の相互変換
  15. 15. ◆クラステンプレートにコンパイル時定数を渡すには• 整数型を渡すtemplate<int W, int H> RectArea { static constexpr int value = W * H;};static constexpr int w = 50;static constexpr int h = 100;static_assert( RectArea<w, h>::value == 5000, “” )
  16. 16. ◆クラステンプレートにコンパイル時定数を渡すには• 整数型を渡す 整数型はテンプレート引数にtemplate<int W, int H> RectArea { そのまま渡せる static constexpr int value = W * H;};static constexpr int w = 50;static constexpr int h = 100;static_assert( RectArea<w, h>::value == 5000, “” )
  17. 17. ◆クラステンプレートにコンパイル時定数を渡すには• 整数型以外のオブジェクトを渡すには?struct Rect { int w; int h; };template< ??? >struct Area { static constexpr int value = ???;};
  18. 18. ◆クラステンプレートにコンパイル時定数を渡すには• 整数型以外のオブジェクトを渡すには?struct Rect { int w; int h; }; このクラスのインスタンスを テンプレートに渡したいtemplate< ??? >struct Area { テンプレート引数を static constexpr int value = ???; どう書けばいい?};
  19. 19. ◆クラステンプレートにコンパイル時定数を渡すには• クラスを直接テンプレート引数にしてみるtemplate<Rect V>struct Area { static constexpr int value = V.w * V.h;};static constexpr Rect rect = {10, 20};static_assert( Area<rect>::value == 200, “” );
  20. 20. ◆クラステンプレートにコンパイル時定数を渡すには• クラスを直接テンプレート引数にしてみるtemplate<Rect V> コンパイルエラー!!struct Area { static constexpr int value = V.w * V.h;};static constexpr Rect rect = {10, 20};static_assert( Area<rect>::value == 200, “” );• クラス型をテンプレート引数にすることはできない• 論外
  21. 21. ◆クラステンプレートにコンパイル時定数を渡すには• ポインタをテンプレート引数にしてみるtemplate<Rect const* P>struct Area { static constexpr int value = P->w * P->h;};static constexpr Rect rect = {10, 20};static_assert( Area<&rect>::value == 200, “” );
  22. 22. ◆クラステンプレートにコンパイル時定数を渡すには• ポインタをテンプレート引数にしてみるtemplate<Rect const* P>struct Area { static constexpr int value = P->w * P->h;}; OK!static constexpr Rect rect = {10, 20};static_assert( Area<&rect>::value == 200, “” );• ポインタ型をテンプレート引数にすることは可能
  23. 23. ◆クラステンプレートにコンパイル時定数を渡すには• ポインタをテンプレート引数にしてみるtemplate<Rect const* P>struct Area { static constexpr int value = P->w * P->h;};int main() { static constexpr Rect rect = {10, 20}; static_assert( Area<&rect>::value == 200, “” );}
  24. 24. ◆クラステンプレートにコンパイル時定数を渡すには• ポインタをテンプレート引数にしてみるtemplate<Rect const* P>struct Area { static constexpr int value = P->w * P->h;};int main() { コンパイルエラー!! static constexpr Rect rect = {10, 20}; static_assert( Area<&rect>::value == 200, “” );}• テンプレート引数に渡せる値 – 整数型 / リンケージを持つオブジェクト• ローカル変数、⼀時オブジェクト、⽂字列リテラル等を テンプレート引数に渡すことはできない
  25. 25. ◆クラステンプレートにコンパイル時定数を渡すには• プロキシクラスをテンプレート引数にしてみるtemplate<class Proxy>struct Area { static constexpr int value = Proxy()().w * Proxy()().h;};int main() { static constexpr Rect rect = {10, 20}; struct proxy { constexpr Rect const& operator()() const { return rect; } }; static_assert( Area<proxy>::value == 200, “” );}
  26. 26. ◆クラステンプレートにコンパイル時定数を渡すには• プロキシクラスをテンプレート引数にしてみる template<class Proxy> struct Area { プロキシを介して値を取得 static constexpr int value = Proxy()().w * Proxy()().h; }; int main() { proxy クラスの operator() は static constexpr Rect rect = {10, 20}; ローカル変数の Rect を返す struct proxy { constexpr Rect const& operator()() const { return rect; } }; static_assert( Area<proxy>::value == 200, “” ); } OK!• 短所 – プロキシクラスをいちいち定義しなければならない
  27. 27. ◆クラステンプレートにコンパイル時定数を渡すには• ポインタをテンプレート引数にする⽅法template<Object const* P>struct TemplateClass; – リンケージを持つオブジェクト(グローバル変数)しか渡すこと ができない• プロキシクラスをテンプレート引数にする⽅法template<class Proxy>struct TemplateClass; – その都度プロキシクラスを作成する必要がある – (プロキシの定義をマクロにすれば多少書きやすいかも)
  28. 28. ◆index_tuple idiom• index_tuple と index_range ヘルパ template<ptrdiff_t... Indexes> struct index_tuple; template<ptrdiff_t First, ptrdiff_t Last> struct index_range; static_assert( std::is_same< index_range<0, 5>::type, index_tuple<0, 1, 2, 3, 4> >::value, “” );
  29. 29. ◆index_tuple idiom• index_tuple と index_range ヘルパ template<ptrdiff_t... Indexes> パラメータパックを struct index_tuple; pack expansion expression (Indexes...) で使う template<ptrdiff_t First, ptrdiff_t Last> struct index_range; (First .. Last] の index_tuple を⽣成する static_assert( std::is_same< ヘルパメタ関数 index_range<0, 5>::type, index_tuple<0, 1, 2, 3, 4> >::value, “” );
  30. 30. ◆index_tuple idiom• TMP で index_tuple を使う #include <sprout/index_tuple.hpp> #include <boost/mpl/vector.hpp> template<class Seq, class IndexTuple> struct to_tuple_impl; template<class Seq, ptrdiff_t... Indexes> struct to_tuple_impl<Seq, index_tuple<Indexes...> > { typedef tuple< mpl::at_c<Seq, Indexes>... > type; }; /* MPLシーケンスから tuple への変換 */ template<class Seq> struct to_tuple : to_tuple_impl< Seq, typename index_range<0, mpl::size<Seq>::value>::type > { }; typedef mpl::vector<int, double> vec; static_assert( is_same<to_tuple<vec>::type, tuple<int, double> >::value, “” );
  31. 31. ◆index_tuple idiom• TMP で index_tuple を使う #include <sprout/index_tuple.hpp> #include <boost/mpl/vector.hpp> index_tuple<Indexes...> で template<class Seq, class IndexTuple> テンプレート引数を特殊化する struct to_tuple_impl; template<class Seq, ptrdiff_t... Indexes> struct to_tuple_impl<Seq, index_tuple<Indexes...> > { typedef tuple< mpl::at_c<Seq, Indexes>... > type; }; /* MPLシーケンスから tuple への変換 */ pack expansion expression で template<class Seq> Indexes を使ったリストに展開する struct to_tuple : to_tuple_impl< Seq, typename index_range<0, mpl::size<Seq>::value>::type > { }; index_range で index_tuple を ⽣成して実装に丸投げ typedef mpl::vector<int, double> vec; static_assert( is_same<to_tuple<vec>::type, tuple<int, double> >::value, “” );
  32. 32. ◆index_tuple idiom• constexpr 関数で index_tuple を使う #include <sprout/index_tuple.hpp> #include <sprout/array.hpp> template<class T, size_t N, ptrdiff_t...Indexes> constexpr array<T, N> to_array_impl(T const (& arr)[N], index_tuple<Indexes...>) { return array<T, N>{{ arr[Indexes]... }}; } /* 生配列から sprout::array への変換 */ template<class T, size_t N> constexpr array<T, N> to_array(T const (& arr)[N]) { return to_array_impl(arr, typename index_range<0, N>::type()); } static constexpr int arr[2] = { 1, 2 }; static constexpr array<int, 2> s = to_array(arr);
  33. 33. ◆index_tuple idiom• constexpr 関数で index_tuple を使う #include <sprout/index_tuple.hpp> index_tuple<Indexes...> #include <sprout/array.hpp> を引数にして推論させる template<class T, size_t N, ptrdiff_t...Indexes> constexpr array<T, N> to_array_impl(T const (& arr)[N], index_tuple<Indexes...>) { return array<T, N>{{ arr[Indexes]... }}; } pack expansion expression で /* 生配列から sprout::array への変換 */ Indexes を使ったリストに展開する template<class T, size_t N> constexpr array<T, N> to_array(T const (& arr)[N]) { return to_array_impl(arr, typename index_range<0, N>::type()); } index_range で index_tuple を static constexpr int arr[2] = { 1, 2 }; ⽣成して実装に丸投げ static constexpr array<int, 2> s = to_array(arr);
  34. 34. ◆index_tuple idiom• index_tuple イディオムは、インデックスアクセス可能 なデータ構造⼀般に適⽤できる – 配列 – タプル – ランダムアクセスイテレータ – 型リスト• constexpr に限らず、通常の関数や TMP にも同じよう に応⽤できる• ただしインデックスアクセス不可なデータ構造には適⽤ できない – ⾮ランダムアクセスなイテレータなど
  35. 35. ◆型⽂字列と constexpr ⽂字列の相互変換• 型⽂字列 typedef mpl::string< ‘Hell’, ‘o,wo’, ‘rld!’ > hello_t; – ⽂字列は可変⻑テンプレート引数で表現される – ⽂字列リテラルは使えない • (マクロの⿊魔術を使えば制限付きで可能ではある)• constexpr ⽂字列 static constexpr auto hello = sprout::to_string( “Hello,world!” ); – コンパイル時定数である – ⽂字列リテラルが使⽤可能• これらを相互に変換できるようにしたい
  36. 36. ◆型⽂字列と constexpr ⽂字列の相互変換• mpl::string → sprout::string #include <type_traits> #include <sprout/index_tuple.hpp> #include <sprout/type.hpp> #include <sprout/string.hpp> #include <sprout/type/boost/mpl/string.hpp> using namespace std; using namespace sprout; namespace mpl = boost::mpl; namespace types = sprout::types;
  37. 37. ◆型⽂字列と constexpr ⽂字列の相互変換• mpl::string → sprout::string /* T::value がナル文字であるか返すメタ関数クラス */ struct is_nul { template<class T, class = void> struct apply : false_type { }; template<class T> struct apply<T, typename enable_if<T::value == 0>::type> : true_type { }; }; /* ナル文字までの文字列長 */ template<class Seq> struct str_length : types::distance< typename types::begin<Seq>::type, typename types::seq::find_if<Seq, is_nul>::type > { };
  38. 38. ◆型⽂字列と constexpr ⽂字列の相互変換• mpl::string → sprout::string template<class Seq, ptrdiff_t... Indexes> constexpr sprout::basic_string< typename Seq::value_type, str_length<Seq>::value > to_sprout_string_impl( index_tuple<Indexes...> ) { return sprout::make_string_as<typename Seq::value_type>( types::tuple_element<Indexes, Seq>::type::value... ); } /* sprout::string に変換 */ template<class Seq> constexpr sprout::basic_string< typename Seq::value_type, str_length<Seq>::value > to_sprout_string() { return to_sprout_string_impl<Seq>( typename index_range<0, str_length<Seq>::value>::type() ); }
  39. 39. ◆型⽂字列と constexpr ⽂字列の相互変換• mpl::string → sprout::string template<class Seq, ptrdiff_t... Indexes> constexpr sprout::basic_string< index_tuple<Indexes...> を typename Seq::value_type, 実装関数で受け取る str_length<Seq>::value > to_sprout_string_impl( index_tuple<Indexes...> ) { return sprout::make_string_as<typename Seq::value_type>( types::tuple_element<Indexes, Seq>::type::value... ); Indexes を使ってシーケンス要素の } ⽂字のリストに展開 /* sprout::string に変換 */ template<class Seq> constexpr sprout::basic_string< basic_string<Elem, Length> typename Seq::value_type, str_length<Seq>::value index_range で index_tuple を > to_sprout_string() { ⽣成して実装に丸投げ return to_sprout_string_impl<Seq>( typename index_range<0, str_length<Seq>::value>::type() ); }
  40. 40. ◆型⽂字列と constexpr ⽂字列の相互変換• mpl::string → sprout::string typedef mpl::string< ‘foo’, ‘bar’ > type; static constexpr auto s = to_sprout_string<type>(); static_assert( s == “foobar”, “” ); mpl::string (型)から sprout::string (コンパイル時定数)へ変換• ⼀般に【型→値】の変換は⾃明に書ける(場合が多い)
  41. 41. ◆型⽂字列と constexpr ⽂字列の相互変換• sprout::string → mpl::string #include <type_traits> #include <sprout/index_tuple.hpp> #include <sprout/fixed_container.hpp> #include <sprout/string.hpp> #include <boost/mpl/string.hpp> #include <boost/preprocessor/cat.hpp> using namespace std; using namespace sprout; namespace mpl = boost::mpl;
  42. 42. ◆型⽂字列と constexpr ⽂字列の相互変換• sprout::string → mpl::string template<class Proxy> struct to_mpl_string { template<class IndexTuple> struct impl; template<ptrdiff_t... Indexes> struct impl<index_tuple<Indexes...> > { typedef mpl::string< sprout::begin(Proxy()())[Indexes]... > type; }; /* mpl::string に変換 */ typedef class impl< typename index_range<0, sprout::size(Proxy()())>::type >::type type; };
  43. 43. ◆型⽂字列と constexpr ⽂字列の相互変換• sprout::string → mpl::string template<class Proxy> index_tuple<Indexes...> を struct to_mpl_string { 実装メタ関数で受け取る template<class IndexTuple> struct impl; template<ptrdiff_t... Indexes> struct impl<index_tuple<Indexes...> > { typedef mpl::string< mpl::string<Elem...> sprout::begin(Proxy()())[Indexes]... > type; }; Indexes を使ってシーケンス要素の /* mpl::string に変換 */ ⽂字のリストに展開 typedef class impl< typename index_range<0, sprout::size(Proxy()())>::type >::type type; }; index_range で index_tuple を ⽣成して実装に丸投げ
  44. 44. ◆型⽂字列と constexpr ⽂字列の相互変換• sprout::string → mpl::string /* 変換結果を typedef するマクロ*/ #define STRING_CLASS_TYPEDEF(SOURCE, TYPE) ¥ struct BOOST_PP_CAT(PROXY_, __LINE__) { ¥ constexpr typename remove_reference<decltype(SOURCE)>::type ¥ operator() () const { return SOURCE; } ¥ }; ¥ typedef typename to_mpl_string< ¥ BOOST_PP_CAT(PROXY_, __LINE__) ¥ >::type TYPE
  45. 45. ◆型⽂字列と constexpr ⽂字列の相互変換• sprout::string → mpl::string PROXY_127 のような名前の プロキシクラスが定義される /* 変換結果を typedef するマクロ*/ #define STRING_CLASS_TYPEDEF(SOURCE, TYPE) ¥ struct BOOST_PP_CAT(PROXY_, __LINE__) { ¥ constexpr typename remove_reference<decltype(SOURCE)>::type ¥ operator() () const { return SOURCE; } ¥ }; ¥ operator() は変換元ソースを typedef typename to_mpl_string< ¥ そのまま返す constexpr 関数 BOOST_PP_CAT(PROXY_, __LINE__) ¥ >::type TYPE 定義したプロキシクラスを渡す
  46. 46. ◆型⽂字列と constexpr ⽂字列の相互変換• sprout::string → mpl::string #include <boost/mpl/equal.hpp> sprout::string (コンパイル時定数)から mpl::string (型)へ変換 static constexpr auto s = sprout::to_string( “foobar” ); STRING_CLASS_TYPEDEF(s, type); static_assert( mpl::equal< type, mpl::string<foo, bar> >::value, “” );• 【値→型】の変換は⼯夫次第で可能• ⽋点 – ⾃明な書き⽅ができない(場合が多い) – プロキシクラスの定義が必要な場合、インラインに書けないし、 constexpr 関数の中で使えない
  47. 47. ◆constexpr と TMP の連携• 整数型以外のコンパイル時定数でも、テンプ レートに受け渡す⽅法はある• index_tuple イディオムや、プロキシクラス等 を活⽤することで、constexpr と TMP の間で 相互にやりとりをすることができる
  48. 48. ◆(続)constexpr レイトレーシング• Sprout.Darkroom – metatrace という TMP ライブラリを元にした constexpr レイ トレーサーライブラリ
  49. 49. ◆(続)constexpr レイトレーシング• 2つの球(Boost.勉強会#7 東京時点)
  50. 50. ◆(続)constexpr レイトレーシング• 鏡の部屋の2つの球
  51. 51. ◆(続)constexpr レイトレーシング• 鏡の部屋の2つの球(市松模様の床)
  52. 52. ◆(続)constexpr レイトレーシング• 地球のような何か
  53. 53. ◆(続)constexpr レイトレーシング• エレメント(カラーやスペキュラ)を表現するにはtemplate<typename Element, typename Scale>class plaid_element {private: Element elem1_; Element elem2_; Scale scale_; template<typename Unit> constexpr Element calc_1(Unit const& u, Unit const& v) const { return (u >= 0 && v >= 0) || (u < 0 && v < 0) ? elem1_ : elem2_; }public: template<typename Unit> constexpr Element operator() (Unit const& u, Unit const& v) const { return calc_1( (u < 0 ? scale_ + fmod(u, scale_) : fmod(u, scale_)) - scale_ / 2, (v < 0 ? scale_ + fmod(v, scale_) : fmod(v, scale_)) - scale_ / 2 ); }};
  54. 54. ◆(続)constexpr レイトレーシング• エレメント(カラーやスペキュラ)を表現するにはtemplate<typename Element, typename Scale>class plaid_element {private: 市松模様を表現するエレメント Element elem1_; Element elem2_; 座標を⼆つに分けて Scale scale_; どちらかのエレメント(⽩/⿊など)を返す template<typename Unit> constexpr Element calc_1(Unit const& u, Unit const& v) const { return (u >= 0 && v >= 0) || (u < 0 && v < 0) ? elem1_ : elem2_; エレメントのコンセプトは } uv 座標を受け取って結果を返すpublic: operator()(u, v) を持つこと template<typename Unit> constexpr Element operator() (Unit const& u, Unit const& v) const { return calc_1( (u < 0 ? scale_ + fmod(u, scale_) : fmod(u, scale_)) - scale_ / 2, (v < 0 ? scale_ + fmod(v, scale_) : fmod(v, scale_)) - scale_ / 2 ); }};
  55. 55. ◆(続)constexpr レイトレーシング• テクスチャマップを読み込むには#include <sprout/darkroom.hpp>/* ファイル "earth.tex.hpp" の内容を tex に読み込む */#define DARKROOM_DEF_LOAD_TEXTURE_IDENTIFIER tex#define DARKROOM_DEF_LOAD_TEXTURE_FILE "earth.tex.hpp"#include DARKROOM_LOAD_TEXTURE – earth.png
  56. 56. ◆(続)constexpr レイトレーシング• テクスチャマップを読み込むには#include <sprout/darkroom.hpp>/* ファイル "earth.tex.hpp" の内容を tex に読み込む */#define DARKROOM_DEF_LOAD_TEXTURE_IDENTIFIER tex#define DARKROOM_DEF_LOAD_TEXTURE_FILE "earth.tex.hpp"#include DARKROOM_LOAD_TEXTURE – 擬似コード/* 実装は include ディレクティブで CVS を取りこむトリックと同じような感じ */constexpr auto tex {# include "earth.tex.hpp"}; “earth.tex.hpp” の中⾝は コンマ区切りのピクセルデータのようなもの
  57. 57. ◆まとめ• constexpr を活⽤することで、『型』 『オブジェクト』『外部データ』等さま ざまなソースを、コンパイル時に相互に 扱うことができる• constexpr でもっともっと遊ぼう!!
  58. 58. ご清聴 ありがとうございました

×