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,535 views

Published on

Published in: Technology
  • Be the first to comment

闇魔術を触ってみた

  1. 1. 闇魔術を触ってみた KMC ID:dtyazsk
  2. 2. 自己紹介 • K都大学に通う理学部生 • 例会講座(FizzBuzz)と春合宿講座(文字列型までがんばる)のせいで もしかしたらコンパイル時処理狂と思われているかもだが 普段はVC++とDXライブラリでゲーム作ってます(constexprがない) • 冷やしF#始めました
  3. 3. 闇魔術is • C++のことではない • C++にはboostってライブラリがある • そこにめっちゃヤバイライブラリがある
  4. 4. BOOST_PP • boost¥preprocessor.hppに入ってるマクロ群 • 本講座でやったコンパイル時より前、プリプロセス時にやる闇魔術 • TMPとかではできないとんでもないことができる • 一昨日唐突に使いたくなった • C言語でも使えるのかなぁ(誰か試してぽよ) • C++的コードに組み込んで使用例にしてますが別にC的な使い方も出来ます
  5. 5. 例えば BOOST_PP_ADD • 足し算してくれる • 例えばBOOST_PP_ADD(3,5)で8に展開される BOOST_PP_BOOL • 渡したものが1から255に展開されるなら1、そうでないなら0 • 例えばBOOST_PP_BOOL(10)で1に展開される • 闇っぽくないな?
  6. 6. プリプロセッサでは • 型も値もクソもなく2+5とかいう式も評価されない • すなわちさっきのマクロではきちんと5とかで渡さないといけない • 例えばBOOST_PP_BOOLでtrueとか渡しても機能しないので注意 • 数値に展開されるマクロならおk • ただ大きすぎるとマクロの再帰深度限界に達するらしい… • どういう実装してるんだ
  7. 7. 他にも BOOST_PP_CAT • トークン名結合 • BOOST_PP_CAT(text,2)でtext2に展開される • 何かと便利(index_tupleイディオムのヘルパーで使おうと考えてた) BOOST_PP_STRINGIZE • 渡したトークンを文字列化する • static_assertの第2引数に渡すこともできる • 他にもなんか使えそう
  8. 8. BOOST_PP_CATを使ってみる • とりあえずindex_tupleとindex_countが定義されてるとする • これらについては本講座のスライド参照 #define INDEX_COUNT(from,to)¥ template<class>class BOOST_PP_CAT(index_count_help_, from); ¥ template<int... Nums>¥ class BOOST_PP_CAT(index_count_help_, from)¥ <index_tuple<Nums...>>{¥ public:¥ using type = from <Nums...>; }; ¥ template<size_t N>¥ using to = typename BOOST_PP_CAT(index_count_help_, from)¥ <typename index_count<N>::type>::type; 上から説明します
  9. 9. BOOST_PP_CATを使ってみる • とりあえずindex_tupleとindex_countが定義されてるとする • これらについては本講座のスライド参照 #define INDEX_COUNT(from,to)¥ template<class>class BOOST_PP_CAT(index_count_help_, from); ¥ template<int... Nums>¥ class BOOST_PP_CAT(index_count_help_, from)¥ <index_tuple<Nums...>>{¥ public:¥ using type = from <Nums...>; }; ¥ template<size_t N>¥ using to = typename BOOST_PP_CAT(index_count_help_, from)¥ <typename index_count<N>::type>::type; 引数をfromとtoに代入して展開するマクロを定義
  10. 10. BOOST_PP_CATを使ってみる • とりあえずindex_tupleとindex_countが定義されてるとする • これらについては本講座のスライド参照 #define INDEX_COUNT(from,to)¥ template<class>class BOOST_PP_CAT(index_count_help_, from); ¥ template<int... Nums>¥ class BOOST_PP_CAT(index_count_help_, from)¥ <index_tuple<Nums...>>{¥ public:¥ using type = from <Nums...>; }; ¥ template<size_t N>¥ using to = typename BOOST_PP_CAT(index_count_help_, from)¥ <typename index_count<N>::type>::type; トークン名結合してよくわからないクラスができる
  11. 11. BOOST_PP_CATを使ってみる • とりあえずindex_tupleとindex_countが定義されてるとする • これらについては本講座のスライド参照 #define INDEX_COUNT(from,to)¥ template<class>class BOOST_PP_CAT(index_count_help_, from); ¥ template<int... Nums>¥ class BOOST_PP_CAT(index_count_help_, from)¥ <index_tuple<Nums...>>{¥ public:¥ using type = from <Nums...>; }; ¥ template<size_t N>¥ using to = typename BOOST_PP_CAT(index_count_help_, from)¥ <typename index_count<N>::type>::type; index_tupleで特殊化
  12. 12. BOOST_PP_CATを使ってみる • とりあえずindex_tupleとindex_countが定義されてるとする • これらについては本講座のスライド参照 #define INDEX_COUNT(from,to)¥ template<class>class BOOST_PP_CAT(index_count_help_, from); ¥ template<int... Nums>¥ class BOOST_PP_CAT(index_count_help_, from)¥ <index_tuple<Nums...>>{¥ public:¥ using type = from <Nums...>; }; ¥ template<size_t N>¥ using to = typename BOOST_PP_CAT(index_count_help_, from)¥ <typename index_count<N>::type>::type; fromにNums…を渡したやつでtypeにエイリアス
  13. 13. BOOST_PP_CATを使ってみる • とりあえずindex_tupleとindex_countが定義されてるとする • これらについては本講座のスライド参照 #define INDEX_COUNT(from,to)¥ template<class>class BOOST_PP_CAT(index_count_help_, from); ¥ template<int... Nums>¥ class BOOST_PP_CAT(index_count_help_, from)¥ <index_tuple<Nums...>>{¥ public:¥ using type = from <Nums...>; }; ¥ template<size_t N>¥ using to = typename BOOST_PP_CAT(index_count_help_, from)¥ <typename index_count<N>::type>::type; 上のクラスにindex_countのtype渡してtoにエイリアス
  14. 14. さっきの例の使い方 template<int… Nums>class sum_type{ static int get(){ int ret(); for(const auto& x : {Nums…} ) ret+=x; return ret; } }; INDEX_COUNT(sum,sum_type) cout<<sum<10>::get()<<endl;//45が出力される • つまりsum<10>でsum_type<0,1,2,3,4,5,6,7,8,9>に同じになる • BOOST_PP_CATめっちゃ便利っぽい?
  15. 15. BOOST_PP_IF • BOOST_PP_IF(cond, t, f)で定義されてる • condには0から255に展開されるマクロ、または数値直打ち • condが0ならtに、そうでないならfに展開される • あれ、案外普通?
  16. 16. #include<boost¥preprocessor.hpp> #include<iostream> int main() { std::cout<<BOOST_PP_IF(3,”Hello World!”,42)<<std::endl; }
  17. 17. ん?
  18. 18. コンパイル時では出来ないことやっとる • 条件演算子でさっきの芸当は不可能 • 条件演算子では結果の2つの型に互換性が必要 • ってMSVCがエラー吐いた • プリプロセッサなので機械的に展開された • すなわちコンパイル時にはすでに”Hello World!!”になってたってこと • でもまだ闇っぽくない • 十分ヤバイニオイしてきてる気がしないこともない
  19. 19. BOOST_PP_ENUM • BOOST_PP_ENUM(count, macro, data) • countに255以下の数字を入れる • macroにはマクロを入れる • macro(z,0,data),macro(z,1,data),…,macro(z,count-1,data)展開される • zが謎すぎて謎だが見たところ2が渡されてるっぽい? • 下手に触れないほうがいいっぽいです
  20. 20. 例 #define TYPE_DECLARE(z,n,type) class BOOST_PP_CAT(type,n) template<BOOST_PP_ENUM(16,TYPE_DECLARE,Type)>class test{};
  21. 21. ホラーが起こってる • テンプレート引数16個とか人間が作るテンプレートクラスじゃねぇ • 普通に可変長引数テンプレートでいいじゃんってツッコミ待ち • 凄いヤバイっぽい • ちなみにBOOST_PP_ENUM_SHIFTEDで1からの展開になります
  22. 22. BOOST_PP_REPEAT • BOOST_PP_REPEAT(count, macro, data) • さっきのカンマない版 • スペース1個は開けてくれてる • やなニオイがプンプン
  23. 23. 使い方 #define DECLARE(z,n,type)¥ class BOOST_PP_CAT(type, n){ static const int x = n; }; BOOST_PP_REPEAT(32, DECLARE, test)
  24. 24. これヤバ過ぎるでしょ • 似たようなクラスを大量定義するのにオススメ • 他にも大量の足し算するときとか • やっぱりアホ感拭えない • BOOST_PP_REPEAT_FROM_TOで第1引数から第2引数-1まで展開
  25. 25. とりあえずFizzBuzzする • テクニック知ってFizzBuzz試すのは礼儀(ほんまか) • BOOST_PP_STRINGIZEとstatic_assertでコンパイルエラーメーセージで 出します
  26. 26. まずは倍数チェック • BOOST_PP_EQUAL(x,y)でxとyが同じなら1、そうでないなら0 • 正確にはxとyが同じものに展開するマクロまたは数値 • それとBOOST_PP_MODとBOOST_PP_IFを使えば 「xがyの倍数ならt、そうでないならfに展開する」マクロを作れる
  27. 27. というわけで #define MOD_IF(n,m,t,f)¥ BOOST_PP_IF(¥ BOOST_PP_EQUAL(¥ BOOST_PP_MOD(n,m),¥ 0),¥ t,¥ f) • 説明は不要だよね
  28. 28. FizzBuzzのための文字列 • FizzBuzzのルールを思い出す • まず3の倍数であるかチェック • 3の倍数なら「5の倍数ならFizzBuzz、そうでないならFizz」 • そうでないなら「5の倍数ならBuzz、そうでないならその数字」 • というわけでさっきのMOD_IF使う • こんな感じ #define FizzBuzzLoop(z,n,t)¥ MOD_IF(n,3,MOD_IF(n,5,FizzBuzz,Fizz),MOD_IF(n,5,Buzz,n)) • この引数の取り方はBOOST_PP_REPEAT_FROM_TOのため
  29. 29. 出力 BOOST_PP_STRINGIZE(BOOST_PP_REPEAT_FROM_TO(1,16,FizzBuzzLoop,t)) • 「さっきのFizzBuzzLoopを1から15まで展開」したものを文字列化する • 自明なこと解説しないマンは自明なこと解説しないんじゃ
  30. 30. • インテリセンス便利 • GCCにパス通すの面倒だった(VC++では前から通してた)
  31. 31. まだまだ闇の途中 • boost¥preprocessor.hppではもっとマクロが定義されている • またコンパイラ定義済みマクロもそれなりにある • これらを使いこなしてこそ上級闇魔導師になれるはず • 俺たちの戦いはこれからだ • こんなことやってる暇あったら実行時C++やってる方がいい
  32. 32. おまけ • ヒープ食いつぶした • どのタイミングで 食いつぶしたんだ • インテリセンス死ぬので 良い子は真似しない
  33. 33. 参考資料 • C++でゲームプログラミング http://d.hatena.ne.jp/osyo-manga/ • BOOST_PP http://d.hatena.ne.jp/osyo-manga/20100906/1285986310 • Boost.Preprocessorでプログラミングしましょう http://www.slideshare.net/digitalghost/boostpp • Boost.ppのリファレンス http://www.boost.org/doc/libs/1_44_0/libs/preprocessor/doc/ref.html
  34. 34. 終わり ご清聴ありがとうございました

×