Boost.Preprocessor でプログラミングしましょう DigitalGhost http://d.hatena.ne.jp/DigitalGhost/ http://twitter.com/DecimalBloat
Nov 11, 2014
Boost.Preprocessorでプログラミングしましょう
DigitalGhosthttp://d.hatena.ne.jp/DigitalGhost/
http://twitter.com/DecimalBloat
私のこと
hatena のプロフィールとか
見てください
とりあえず 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 は省略してます
gcc -P で展開
1 , 2 , FIZZ , 4 , BUZZ , FIZZ , 7 , 8 ,
FIZZ , BUZZ , 11 , FIZZ , 13 , 14 , FIZZBUZZ
, 16 , 17 , FIZZ , 19 , BUZZ …
コンパイルすらせず解けた!
Boost.Preprocessor について
「コピペ→ちょっとだけ変更」を人間が繰り返す
代わりに、プリプロセッサで自動化するためのマ
クロいろいろ
template<typename T1, typename T2, …,
typename T50> とかいうテンプレート(実際
にBoostにはあります)を作るときとかにとても
便利
使われている例
Boost.ScopeExit
Boost.Typeof
Boost.ConceptCheck
Boost.Parameters
etc...
実行環境
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
“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( \ 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, _)
BOOST_PP_ENUM_SHIFTED(n, op, data)
展開する数とマクロで、 1 〜 (n 1) – まで数字
を変えながらコピペするマクロ
#define DECLARE_OP(z, n, data) data ## n
template<
BOOST_PP_ENUM_SHIFTED(51, DECLARE_OP, typename T)
> struct vector50;
BOOST_PP_ENUM_SHIFTED(n, op, data)
展開する数とマクロで、 1 〜 (n 1) – まで数字
を変えながらコピペするマクロ
#define DECLARE_OP(z, n, data) data ## n
template<
DECRARE_OP(z, 1, typename T) ,
DECRARE_OP(z, 2, typename T) ,
…
DECRARE_OP(z, 50, typename T)
> struct vector50;
BOOST_PP_ENUM_SHIFTED(n, op, data)
展開する数とマクロで、 1 〜 (n 1) – まで数字
を変えながらコピペするマクロ
#define DECLARE_OP(z, n, data) data ## n
template<
typename T ## 1 ,
typename T ## 2 ,
…
typename T ## 50
> struct vector50;
BOOST_PP_ENUM_SHIFTED(n, op, data)
展開する数とマクロで、 1 〜 (n 1) – まで数字
を変えながらコピペするマクロ
#define DECLARE_OP(z, n, data) data ## n
template<
typename T1 ,
typename T2 ,
…
typename T50
> struct vector50;
関連するマクロ
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;
関連するマクロ
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;
関連するマクロ
BOOST_PP_ENUM_SHIFTED_PARAMS(n, d)
d ## 1, d ## 2, … d ## (n 1) – と展開する
template<
typename T1 , typename T2 , … typename T50
>
struct vector50;
関連するマクロ
関数テンプレートの場合:
BOOST_PP_SHIFTED_BINARY_PARAMS
template< typename T1 , typename T2 , … typename T50 >
tuple50< T1 , T2 , … T50 >
make_tuple50(
BOOST_PP_ENUM_BINARY_PARAMS(50, const T, & arg)
);
関連するマクロ
関数テンプレートの場合:
BOOST_PP_SHIFTED_BINARY_PARAMS
template< 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 ,
);
関連するマクロ
関数テンプレートの場合:
BOOST_PP_SHIFTED_BINARY_PARAMS
template< typename T1 , typename T2 , … typename T50 >
tuple50< T1 , T2 , … T50 >
make_tuple50(
const T1 & arg1 ,
const T2 & arg2 ,
…
const T50 & arg50 ,
);※他にもいくつかバリエーションがあります
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, _)
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
BAD(HOGE, DOUBLE(FUGA))
GOOD(HOGE, DOUBLE(FUGA))
HOGEDOUBLE(FUGA)
と展開されてしまう
(トークン連結のほうが先に
実行される)HOGEFUGA FUGA
になる
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( \ 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, _)
BOOST_PP_IIF(cond, t, f)
cond が
「1」というトークンであれば t
「0」というトークンであれば f
BOOST_PP_IIF(1, HOGE, PIYO)
→ HOGE
BOOST_PP_IIF(0, HOGE, PIYO)
→ PIYO
※一つめの引数(cond)が受け付けられるのは、「0」
か「1」か、もしくはそう展開されるマクロのみ
プリプロセッサでの数字の扱い
プリプロセッサは「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 なら空トークンになる
BOOST_PP_EXPR_IIF(1, HOGE)
→ HOGE
BOOST_PP_EXPR_IIF(0, HOGE)
→
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, _)
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
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, _)
BOOST_PP_IS_EMPTY(a)
A が空トークンか、空トークンに展開されるな
ら 1 、識別子なら 0
BOOST_IS_EMPTY(HOGE)
→ 0
BOOST_IS_EMPTY( )
→ 1
#define DUMMY
BOOST_IS_EMPTY(DUMMY)
→ 1
(2 番目の例は VC では警告がでます)
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, _)
BOOST_PP_MOD(m, n)
a を b で割った余り(つまり m % n)
BOOST_PP_MOD(5, 3)
→ 2
BOOST_PP_MOD(BOOST_PP_MOD(139, 25), 8)
→ 6
BOOST_PP_ADD BOOST_PP_SUB
BOOST_PP_MUL BOOST_PP_DIV
もあります
a を b で割った余り(つまり m % n)
もう一度、数字に関する注意
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
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, _)
FizzBuzz を手動で展開
BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _) を展開
FIZZBUZZ_OP(z, 1, _) ,
FIZZBUZZ_OP(z, 2, _) ,
…
FIZZBUZZ_OP(z, 100, _)
FIZZBUZZ_OPは、 1→1 2→2 3→FIZZ …というようなことをする
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;
}
FIZZBUZZ_OP を C++ で書いてみる
(C++的にはすごく効率が悪いですが、後の解説のためなので見逃してください)
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)
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;
}
ここからプリプロセッサで置き換え
FizzBuzz を手動で展開
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;
}
str1 + str2 → BOOST_PP_CAT(str1, str2)
FizzBuzz を手動で展開
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;
}
c ? "str" : "" → BOOST_PP_EXPR_IIF(c, str)
FizzBuzz を手動で展開
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;
}
!n → BOOST_PP_NOT(n)
FizzBuzz を手動で展開
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;
}
m % n → BOOST_PP_MOD(m, n)
FizzBuzz を手動で展開
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)
FIZZBUZZ_OP_II を定義
FizzBuzz を手動で展開
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)
c ? a : b → BOOST_PP_IIF(c, a, b)
FizzBuzz を手動で展開
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)
str.empty() → BOOST_PP_IS_EMPTY(str)
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)
fizzbuzz_op をマクロ化
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, _)
完成!
もっと複雑な例
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_smart_ptr<T>(new T(param0));
}
これでは値で引数を受けているので効率が悪い
参照を使おう
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 参照が使えないので不便
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 参照かそうでないかに
よって呼び分けられる
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));
}
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_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, _)
代入
Y は X() と展開される
4 と展開したい!
#define X() 4
#define Y() X()
#undef X
Y
そこで
BOOST_PP_SLOT(1) は 10 に展開される
素敵!
#define X() 4
#define BOOST_PP_VALUE 1 + 2 + 3 + X()
#include BOOST_PP_ASSIGN_SLOT(1)
#undef X
BOOST_PP_SLOT(1)
誰得?
Boost.Typeof は、型を整数の列にエンコード
する必要があるので、型に一意な整数 ID を振る
ために使われています
他に
BOOST_PP_ITERATE
自分自身を繰り返し #include します
BOOST_PP_ENUM で書くにはマクロが大きすぎる
場合に便利
Boost.PP を読むときの注意
BOOST_PP_AUTO_REC というマクロが登場
しますが、これが曲者です
http://d.hatena.ne.jp/DigitalGhost/20090903/1252002035 に概要が
あります
終わり