Top Banner
Boost.Preprocessor でプログラミングしましょう DigitalGhost http://d.hatena.ne.jp/DigitalGhost/ http://twitter.com/DecimalBloat
63

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

Nov 11, 2014

Download

Technology

digitalghost

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Boost.Preprocessorでプログラミングしましょう

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

DigitalGhosthttp://d.hatena.ne.jp/DigitalGhost/

http://twitter.com/DecimalBloat

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

私のこと

hatena のプロフィールとか

見てください

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

とりあえず 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 は省略してます

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

gcc -P で展開

1 , 2 , FIZZ , 4 , BUZZ , FIZZ , 7 , 8 ,

FIZZ , BUZZ , 11 , FIZZ , 13 , 14 , FIZZBUZZ

, 16 , 17 , FIZZ , 19 , BUZZ …

コンパイルすらせず解けた!

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

Boost.Preprocessor について

「コピペ→ちょっとだけ変更」を人間が繰り返す

代わりに、プリプロセッサで自動化するためのマ

クロいろいろ

template<typename T1, typename T2, …,

typename T50> とかいうテンプレート(実際

にBoostにはあります)を作るときとかにとても

便利

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

使われている例

Boost.ScopeExit

Boost.Typeof

Boost.ConceptCheck

Boost.Parameters

etc...

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

実行環境

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

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

“Hello World!” in Preprocessor

ソース hello.cpp

Hello, World!

$ gcc -P hello.cpp

Hello, World!

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

“Hello World!” in Preprocessor

ソース hello2.cpp

#define HELLO(x) Hello, x!

HELLO(x)

$ gcc -P hello2.cpp

Hello, World!

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

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, _)

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

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;

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

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;

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

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;

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

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;

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

関連するマクロ

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;

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

関連するマクロ

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;

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

関連するマクロ

BOOST_PP_ENUM_SHIFTED_PARAMS(n, d)

d ## 1, d ## 2, … d ## (n 1) – と展開する

template<

typename T1 , typename T2 , … typename T50

>

struct vector50;

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

関連するマクロ

関数テンプレートの場合:

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)

);

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

関連するマクロ

関数テンプレートの場合:

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 ,

);

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

関連するマクロ

関数テンプレートの場合:

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 ,

);※他にもいくつかバリエーションがあります

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

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, _)

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

BOOST_PP_CAT(a, b)

a と b をトークン連結します

a ## b とだいたい同じです

BOOST_PP_CAT(HOGE, HOGE) // HOGEHOGE

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

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

になる

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

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 がマクロだった場合、全て展開

が終わった後に連結します

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

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, _)

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

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」か、もしくはそう展開されるマクロのみ

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

プリプロセッサでの数字の扱い

プリプロセッサは「1」が示す 値 を認識してい

ない

「1LL」とか「1.0」は×

値を認識して扱うのはコンパイルや実行時

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

プリプロセッサの数字の扱い

「123」や「abc」を「文字の並び(トーク

ン)」として扱っている

丸カッコとカンマ以外の記号や空白が混ざってい

てもトークン

「123-abc; .exe」も一つのトークン

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

関連するマクロ

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)

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

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, _)

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

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

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

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, _)

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

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 では警告がでます)

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

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, _)

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

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)

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

もう一度、数字に関する注意

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

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

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, _)

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

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 …というようなことをする

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

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++的にはすごく効率が悪いですが、後の解説のためなので見逃してください)

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

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)

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

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;

}

ここからプリプロセッサで置き換え

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

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)

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

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)

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

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)

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

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)

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

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 を定義

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

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)

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

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)

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

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 をマクロ化

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

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, _)

完成!

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

もっと複雑な例

make_smart

newでT型の値を作ってすぐにスマートポインタで管

理する場合、だいたい

smart_ptr<T>(new T(param1, param2 …));

という感じに書く

これは面倒だし、生のポインタが一瞬登場してしま

う。完全にポインタを消したい

関数を作ってラップしてしまおう

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

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));

}

これでは値で引数を受けているので効率が悪い

参照を使おう

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

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 参照が使えないので不便

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

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 参照かそうでないかに

よって呼び分けられる

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

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));

}

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

make_smart_ptr(n引数版)

3要素タプル版

1つ目の引数が(略)で、2 * 2 * 2 = 8 パターン

4要素(略)

1つ目(略)で、2 *(略)= 16 パターン

結局ここまでだけでも、2 + 4 + 8 + 16 = 30

パターン書かないといけない

面倒!

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

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, _)

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

代入

Y は X() と展開される

4 と展開したい!

#define X() 4

#define Y() X()

#undef X

Y

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

そこで

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)

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

誰得?

Boost.Typeof は、型を整数の列にエンコード

する必要があるので、型に一意な整数 ID を振る

ために使われています

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

他に

BOOST_PP_ITERATE

自分自身を繰り返し #include します

BOOST_PP_ENUM で書くにはマクロが大きすぎる

場合に便利

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

Boost.PP を読むときの注意

BOOST_PP_AUTO_REC というマクロが登場

しますが、これが曲者です

http://d.hatena.ne.jp/DigitalGhost/20090903/1252002035 に概要が

あります

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

終わり