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.

二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ

4,374 views

Published on

Cプリプロセッサマクロで再帰呼び出しをするための手法とBOOST_PP_AUTO_RECの解説

Published in: Technology
  • Be the first to comment

二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ

  1. 1. 二分探索法 2014/05/24 Boost.勉強会#15 札幌 でちまる
  2. 2. 二分探索法 で 2014/05/24 Boost.勉強会#15 札幌 でちまる
  3. 3. 二分探索法 で作る 2014/05/24 Boost.勉強会#15 札幌 でちまる
  4. 4. 二分探索法 で作る 再帰呼び出しできる 2014/05/24 Boost.勉強会#15 札幌 でちまる
  5. 5. 二分探索法 で作る 再帰呼び出しできる Cプリプロセッサマクロ
  6. 6. よく知られた事実 マクロは再帰できない
  7. 7. でも #include <iostream> #include <boost/preprocessor/repetition/for.hpp> #include <boost/preprocessor/arithmetic/dec.hpp> #define M1(r, x) BOOST_PP_FOR(x, P, OP, M2) #define M2(r, x) x, #define P(r, x) x #define OP(r, x) BOOST_PP_DEC(x) int main() { int xs[] = { BOOST_PP_FOR(5, P, OP, M1) }; // A. for (auto x : xs) std::cout << x << ' '; } > 5 4 3 2 1 4 3 2 1 3 2 1 2 1 1 BOOST_PP_FORの中でBOOST_PP_FORの呼び出しがあるけどうまくいく
  8. 8. BOOST_PP_FORを読んでみよう
  9. 9. これがBOOST_PP_FORだ # if 0 # define BOOST_PP_FOR(state, pred, op, macro) # endif # # define BOOST_PP_FOR BOOST_PP_CAT(BOOST_PP_FOR_, BOOST_PP_AUTO_REC(BOOST_PP_FOR_P, 256)) # # define BOOST_PP_FOR_P(n) BOOST_PP_CAT(BOOST_PP_FOR_CHECK_, BOOST_PP_FOR_ ## n(1, BOOST_PP_FOR_SR_P, BOOST_PP_FOR_SR_O, BOOST_PP_FOR_SR_M)) # # define BOOST_PP_FOR_SR_P(r, s) s # define BOOST_PP_FOR_SR_O(r, s) 0 # define BOOST_PP_FOR_SR_M(r, s) BOOST_PP_NIL # # define BOOST_PP_FOR_257(s, p, o, m) BOOST_PP_ERROR(0x0002) # # define BOOST_PP_FOR_CHECK_BOOST_PP_NIL 1 # # define BOOST_PP_FOR_CHECK_BOOST_PP_FOR_1(s, p, o, m) 0 # define BOOST_PP_FOR_CHECK_BOOST_PP_FOR_2(s, p, o, m) 0 # define BOOST_PP_FOR_CHECK_BOOST_PP_FOR_3(s, p, o, m) 0 …… # define BOOST_PP_FOR_1(s, p, o, m) BOOST_PP_FOR_1_C(BOOST_PP_BOOL(p(2, s)), s, p, o, m) # define BOOST_PP_FOR_2(s, p, o, m) BOOST_PP_FOR_2_C(BOOST_PP_BOOL(p(3, s)), s, p, o, m) # define BOOST_PP_FOR_3(s, p, o, m) BOOST_PP_FOR_3_C(BOOST_PP_BOOL(p(4, s)), s, p, o, m) …… # define BOOST_PP_FOR_1_C(c, s, p, o, m) BOOST_PP_IIF(c, m, BOOST_PP_TUPLE_EAT_2)(2, s) BOOST_PP_IIF(c, BOOST_PP_FOR_2, BOOST_PP_TUPLE_EAT_4) (BOOST_PP_EXPR_IIF(c, o)(2, s), p, o, m) # define BOOST_PP_FOR_2_C(c, s, p, o, m) BOOST_PP_IIF(c, m, BOOST_PP_TUPLE_EAT_2)(3, s) BOOST_PP_IIF(c, BOOST_PP_FOR_3, BOOST_PP_TUPLE_EAT_4) (BOOST_PP_EXPR_IIF(c, o)(3, s), p, o, m) # define BOOST_PP_FOR_3_C(c, s, p, o, m) BOOST_PP_IIF(c, m, BOOST_PP_TUPLE_EAT_2)(4, s) BOOST_PP_IIF(c, BOOST_PP_FOR_4, BOOST_PP_TUPLE_EAT_4) (BOOST_PP_EXPR_IIF(c, o)(4, s), p, o, m) ……
  10. 10. まだ諦めない
  11. 11. # if 0 # define BOOST_PP_FOR(state, pred, op, macro) # endif # # define BOOST_PP_FOR BOOST_PP_CAT( BOOST_PP_FOR_, BOOST_PP_AUTO_REC( BOOST_PP_FOR_P, 256))
  12. 12. # if 0 # define BOOST_PP_FOR(state, pred, op, macro) # endif # # define BOOST_PP_FOR BOOST_PP_CAT( BOOST_PP_FOR_, BOOST_PP_AUTO_REC( BOOST_PP_FOR_P, 256)) 関数マクロじゃなかった
  13. 13. ● BOOST_PP_FOR_n が本体っぽい ● BOOST_PP_FOR はオブジェクトマクロで 最終的に BOOST_PP_FOR_n に 展開されるっぽい – nは負でない整数 ● BOOST_PP_FOR_n はなんかループの1ステップ の処理っぽい
  14. 14. # if 0 # define BOOST_PP_FOR(state, pred, op, macro) # endif # # define BOOST_PP_FOR BOOST_PP_CAT( BOOST_PP_FOR_, BOOST_PP_AUTO_REC( BOOST_PP_FOR_P, 256)) なんかいかにも再帰してる感じの名前
  15. 15. こ れ が BOOST_PP_AUTO_REC だ (要約) # define AUTO_REC(pred, n) NODE_ENTRY_ ## n(pred) # # define NODE_ENTRY_8(p) NODE_4(p)(p)(p) # define NODE_ENTRY_4(p) NODE_2(p)(p) # define NODE_ENTRY_2(p) NODE_1(p) # # define NODE_4(p) IF(p(4), NODE_2, NODE_6) # define NODE_2(p) IF(p(2), NODE_1, NODE_3) # define NODE_1(p) IF(p(1), 1, 2) # define NODE_3(p) IF(p(3), 3, 4) # define NODE_6(p) IIF(p(6), NODE_5, NODE_7) # define NODE_5(p) IF(p(5), 5, 6) # define NODE_7(p) IF(p(7), 7, 8)
  16. 16. 諦めるな まだいける
  17. 17. p(1) 2 1 p(3) 4 3 p(5) 6 5 p(7) 8 7 p(6) p(2) p(4) true true true false 分かりやすい図
  18. 18. どうみても二分探索です 本当にありがとうございました
  19. 19. ● マクロは再帰展開できない – 大元の呼び出し→展開できる – その呼び出し中に現われた呼び出し→展開できない ● #define F(x) x という Fについて BOOST_PP_CAT(CHECK_, F(OK)) が – 展開できる → CHECK_OK – 展開できない → CHECK_F(OK) ● CHECK_OK と CHECK_F(x) を0と1に置き換え れば展開したかどうか検出できる
  20. 20. # define BOOST_PP_FOR_P(n) BOOST_PP_CAT( BOOST_PP_FOR_CHECK_, BOOST_PP_FOR_ ## n( 1, BOOST_PP_FOR_SR_P, BOOST_PP_FOR_SR_O, BOOST_PP_FOR_SR_M)) # # define BOOST_PP_FOR_SR_P(r, s) s # define BOOST_PP_FOR_SR_O(r, s) 0 # define BOOST_PP_FOR_SR_M(r, s) BOOST_PP_NIL # # define BOOST_PP_FOR_CHECK_BOOST_PP_NIL 1 # # define BOOST_PP_FOR_CHECK_BOOST_PP_FOR_1(s, p, o, m) 0
  21. 21. ● これを BOOST_PP_AUTO_REC に使え ば,BOOST_PP_FOR_n が展開済みかどうか検 出できる ● 展開済みなら BOOST_PP_FOR_n+1 を使う ● めでたしめでたし

×