Contenu connexe Similaire à Boost.Preprocessorでプログラミングしましょう Similaire à Boost.Preprocessorでプログラミングしましょう (6) Boost.Preprocessorでプログラミングしましょう1. Boost.Preprocessor
でプログラミングしましょう
DigitalGhost
http://d.hatena.ne.jp/DigitalGhost/
http://twitter.com/DecimalBloat
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. gcc -P で展開
1 , 2 , FIZZ , 4 , BUZZ , FIZZ , 7 , 8 ,
FIZZ , BUZZ , 11 , FIZZ , 13 , 14 , FIZZBUZZ
, 16 , 17 , FIZZ , 19 , BUZZ …
コンパイルすらせず
解けた!
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. “Hello World!” in Preprocessor
ソース hello.cpp
Hello, World!
$ gcc -P hello.cpp
Hello, World!
9. “Hello World!” in Preprocessor
ソース hello2.cpp
#define HELLO(x) Hello, x!
HELLO(x)
$ gcc -P hello2.cpp
Hello, World!
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, _)
12. 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;
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, _)
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 実行される)
になる
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. 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」か、もしくはそう展開されるマクロのみ
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)
→ HOGE
BOOST_PP_EXPR_IIF(0, HOGE)
→
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. 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. 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, _)
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. 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
もあります
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. FizzBuzz を手動で展開
BOOST_PP_ENUM_SHIFTED(101, FIZZBUZZ_OP, _) を展開
FIZZBUZZ_OP(z, 1, _) ,
FIZZBUZZ_OP(z, 2, _) , FIZZBUZZ_OPは、
… 1→1
FIZZBUZZ_OP(z, 100, _) 2→2
3→FIZZ
…
というようなことをする
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. 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)
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. 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. 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. 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. 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. 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. 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. 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. 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, _)
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));
}
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, _)
59. そこで
#define X() 4
#define BOOST_PP_VALUE 1 + 2 + 3 + X()
#include BOOST_PP_ASSIGN_SLOT(1)
#undef X
BOOST_PP_SLOT(1)
BOOST_PP_SLOT(1) は 10 に展開される
素敵!