Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

30,322 views

Published on

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

Published in: Technology
  • Be the first to comment

中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. ご清聴 ありがとうございました

×