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

Similar documents
Microsoft PowerPoint - prog03.ppt

Microsoft PowerPoint - 計算機言語 第7回.ppt

Microsoft Word - Training10_プリプロセッサ.docx

02: 変数と標準入出力

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Java Scriptプログラミング入門 3.6~ 茨城大学工学部情報工学科 08T4018Y 小幡智裕

プログラミングI第10回

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

Microsoft PowerPoint - enshu4.ppt [äº™æ‘łã…¢ã…¼ã…›]

8 / 0 1 i++ i 1 i-- i C !!! C 2

文字列操作と正規表現

Microsoft PowerPoint - handout07.ppt [互換モード]

02: 変数と標準入出力

Microsoft Word - no15.docx

memo

Slide 1

PowerPoint プレゼンテーション

Prog1_10th

C C UNIX C ( ) 4 1 HTML 1

Microsoft PowerPoint - 5Chap15.ppt

Prog1_6th

書式に示すように表示したい文字列をダブルクォーテーション (") の間に書けば良い ダブルクォーテーションで囲まれた文字列は 文字列リテラル と呼ばれる プログラム中では以下のように用いる プログラム例 1 printf(" 情報処理基礎 "); printf("c 言語の練習 "); printf

マウス操作だけで本格プログラミングを - 世界のナベアツをコンピュータで - プログラムというと普通は英語みたいな言葉で作ることになりますが 今回はマウスの操作だけで作ってみます Baltie, SGP System 操作説明ビデオなどは 高校 情

CプログラミングI

Microsoft PowerPoint - prog08.ppt

また 初期化について 以下のサンプルコードのように指定すれば 定義時に値を代入できます * オマケ配列は同名で複数個の箱を用意出来ます 同名ではありますが それぞれは別々の個体であるわけです また この複数個の変数は メモリ上に連続で確保されます 2. 文字と文字列 C 言語では文字と文字列は異なる

Microsoft Word - no103.docx

<4D F736F F D2091E63589F182628CBE8CEA8D758DC08E9197BF2E646F6378>

ゲームプログラミング講習 第0章 導入

Microsoft PowerPoint - ruby_instruction.ppt

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

ポインタ変数

Microsoft PowerPoint - CproNt02.ppt [互換モード]

演算増幅器

プログラミング実習I

kiso2-06.key

Microsoft PowerPoint - prog04.ppt

分割コンパイル (2018 年度 ) 担当 : 笹倉 佐藤 分割コンパイルとは 一つのプログラムのソースを複数のソースファイルに分けてコンパイルすること ある程度大きなプログラムの場合ソースファイルをいくつかに分割して開発するのが普通 1

Microsoft Word - no13.docx

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

Microsoft PowerPoint - 12.ppt [互換モード]

PowerPoint プレゼンテーション

ソフトウェア基礎 Ⅰ Report#2 提出日 : 2009 年 8 月 11 日 所属 : 工学部情報工学科 学籍番号 : K 氏名 : 當銘孔太

PowerPoint Presentation

メソッドのまとめ

Microsoft PowerPoint - prog04.ppt

Microsoft PowerPoint - prog08.ppt

Microsoft PowerPoint - 12.ppt [互換モード]

Java プログラミング Ⅰ 3 回目変数 変数 変 数 一時的に値を記憶させておく機能型 ( データ型 ) と識別子をもつ 2 型 ( データ型 ) 変数の種類型に応じて記憶できる値の種類や範囲が決まる 型 値の種類 値の範囲 boolean 真偽値 true / false char 2バイト文

memo

コンパイラ演習第 11 回 2006/1/19 大山恵弘 佐藤秀明 今回の内容 バリアント / レコード 表現方法 型付け パターンマッチ 型付け switch 文への変換 簡単な最適化 マッチング漏れ 以降のフェーズでの処理 発展 exhaustivenessinformation の利用 パター

#include<math.h> 数学関係の関数群で sin() cos() tan() などの三角関数や累乗の pow() 平方根を求める sqrt() 対数 log() などがあります #include<string.h> 文字列を扱う関数群 コイツもまた後日に 4. 自作関数 実は 関数は自分

02: 変数と標準入出力

Microsoft PowerPoint - 第3回目.ppt [互換モード]

memo

Microsoft PowerPoint - 13.ppt [互換モード]

02: 変数と標準入出力

このルールをそのまま正規表現として書くと 下記のようになります ^A[0-9]{2}00[0-9]{3}([0-9]{2})?$ ちょっと難しく見えるかもしれませんが 下記のような対応になっています 最初 固定 年度 固定 通番 ( 枝番 ) 最後 ルール "A" 数字 2 桁 0 を 2 桁 数字

講習No.1

1. 入力した文字列を得る 1.1. 関数 scanf() を使う まずは関数 scanf() を使ったプログラムを作ってみましょう 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: #include<stdio.h> #define SIZE 128 main(

Microsoft PowerPoint - kougi6.ppt

講習No.12

PowerPoint プレゼンテーション

Microsoft PowerPoint - prog03.ppt

次に示す数値の並びを昇順にソートするものとする このソートでは配列の末尾側から操作を行っていく まず 末尾の数値 9 と 8 に着目する 昇順にソートするので この値を交換すると以下の数値の並びになる 次に末尾側から 2 番目と 3 番目の 1

02: 変数と標準入出力

PYTHON 資料 電脳梁山泊烏賊塾 PYTHON 入門 文字列 文字列リテラル プログラムの中で文字列を表す方法は幾つか有るが 基本的な方法は下記の 2 種で有る 対象と成る文字の集まりをダブルクオーテーション ( " ) で囲うか シングルクオーテーション ( ' ) で囲う PYTHON3 "

Microsoft PowerPoint - prog08.ppt

Microsoft PowerPoint - å®�æ−•è©¦é¨fi3ㆮ対ç�Œ.pptx

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

Cプログラミング1(再) 第2回

基礎プログラミング2015

Microsoft PowerPoint - bp02.ppt

(2) 構造体変数の宣言 文法は次のとおり. struct 構造体タグ名構造体変数名 ; (1) と (2) は同時に行える. struct 構造体タグ名 { データ型変数 1; データ型変数 2;... 構造体変数名 ; 例 : struct STUDENT{ stdata; int id; do

Java プログラミング Ⅰ 3 回目変 数 今日の講義講義で学ぶ内容 変数とは 変数の使い方 キーボード入力の仕方 変 数 変 数 一時的に値を記憶させておく機能 変数は 型 ( データ型 ) と識別子をもちます 2 型 ( データ型 ) 変数に記憶する値の種類変数の型は 記憶できる値の種類と範囲

今までの復習 プログラムで最低限必要なもの 入力 ( キーボードから ファイルから ) 出力 ( 画面へ ファイルへ ) 条件分岐 : 条件の成立 不成立により 異なる動作をする 繰り返し : 一定の回数の繰返し 条件成立の間の繰返し 関数の定義 関数の呼び出し C ではそれ以外に ポインタ データ

memo

Prog1_15th

PowerPoint プレゼンテーション

数はファイル内のどの関数からでも参照できるので便利ではありますが 変数の衝突が起こったり ファイル内のどこで値が書き換えられたかわかりづらくなったりなどの欠点があります 複数の関数で変数を共有する時は出来るだけ引数を使うようにし グローバル変数は プログラムの全体の状態を表すものなど最低限のものに留

ファイル入出力

タブ or スペース? インデントには タブ文字を使用する方法と半角スペースを使用する方法があります インデントにタ ブ文字を使うか半角スペースを使うかは 各プロジェクトで決められていることもありますが プログラ ムを書く人の好みだったりすることもあります まともなエディタであれば タブキーを押下し

Microsoft PowerPoint - lec10.ppt

Java講座

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

Microsoft Word - CygwinでPython.docx

PowerPoint プレゼンテーション

JavaプログラミングⅠ

関数の動作 / printhw(); 7 printf(" n"); printhw(); printf("############ n"); 4 printhw(); 5 関数の作り方 ( 関数名 ) 戻り値 ( 後述 ) void である. 関数名 (

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

た場合クラスを用いて 以下のように書くことが出来る ( 教科書 p.270) プログラム例 2( ソースファイル名 :Chap08/AccountTester.java) // 銀行口座クラスとそれをテストするクラス第 1 版 // 銀行口座クラス class Account String name

C 言語の式と文 C 言語の文 ( 関数の呼び出し ) printf("hello, n"); 式 a a+4 a++ a = 7 関数名関数の引数セミコロン 3 < a "hello" printf("hello") 関数の引数は () で囲み, 中に式を書く. 文 ( 式文 ) は

<4D F736F F D20438CBE8CEA8D758DC03389F0939A82C282AB2E646F63>

コードテンプレートフレームワーク 機能ガイド 基礎編

02: 変数と標準入出力

Microsoft Word - Javacc.docx

情報工学実験 C コンパイラ第 2 回説明資料 (2017 年度 ) 担当 : 笹倉 佐藤

ポインタ変数

Transcription:

Boost.Preprocessor でプログラミングしましょう DigitalGhost http://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 もあります

もう一度 数字に関する注意 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 を手動で展開 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++ 的にはすごく効率が悪いですが 後の解説のためなので見逃してください )

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 を手動で展開 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; }

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

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

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

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)

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)

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)

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)

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

代入 #define X() 4 #define Y() X() #undef X Y Y は X() と展開される 4 と展開したい!

そこで #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 に展開される 素敵!

誰得? Boost.Typeof は 型を整数の列にエンコード する必要があるので 型に一意な整数 ID を振る ために使われています

他に BOOST_PP_ITERATE 自分自身を繰り返し #include します BOOST_PP_ENUM で書くにはマクロが大きすぎる場合に便利

Boost.PP を読むときの注意 BOOST_PP_AUTO_REC というマクロが登場しますが これが曲者です http://d.hatena.ne.jp/digitalghost/20090903/1252002035 に概要が あります

終わり