Boost.Preprocessor   でプログラミングしましょう                               DigitalGhost        http://d.hatena.ne.jp/DigitalGhost/  ...
私のことhatena のプロフィールとか見てください
とりあえず FizzBuzz 書いてみた#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BO...
gcc -P で展開 1 , 2 , FIZZ , 4 , BUZZ , FIZZ , 7 , 8 ,FIZZ , BUZZ , 11 , FIZZ , 13 , 14 , FIZZBUZZ, 16 , 17 , FIZZ , 19 , BUZ...
Boost.Preprocessor について「コピペ→ちょっとだけ変更」を人間が繰り返す代わりに、プリプロセッサで自動化するためのマクロいろいろtemplate<typename T1, typename T2, …,typename T50...
使われている例Boost.ScopeExitBoost.TypeofBoost.ConceptCheckBoost.Parametersetc...
実行環境VC : cl.exe /EP ソースファイルgcc : cpp -P ソースファイル ※ cl.exe /EP だと、プリプロセスディレクティブの 行も空行として残ってしまうので、適当に削除してく ださい for /f "delims...
“Hello World!” in Preprocessorソース hello.cpp  Hello, World!$ gcc -P hello.cpp  Hello, World!
“Hello World!” in Preprocessorソース hello2.cpp  #define HELLO(x) Hello, x!  HELLO(x)$ gcc -P hello2.cpp  Hello, World!
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntempla...
BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntempla...
BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntempla...
BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntempla...
関連するマクロBOOST_PP_ENUM_SHIFTED_PARAMS(n, d)  d ## 1, d ## 2, … d ## (n – 1) と展開するtemplate<  BOOST_PP_ENUM_SHIFTED_PARAMS(51,...
関連するマクロBOOST_PP_ENUM_SHIFTED_PARAMS(n, d)  d ## 1, d ## 2, … d ## (n – 1) と展開するtemplate<  typename T ## 1 , typename T ## ...
関連するマクロBOOST_PP_ENUM_SHIFTED_PARAMS(n, d)  d ## 1, d ## 2, … d ## (n – 1) と展開するtemplate<  typename T1 , typename T2 , … ty...
関連するマクロ関数テンプレートの場合:BOOST_PP_SHIFTED_BINARY_PARAMStemplate< typename T1 , typename T2 , … typename T50 >tuple50< T1 , T2 , ...
関連するマクロ関数テンプレートの場合:BOOST_PP_SHIFTED_BINARY_PARAMStemplate< typename T1 , typename T2 , … typename T50 >tuple50< T1 , T2 , ...
関連するマクロ関数テンプレートの場合:BOOST_PP_SHIFTED_BINARY_PARAMStemplate< typename T1 , typename T2 , … typename T50 >tuple50< T1 , T2 , ...
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
BOOST_PP_CAT(a, b)a と b をトークン連結しますa ## b とだいたい同じです BOOST_PP_CAT(HOGE, HOGE) // HOGEHOGE
BOOST_PP_CAT(a, b)それは ## で十分じゃないの?#define BAD(a, b) a ## b#define GOOD(a, b) BOOST_PP_CAT(a, b)#define DOUBLE(a) a a      ...
BOOST_PP_CAT(a, b)ちなみに実装#define BOOST_PP_CAT(a, b) BOOST_PP_I(a, b)#define BOOST_PP_CAT_I(a, b) a ## bこうすれば a, b がマクロだった場合...
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
BOOST_PP_IIF(cond, t, f)cond が 「1」というトークンであれば t 「0」というトークンであれば fBOOST_PP_IIF(1, HOGE, PIYO)→ HOGEBOOST_PP_IIF(0, HOGE, PIY...
プリプロセッサでの数字の扱いプリプロセッサは「1」が示す 値 を認識していない 「1LL」とか「1.0」は× 値を認識して扱うのはコンパイルや実行時
プリプロセッサの数字の扱い「123」や「abc」を「文字の並び(トークン)」として扱っている丸カッコとカンマ以外の記号や空白が混ざっていてもトークン 「123-abc;   .exe」も一つのトークン
関連するマクロBOOST_PP_IF(cond, t, f)  cond が 1〜255 なら t 、0 なら f になるBOOST_PP_EXPR_IIF(cond, t)  cond が 1 なら t に、 0 なら空トークンになるBOOS...
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
BOOST_PP_BOOL(n)                     BOOST_PP_NOT(n)BOOST_PP_BOOL(n)  n が 1〜255 なら 1 、0 なら 0     ( n != 0 と同じ)BOOST_PP_NOT...
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
BOOST_PP_IS_EMPTY(a)A が空トークンか、空トークンに展開されるなら 1 、識別子なら 0BOOST_IS_EMPTY(HOGE)→ 0BOOST_IS_EMPTY(   )→ 1#define DUMMYBOOST_IS_E...
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
BOOST_PP_MOD(m, n)a を b で割った余り(つまり m % n)BOOST_PP_MOD(5, 3)→ 2BOOST_PP_MOD(BOOST_PP_MOD(139, 25), 8)→ 6BOOST_PP_ADD BOOST_...
もう一度、数字に関する注意BOOST_PP_IIF と同じく、C++ の値を認識しているわけではないので、 BOOST_PP_ADD(1 + 1, 2 + 2)とかはできない BOOST_PP_ADD(  BOOST_PP_ADD(1, 1),...
FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
FizzBuzz を手動で展開BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _) を展開FIZZBUZZ_OP(z, 1, _) ,FIZZBUZZ_OP(z, 2, _) ,   FIZZBUZZ_OPは、…...
FizzBuzz を手動で展開FIZZBUZZ_OP を C++ で書いてみるstring fizzbuzz_op(int n) {  string const & fizzbuzz =      string(!(n % 3) ? "FIZZ...
FizzBuzz を手動で展開この関数をこんな風に置き換え str1 + str2 → BOOST_PP_CAT(str1, str2) m % n → BOOST_PP_MOD(m, n) !n → BOOST_PP_NOT(n) str.e...
FizzBuzz を手動で展開ここからプリプロセッサで置き換えstring fizzbuzz_op(int n) {  string const & fizzbuzz =      string(!(n % 3) ? "FIZZ" : "") ...
FizzBuzz を手動で展開str1 + str2 → BOOST_PP_CAT(str1, str2)string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_PP_CA...
FizzBuzz を手動で展開c ? "str" : "" → BOOST_PP_EXPR_IIF(c, str)string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_P...
FizzBuzz を手動で展開!n → BOOST_PP_NOT(n)string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_PP_CAT(      BOOST_PP_E...
FizzBuzz を手動で展開m % n → BOOST_PP_MOD(m, n)string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_PP_CAT(      BOOS...
FizzBuzz を手動で展開FIZZBUZZ_OP_II を定義string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_PP_CAT(FIZZBUZZ_OP_II(n, ...
FizzBuzz を手動で展開c ? a : b → BOOST_PP_IIF(c, a, b)string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_PP_CAT(FIZ...
FizzBuzz を手動で展開str.empty( ) → BOOST_PP_IS_EMPTY(str)string fizzbuzz_op(int n) {  string const & fizzbuzz =    BOOST_PP_CAT...
FizzBuzz を手動で展開fizzbuzz_op をマクロ化#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                          ...
FizzBuzz を手動で展開完成!#define FIZZBUZZ_OP(z, n, d)                      FIZZBUZZ_OP_I(                                    BOOS...
もっと複雑な例make_smart newでT型の値を作ってすぐにスマートポインタで管 理する場合、だいたい   smart_ptr<T>(new T(param1, param2 …)); という感じに書く これは面倒だし、生のポインタが一瞬...
make_smart_ptr(1引数版)make_smart(1引数版)template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 param0) {  return my_sm...
make_smart_ptr(1引数版)make_smart(1引数版)template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 & param0) {  return my_...
make_smart_ptr(1引数版)make_smart(1引数版)template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 & param0) {  return my_...
make_smart_ptr(2引数版)1つ目の引数が const / 非 const 、2つ目の引数が const / 非 const で、2 * 2 = 4 パターン必要template<typename T, typename T0, t...
make_smart_ptr(n引数版)3要素タプル版 1つ目の引数が(略)で、2 * 2 * 2 = 8 パターン4要素(略) 1つ目(略)で、2 *(略)= 16 パターン結局ここまでだけでも、2 + 4 + 8 + 16 = 30パターン...
Boost.PP で自動生成#define DEF_MAKE_SMART_OVERLOADS_OP(z, n, data)   BOOST_PP_SEQ_FOR_EACH_PRODUCT(DEF_MAKE_TUPLE, ((n)) BOOST_...
代入#define X() 4#define Y() X()#undef XYY は X( ) と展開される4 と展開したい!
そこで#define X() 4#define BOOST_PP_VALUE 1 + 2 + 3 + X()#include BOOST_PP_ASSIGN_SLOT(1)#undef XBOOST_PP_SLOT(1)BOOST_PP_SLO...
誰得?Boost.Typeof は、型を整数の列にエンコードする必要があるので、型に一意な整数 ID を振るために使われています
他にBOOST_PP_ITERATE 自分自身を繰り返し #include します BOOST_PP_ENUM で書くにはマクロが大きすぎる 場合に便利
Boost.PP を読むときの注意BOOST_PP_AUTO_REC というマクロが登場しますが、これが曲者ですhttp://d.hatena.ne.jp/DigitalGhost/20090903/1252002035   に概要があります
終わり
Upcoming SlideShare
Loading in...5
×

Boost.Preprocessorでプログラミングしましょう

3,755

Published on

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

No Downloads
Views
Total Views
3,755
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
16
Comments
0
Likes
9
Embeds 0
No embeds

No notes for slide

Boost.Preprocessorでプログラミングしましょう

  1. 1. Boost.Preprocessor でプログラミングしましょう DigitalGhost http://d.hatena.ne.jp/DigitalGhost/ http://twitter.com/DecimalBloat
  2. 2. 私のことhatena のプロフィールとか見てください
  3. 3. とりあえず FizzBuzz 書いてみた#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _) ※ include は省略してます
  4. 4. gcc -P で展開 1 , 2 , FIZZ , 4 , BUZZ , FIZZ , 7 , 8 ,FIZZ , BUZZ , 11 , FIZZ , 13 , 14 , FIZZBUZZ, 16 , 17 , FIZZ , 19 , BUZZ … コンパイルすらせず 解けた!
  5. 5. Boost.Preprocessor について「コピペ→ちょっとだけ変更」を人間が繰り返す代わりに、プリプロセッサで自動化するためのマクロいろいろtemplate<typename T1, typename T2, …,typename T50> とかいうテンプレート(実際にBoostにはあります)を作るときとかにとても便利
  6. 6. 使われている例Boost.ScopeExitBoost.TypeofBoost.ConceptCheckBoost.Parametersetc...
  7. 7. 実行環境VC : cl.exe /EP ソースファイルgcc : cpp -P ソースファイル ※ cl.exe /EP だと、プリプロセスディレクティブの 行も空行として残ってしまうので、適当に削除してく ださい for /f "delims=" %i in (cl.exe /EP pp.cpp) do @if not "%i"=="" @echo %i
  8. 8. “Hello World!” in Preprocessorソース hello.cpp Hello, World!$ gcc -P hello.cpp Hello, World!
  9. 9. “Hello World!” in Preprocessorソース hello2.cpp #define HELLO(x) Hello, x! HELLO(x)$ gcc -P hello2.cpp Hello, World!
  10. 10. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  11. 11. BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntemplate< BOOST_PP_ENUM_SHIFTED(51, DECLARE_OP, typename T)> struct vector50;
  12. 12. BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntemplate< DECRARE_OP(z, 1, typename T) , DECRARE_OP(z, 2, typename T) , … DECRARE_OP(z, 50, typename T)> struct vector50;
  13. 13. BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntemplate< typename T ## 1 , typename T ## 2 , … typename T ## 50> struct vector50;
  14. 14. BOOST_PP_ENUM_SHIFTED(n, op, data)展開する数とマクロで、 1 〜 (n – 1) まで数字を変えながらコピペするマクロ#define DECLARE_OP(z, n, data) data ## ntemplate< typename T1 , typename T2 , … typename T50> struct vector50;
  15. 15. 関連するマクロBOOST_PP_ENUM_SHIFTED_PARAMS(n, d) d ## 1, d ## 2, … d ## (n – 1) と展開するtemplate< BOOST_PP_ENUM_SHIFTED_PARAMS(51, typename T)>struct vector50;
  16. 16. 関連するマクロBOOST_PP_ENUM_SHIFTED_PARAMS(n, d) d ## 1, d ## 2, … d ## (n – 1) と展開するtemplate< typename T ## 1 , typename T ## 2 , … typename T ## 50>struct vector50;
  17. 17. 関連するマクロBOOST_PP_ENUM_SHIFTED_PARAMS(n, d) d ## 1, d ## 2, … d ## (n – 1) と展開するtemplate< typename T1 , typename T2 , … typename T50>struct vector50;
  18. 18. 関連するマクロ関数テンプレートの場合:BOOST_PP_SHIFTED_BINARY_PARAMStemplate< typename T1 , typename T2 , … typename T50 >tuple50< T1 , T2 , … T50 >make_tuple50( BOOST_PP_ENUM_BINARY_PARAMS(50, const T, & arg));
  19. 19. 関連するマクロ関数テンプレートの場合:BOOST_PP_SHIFTED_BINARY_PARAMStemplate< typename T1 , typename T2 , … typename T50 >tuple50< T1 , T2 , … T50 >make_tuple50( const T ## 1 & arg ## 1 , const T ## 2 & arg ## 2 , … const T ## 50 & arg ## 50 ,);
  20. 20. 関連するマクロ関数テンプレートの場合:BOOST_PP_SHIFTED_BINARY_PARAMStemplate< typename T1 , typename T2 , … typename T50 >tuple50< T1 , T2 , … T50 >make_tuple50( const T1 & arg1 , const T2 & arg2 , … const T50 & arg50 ,); ※他にもいくつかバリエーションがあります
  21. 21. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  22. 22. BOOST_PP_CAT(a, b)a と b をトークン連結しますa ## b とだいたい同じです BOOST_PP_CAT(HOGE, HOGE) // HOGEHOGE
  23. 23. BOOST_PP_CAT(a, b)それは ## で十分じゃないの?#define BAD(a, b) a ## b#define GOOD(a, b) BOOST_PP_CAT(a, b)#define DOUBLE(a) a a HOGEDOUBLE(FUGA)BAD(HOGE, DOUBLE(FUGA)) と展開されてしまうGOOD(HOGE, DOUBLE(FUGA)) (トークン連結のほうが先にHOGEFUGA FUGA 実行される)になる
  24. 24. BOOST_PP_CAT(a, b)ちなみに実装#define BOOST_PP_CAT(a, b) BOOST_PP_I(a, b)#define BOOST_PP_CAT_I(a, b) a ## bこうすれば a, b がマクロだった場合、全て展開が終わった後に連結します
  25. 25. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  26. 26. BOOST_PP_IIF(cond, t, f)cond が 「1」というトークンであれば t 「0」というトークンであれば fBOOST_PP_IIF(1, HOGE, PIYO)→ HOGEBOOST_PP_IIF(0, HOGE, PIYO)→ PIYO ※一つめの引数(cond)が受け付けられるのは、「0」 か「1」か、もしくはそう展開されるマクロのみ
  27. 27. プリプロセッサでの数字の扱いプリプロセッサは「1」が示す 値 を認識していない 「1LL」とか「1.0」は× 値を認識して扱うのはコンパイルや実行時
  28. 28. プリプロセッサの数字の扱い「123」や「abc」を「文字の並び(トークン)」として扱っている丸カッコとカンマ以外の記号や空白が混ざっていてもトークン 「123-abc; .exe」も一つのトークン
  29. 29. 関連するマクロBOOST_PP_IF(cond, t, f) cond が 1〜255 なら t 、0 なら f になるBOOST_PP_EXPR_IIF(cond, t) cond が 1 なら t に、 0 なら空トークンになるBOOST_PP_EXPR_IIF(1, HOGE)→ HOGEBOOST_PP_EXPR_IIF(0, HOGE)→
  30. 30. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  31. 31. BOOST_PP_BOOL(n) BOOST_PP_NOT(n)BOOST_PP_BOOL(n) n が 1〜255 なら 1 、0 なら 0 ( n != 0 と同じ)BOOST_PP_NOT(n) n が 1〜255 なら 0 、0 なら 1 ( !n と同じ)BOOST_PP_BOOL(42) , BOOST_PP_NOT(42)→ 1 , 0
  32. 32. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  33. 33. BOOST_PP_IS_EMPTY(a)A が空トークンか、空トークンに展開されるなら 1 、識別子なら 0BOOST_IS_EMPTY(HOGE)→ 0BOOST_IS_EMPTY( )→ 1#define DUMMYBOOST_IS_EMPTY(DUMMY)→ 1(2 番目の例は VC では警告がでます)
  34. 34. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  35. 35. BOOST_PP_MOD(m, n)a を b で割った余り(つまり m % n)BOOST_PP_MOD(5, 3)→ 2BOOST_PP_MOD(BOOST_PP_MOD(139, 25), 8)→ 6BOOST_PP_ADD BOOST_PP_SUBBOOST_PP_MUL BOOST_PP_DIVもあります
  36. 36. もう一度、数字に関する注意BOOST_PP_IIF と同じく、C++ の値を認識しているわけではないので、 BOOST_PP_ADD(1 + 1, 2 + 2)とかはできない BOOST_PP_ADD( BOOST_PP_ADD(1, 1), BOOST_PP_ADD(2, 2))これはOK
  37. 37. FizzBuzz はどうなってるの?#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  38. 38. FizzBuzz を手動で展開BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _) を展開FIZZBUZZ_OP(z, 1, _) ,FIZZBUZZ_OP(z, 2, _) , FIZZBUZZ_OPは、… 1→1FIZZBUZZ_OP(z, 100, _) 2→2 3→FIZZ … というようなことをする
  39. 39. FizzBuzz を手動で展開FIZZBUZZ_OP を C++ で書いてみるstring fizzbuzz_op(int n) { string const & fizzbuzz = string(!(n % 3) ? "FIZZ" : "") + string(!(n % 5) ? "BUZZ" : ""); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}(C++的にはすごく効率が悪いですが、後の解説のためなので見逃してください)
  40. 40. FizzBuzz を手動で展開この関数をこんな風に置き換え str1 + str2 → BOOST_PP_CAT(str1, str2) m % n → BOOST_PP_MOD(m, n) !n → BOOST_PP_NOT(n) str.empty() → BOOST_PP_IS_EMPTY(str) c ? "str" : "" → BOOST_PP_EXPR_IIF(c, str) c ? a : b → BOOST_PP_IIF(c, a, b)
  41. 41. FizzBuzz を手動で展開ここからプリプロセッサで置き換えstring fizzbuzz_op(int n) { string const & fizzbuzz = string(!(n % 3) ? "FIZZ" : "") + string(!(n % 5) ? "BUZZ" : ""); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}
  42. 42. FizzBuzz を手動で展開str1 + str2 → BOOST_PP_CAT(str1, str2)string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT(!(n % 3) ? "FIZZ" : "", !(n % 5) ? "BUZZ" : ""); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}
  43. 43. FizzBuzz を手動で展開c ? "str" : "" → BOOST_PP_EXPR_IIF(c, str)string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT( BOOST_PP_EXPR_IIF(!(n % 3), FIZZ), BOOST_PP_EXPR_IIF(!(n % 5), BUZZ)); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}
  44. 44. FizzBuzz を手動で展開!n → BOOST_PP_NOT(n)string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT( BOOST_PP_EXPR_IIF(BOOST_PP_NOT(n % 3), FIZZ), BOOST_PP_EXPR_IIF(BOOST_PP_NOT(n % 5), BUZZ)); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}
  45. 45. FizzBuzz を手動で展開m % n → BOOST_PP_MOD(m, n)string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT( BOOST_PP_EXPR_IIF(BOOST_PP_NOT( BOOST_PP_MOD(n, 3)), FIZZ), BOOST_PP_EXPR_IIF(BOOST_PP_NOT( BOOST_PP_MOD(n, 5)), BUZZ)); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}
  46. 46. FizzBuzz を手動で展開FIZZBUZZ_OP_II を定義string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)); return fizzbuzz.empty() ? lexical_cast<string>(n) : fizzbuzz;}#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)
  47. 47. FizzBuzz を手動で展開c ? a : b → BOOST_PP_IIF(c, a, b)string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)); return BOOST_PP_IIF(fizzbuzz.empty(), n, fizzbuzz);}#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)
  48. 48. FizzBuzz を手動で展開str.empty( ) → BOOST_PP_IS_EMPTY(str)string fizzbuzz_op(int n) { string const & fizzbuzz = BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)); return BOOST_PP_IIF(BOOST_PP_IS_EMPTY(fizzbuzz), n, fizzbuzz);}#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)
  49. 49. FizzBuzz を手動で展開fizzbuzz_op をマクロ化#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)
  50. 50. FizzBuzz を手動で展開完成!#define FIZZBUZZ_OP(z, n, d) FIZZBUZZ_OP_I( BOOST_PP_CAT(FIZZBUZZ_OP_II(n, 3, FIZZ), FIZZBUZZ_OP_II(n, 5, BUZZ)), n)#define FIZZBUZZ_OP_I(t, n) BOOST_PP_IIF(BOOST_PP_IS_EMPTY(t), n, t)#define FIZZBUZZ_OP_II(m, n, t) BOOST_PP_EXPR_IIF(BOOST_PP_NOT(BOOST_PP_MOD(m, n)), t)BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _)
  51. 51. もっと複雑な例make_smart newでT型の値を作ってすぐにスマートポインタで管 理する場合、だいたい smart_ptr<T>(new T(param1, param2 …)); という感じに書く これは面倒だし、生のポインタが一瞬登場してしま う。完全にポインタを消したい 関数を作ってラップしてしまおう
  52. 52. make_smart_ptr(1引数版)make_smart(1引数版)template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 param0) { return my_smart_ptr<T>(new T(param0));}これでは値で引数を受けているので効率が悪い参照を使おう
  53. 53. make_smart_ptr(1引数版)make_smart(1引数版)template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 & param0) { return my_smart_ptr<T>(new T(param0));}これでもまだ const 参照が使えないので不便
  54. 54. make_smart_ptr(1引数版)make_smart(1引数版)template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 & param0) { return my_smart_ptr<T>(new T(param0));}template<typename T, typename T0>my_smart_ptr<T> make_smart(T0 const & param0) { return my_smart_ptr<T>(new T(param0));}これで、引数が const 参照かそうでないかによって呼び分けられる
  55. 55. make_smart_ptr(2引数版)1つ目の引数が const / 非 const 、2つ目の引数が const / 非 const で、2 * 2 = 4 パターン必要template<typename T, typename T0, typename T1>my_smart_ptr<T> make_smart(T0 & param0, T1 & param1) { return my_smart_ptr<T>(new T(param0, param1));}template<typename T, typename T0, typename T1>my_smart_ptr<T> make_smart(T0 const & param0, T1 & param1) { return my_smart_ptr<T>(new T(param0, param1));}template<typename T, typename T0, typename T1>my_smart_ptr<T> make_smart(T0 & param0, T1 const & param1) { return my_smart_ptr<T>(new T(param0, param1));}template<typename T, typename T0, typename T1>my_smart_ptr<T> make_smart(T0 const & param0, T1 const & param1) { return my_smart_ptr<T>(new T(param0, param1));}
  56. 56. make_smart_ptr(n引数版)3要素タプル版 1つ目の引数が(略)で、2 * 2 * 2 = 8 パターン4要素(略) 1つ目(略)で、2 *(略)= 16 パターン結局ここまでだけでも、2 + 4 + 8 + 16 = 30パターン書かないといけない 面倒!
  57. 57. Boost.PP で自動生成#define DEF_MAKE_SMART_OVERLOADS_OP(z, n, data) BOOST_PP_SEQ_FOR_EACH_PRODUCT(DEF_MAKE_TUPLE, ((n)) BOOST_PP_REPEAT(n, MAKE_CONST_SEQ, _))#define DEF_MAKE_SMART(r, seq) DEF_MAKE_SMART_I(BOOST_PP_SEQ_HEAD(seq), BOOST_PP_SEQ_TAIL(seq))#define DEF_MAKE_SMART_I(n, seq) template< typename T , BOOST_PP_ENUM_PARAMS(n, typename T) > my_smart_ptr<T> make_smart(BOOST_PP_FOR((n, 0, seq), PARAMS_P, PARAMS_OP, DECL_PARAMS)) { return my_smart_ptr<T>(new T(BOOST_PP_ENUM_PARAMS(n, param))); }#define PARAMS_P(r, state) PARAMS_P_I state#define PARAMS_P_I(n, i, seq) BOOST_PP_GREATER(n, i)#define PARAMS_OP(r, state) PARAMS_OP_I state#define PARAMS_OP_I(n, i, seq) (n, BOOST_PP_INC(i), BOOST_PP_SEQ_TAIL(seq))#define DECL_PARAMS(r, state) DECL_PARAMS_I state#define DECL_PARAMS_I(n, i, seq) BOOST_PP_COMMA_IF(i) T ## i BOOST_PP_SEQ_HEAD(seq) & param ## i#define MAKE_CONST_SEQ(z, n, _) (()(const))BOOST_PP_REPEAT_FROM_TO(1, 6, DEF_MAKE_SMART_OVERLOADS_OP, _)
  58. 58. 代入#define X() 4#define Y() X()#undef XYY は X( ) と展開される4 と展開したい!
  59. 59. そこで#define X() 4#define BOOST_PP_VALUE 1 + 2 + 3 + X()#include BOOST_PP_ASSIGN_SLOT(1)#undef XBOOST_PP_SLOT(1)BOOST_PP_SLOT(1) は 10 に展開される素敵!
  60. 60. 誰得?Boost.Typeof は、型を整数の列にエンコードする必要があるので、型に一意な整数 ID を振るために使われています
  61. 61. 他にBOOST_PP_ITERATE 自分自身を繰り返し #include します BOOST_PP_ENUM で書くにはマクロが大きすぎる 場合に便利
  62. 62. Boost.PP を読むときの注意BOOST_PP_AUTO_REC というマクロが登場しますが、これが曲者ですhttp://d.hatena.ne.jp/DigitalGhost/20090903/1252002035 に概要があります
  63. 63. 終わり
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×