SlideShare a Scribd company logo
Define and Expansion of CPP Macro
Cプリプロセッサマクロの定義と展開
2014/06/28
ドワンゴC++勉強会 #1
でちまる
自己紹介
● でちまる
● @decimalbloat
● 仕事
– 艦これコンテンツの回収と観賞
– ツイッター上で見かけた不思議C++コードを見て実装を
看破する
– Android上でJavaを書く(web系ではない)
本日の発表は
● constexpr
● Cプリプロセッサ
● C++老害トーク
● どれも明日から職場で即実践できる話ばかり
● 是非ご活用ください
今日の話
● Cプリプロセッサメタプログラミングについて
● Cプリプロセッサメタプログラミングの技法
Cプリプロセッサメタプログラミング
について
Cプリプロセッサメタプログラミングとは
● Cプリプロセッサで(主にC++の)コードを出力する
プログラムを書く行為
● C++の構文木や意味論などは一切無視して字句
レベルでプログラムを生成する
● やってることとしてはsedとかawkと変わらない
10個の連番の関数を宣言する例
● #define F(z, i, d) 
void BOOST_PP_CAT(f, i)(int);
BOOST_PP_REPEAT(10, F, ~)
→ void f0(int); void f1(int); …… void f9(int);
● 実際に void f0(int); … とかいうのがソースに書か
れている,と扱われる
使いどころ
● 他の言語機能で解決できないケース
● 例: Scope Exit
– 即席RAIIのためのマクロ
– 簡単にいうと次のようなもの
Scope Exit の簡単な実装
#define SCOPE_EXIT 
scope_exit_t BOOST_PP_CAT(scope_exit_var, __LINE__) = [&]
struct scope_exit_t {
std::function<void()> f;
template<typename F>
scope_exit_t(F f) : f(f) {}
~scope_exit_t() { f(); }
};
int main() {
SCOPE_EXIT { std::cout << "hogen"; };
SCOPE_EXIT { std::cout << "fuga, "; };
}
→ fuga, hoge
Scope Exit の簡単な実装
● RAIIで必要な処理をさせるためにはそれ用の変数
もしくはクラスに名前を付ける必要がある
● しかし単にデストラクタを呼ぶだけなので,人間側
の都合としてはどうでもよい
●
そんなわけでこういうマクロを書けば余計な名前を
考える手間もコード上のノイズも減る
よく言われる問題
野蛮
● 何事も暴力で解決するのが一番だ
――NINJASLAYER より レッドゴリラ=サン
● CプリプロセッサはC++の構文も意味論も理解しな
い
● まーでもこれ以外ないから暴力で解決だ
では構文を解すればよいのでは?
● ついこの間提案された
● http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2014/n3883
.html
● 10年単位で待てばいけるかもしれない
名前が衝突する
● BOOST_PP_ とかそういうprefix付ければ普通衝
突しない
● それでも衝突するのはただの当たり屋では?
コンパイルエラーがひどい
● はい
● ただしそれは関数マクロでやった場合の話
● include主体でやればそうでもない(後述しようと
思ったが時間がなくなった)
制限が多い
● はい
● 再帰展開できないとかそういうのがある
● そもそも,アプリケーション開発でコード生成が必
要になったのなら別にCプリプロセッサでなくPHPと
かPerlとかでよい
● わざわざCプリプロセッサでやるのは,PHPがない
環境でもコード生成したいから
ここまでのまとめ
● PHP使えよ
Cプリプロセッサメタプログラミング
の技法
選べる2つのスタイル
● 関数マクロ濫用スタイル
● include濫用スタイル(こっちの話はしない)
関数マクロ濫用スタイルにおける基本
的な技法
●
基本
– 連結と再展開
– 評価順の制御
– 引数の解体
● 応用
– 数値と真理値
– 分岐
– 繰り返し
– データ構造
基本
連結と再展開
● #define CAT(a, b) a ## b
#define AB C
CAT(A, B)
→C
● 連結してできたトークンをマクロ名として定義してお
くことで,更に展開する
評価順の制御
● #define CAT(a, b) a ## b
CAT(A, CAT(B, C))
ACAT(B, C)
● マクロの置換規則はC++の関数とは大きく違うの
でなかなか分かりづらい
評価順の制御
● 置換の基本は
– 外側のマクロを置き換えてから,
– トークン連結して,
– それぞれの引数を個別に置換して,
– 元の場所に挿入して,
– その場所からもう一度置換する
評価順の制御
● #define CAT(a, b) a ## b
CAT(A, CAT(B, C))
→ACAT(B, C)
● 外側のマクロを置き換えると A ## CAT(B, C)
● 連結すると ACAT(B, C) なので引数としては扱わ
れなくなる
評価順の制御
● #define CAT(a, b) CAT_I(a, b)
#define CAT_I(a, b) a ## b
ーCAT(A, CAT(B, C))
→ABC
● 外側のマクロを置き換えると CAT_I(A, CAT(B, C))
●
トークン連結はないのでそのまま
● 引数について展開する(CATが意図通り動くとする)と CAT_I(A, BC)
●
元の場所に戻してそこからもう一度置換する
● 外側のマクロを置き換えると A ## BC
● 連結して ABC
●
以下省略
引数の解体
● #define REM(...) __VA_ARGS__
#define AP(f, x) f(42, x)
#define F(n, x) F_I(n, REM x)
#define F_I(n, x) F_II(n, x)
#define F(n, x, y, z)
AP(F, (A, B, C))
→
● カッコで包めば一つの引数にできるので,任意長
のarityのマクロを固定長引数のマクロの中で扱え
る
● このマクロの置換がどのように行われるかは自明
なので,手順は読者の課題とする(放棄)
応用
数値と真理値
● Cプリプロセッサには数値という概念はない
● (一部の文脈を除く)
● ソースコード上に現われる1とか2とかいうトークン
を数値として扱うことにする
● 同様に0と1をそれぞれtrueとfalseとして扱うことに
する
● マクロの上でどうやってそれらを数値や真理値とみ
なすのかは次のページで
分岐
● 分岐は基本的な技法だけで書ける
● #define IF(c, t, f) CAT(IF, c)(t, f)
#define IF1(t, f) t
#define IF0(t, f) f
IF(1, hoge, fuga)
→hoge
IF(0, hoge, fuga)
→fuga
分岐
● IFと1または0を連結することでそれが再度マクロ名となることで,
二つのマクロ (IF1, IF0) を使い分ける
● C風の数値から整数への変換も次のように書ける
● #define BOOL(n) CAT(BOOL, n)
#define BOOL0 0
#define BOOL1 1
#define BOOL2 1
#define BOOL3 1
…
BOOL(3)
→1
分岐
● IFと組み合わせればCのif風のものもできる
● #define IF2(n, t, f) IF(BOOL(n), t, f)
数値計算
● とりあえず1加算するマクロだけ作る
● #define INC(n) INC ## n
#define INC0 1
#define INC1 2
#define INC2 3
…
INC(INC(2))
→4
● やってることはBOOLと同じ
繰り返し
● 汎用の繰り返しマクロを作るにはいくつかの方法
があるが,全てについて
● 「どの繰り返しマクロも同じようなことを何個もコピ
ペして書いている」
● というのは共通している
繰り返し
●
最も単純な実装
● #define REPEAT(n, m) REPEAT ## n(m)
#define REPEAT0(m)
#define REPEAT1(m) m(0)
#define REPEAT2(m) REPEAT1(m) m(1)
#define REPEAT3(m) REPEAT2(m) m(2)
#define F(n) hoge ## n
REPEAT(3, F)
→hoge0 hoge1 hoge2
● mを関数マクロとみなすことで,繰り返す内容を自由に指定で
きる
繰り返し
●
もっと複雑なもの
● #define WHILE WHILE0
#define WHILE_END(p, st, op) st
#define WHILE0(p, st, op) 
IF(p(st), WHILE1, WHILE_END)(p, st, op)
#define WHILE1(p, st, op) 
IF(p(op(st)), WHILE2, WHILE_END)(p, op(st), op)
#define WHILE2(p, st, op) 
IF(p(op(st)), WHILE3, WHILE_END)(p, op(st), op)
#define WHILE3(p, st, op) 
IF(p(op(st)), WHILE4, WHILE_END)(p, op(st), op)
…
● p(st)が偽だったらst
● 真だったらop(st)した結果で同じことを繰り返す
繰り返し
● 次のように使う(DECはINCの逆として定義したマク
ロとする)
● #define ADD(m, n) ADD_I WHILE(P, (m, n), OP)
#define P(st) P_I st
#define P_I(m, n) BOOL(m)
#define OP(x) OP_I x
#define OP_I(m, n) (DEC(m), INC(n))
ADD(3, 4)
→7
注意
● 今まで見てきた繰り返しマクロは,引数のマクロ
(ループ内で使うマクロ)の中で同繰り返しマクロを
使うことができない
● そんなわけでこの制限を出し抜くために次のような
技法が考案された
● http://www.slideshare.net/digitalghost/c-
35069539
データ構造
● いくつかあるがよく使われているのは次の二つ
– (a)(b)(c)
– (a, b, c)
Sequence
● (a)(b)(c) というような形式を sequenceと言う
● 先頭または末尾への要素の追加,削除はO(1)で
できるが要素へのアクセスはO(N)なデータ構造
Sequence
● コード例はオンラインで
Tuple
● (a, b, c) のような形式をtupleという
● 長さを変更できないが要素へのアクセスはO(1)な
データ構造
– だった
● C++11からVariadic Macroが導入されたので長さ
の制限がなくなった
Tuple
● コード例はオンラインで
データ構造
● だいたいこの2つがあればまともなプログラムが書
ける
● いずれのデータ構造用の関数マクロも,ループ同
様職人が丹精こめて書き上げたコピペ手直しコー
ドでできている
まとめ
● PHPを使え
● 置換とトークン連結だけでも足し算は作れる
● たとえ貧弱な機能でも人間は濫用する.
抵抗は無意味だ
参考になるソースコード
● http://boost.org/
● https://github.com/dechimal/desalt
質疑応答
終わり

More Related Content

PDF
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
 
PPTX
レベルを上げて物理で殴れ、Fuzzing入門 #pyfes
Tokoroten Nakayama
 
PDF
Popcntによるハミング距離計算
Norishige Fukushima
 
PPTX
HoloLens光学系の謎に迫る
AmadeusSVX
 
PPTX
FINAL FANTASY Record Keeperのマスターデータを支える技術
dena_study
 
PDF
1076: CUDAデバッグ・プロファイリング入門
NVIDIA Japan
 
PPTX
Gstreamer Basics
Seiji Hiraki
 
PDF
ゲーム開発者のための C++11/C++14
Ryo Suzuki
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
Y Watanabe
 
レベルを上げて物理で殴れ、Fuzzing入門 #pyfes
Tokoroten Nakayama
 
Popcntによるハミング距離計算
Norishige Fukushima
 
HoloLens光学系の謎に迫る
AmadeusSVX
 
FINAL FANTASY Record Keeperのマスターデータを支える技術
dena_study
 
1076: CUDAデバッグ・プロファイリング入門
NVIDIA Japan
 
Gstreamer Basics
Seiji Hiraki
 
ゲーム開発者のための C++11/C++14
Ryo Suzuki
 

What's hot (20)

PDF
06 第5.1節-第5.7節 ROS2に対応したツール/パッケージ
Mori Ken
 
PDF
1072: アプリケーション開発を加速するCUDAライブラリ
NVIDIA Japan
 
PPTX
WiredTigerを詳しく説明
Tetsutaro Watanabe
 
PDF
.NET Core 3.0時代のメモリ管理
KageShiron
 
PDF
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
NTT DATA Technology & Innovation
 
PPTX
UE4のスレッドの流れと Input Latency改善の仕組み
エピック・ゲームズ・ジャパン Epic Games Japan
 
PDF
ソーシャルゲームの為のデータベース設計
kaminashi
 
PDF
Introduction to A3C model
WEBFARMER. ltd.
 
DOCX
UE4でPerforceと連携するための手順
エピック・ゲームズ・ジャパン Epic Games Japan
 
PDF
C/C++プログラマのための開発ツール
MITSUNARI Shigeo
 
PDF
深層強化学習でマルチエージェント学習(前篇)
Junichiro Katsuta
 
PDF
30th コンピュータビジョン勉強会@関東 DynamicFusion
Hiroki Mizuno
 
PPT
実行時のために最適なデータ構造を作成しよう
Hiroki Omae
 
PPTX
大規模グラフデータ処理
maruyama097
 
PDF
SfMLearner++ Intro
Hirohito Okuda
 
PDF
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
Takahiro Inoue
 
PPTX
競技プログラミングのためのC++入門
natrium11321
 
PDF
ROS2勉強会@別府 第7章Pythonクライアントライブラリrclpy
Atsuki Yokota
 
PDF
メルカリ・ソウゾウでは どうGoを活用しているのか?
Takuya Ueda
 
PDF
AIによるアニメ生成の挑戦
Koichi Hamada
 
06 第5.1節-第5.7節 ROS2に対応したツール/パッケージ
Mori Ken
 
1072: アプリケーション開発を加速するCUDAライブラリ
NVIDIA Japan
 
WiredTigerを詳しく説明
Tetsutaro Watanabe
 
.NET Core 3.0時代のメモリ管理
KageShiron
 
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
NTT DATA Technology & Innovation
 
UE4のスレッドの流れと Input Latency改善の仕組み
エピック・ゲームズ・ジャパン Epic Games Japan
 
ソーシャルゲームの為のデータベース設計
kaminashi
 
Introduction to A3C model
WEBFARMER. ltd.
 
UE4でPerforceと連携するための手順
エピック・ゲームズ・ジャパン Epic Games Japan
 
C/C++プログラマのための開発ツール
MITSUNARI Shigeo
 
深層強化学習でマルチエージェント学習(前篇)
Junichiro Katsuta
 
30th コンピュータビジョン勉強会@関東 DynamicFusion
Hiroki Mizuno
 
実行時のために最適なデータ構造を作成しよう
Hiroki Omae
 
大規模グラフデータ処理
maruyama097
 
SfMLearner++ Intro
Hirohito Okuda
 
「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜
Takahiro Inoue
 
競技プログラミングのためのC++入門
natrium11321
 
ROS2勉強会@別府 第7章Pythonクライアントライブラリrclpy
Atsuki Yokota
 
メルカリ・ソウゾウでは どうGoを活用しているのか?
Takuya Ueda
 
AIによるアニメ生成の挑戦
Koichi Hamada
 
Ad

Similar to Define and expansion of cpp macro (20)

PDF
第1回勉強会スライド
koturn 0;
 
PPTX
C++ tips 3 カンマ演算子編
道化師 堂華
 
PPT
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
Kiyoshi Ogawa
 
PDF
競技プログラミングにおけるコードの書き方とその利便性
Hibiki Yamashiro
 
PDF
わんくま同盟大阪勉強会#61
TATSUYA HAYAMIZU
 
PDF
C・C++用のコードカバレッジツールを自作してみた話
simotin13 Miyazaki
 
PDF
ディープラーニングフレームワーク とChainerの実装
Ryosuke Okuta
 
PDF
C++ template-primer
Kohsuke Yuasa
 
PPTX
C++の復習
Toshihiko Ando
 
PPTX
C++ tips4 cv修飾編
道化師 堂華
 
PDF
君はまだ,本当のプリプロセスを知らない
digitalghost
 
PDF
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
Masashi Shibata
 
PPTX
関数型言語&形式的手法セミナー(3)
啓 小笠原
 
PDF
【学習メモ#4th】12ステップで作る組込みOS自作入門
sandai
 
PDF
C++でCプリプロセッサを作ったり速くしたりしたお話
Kinuko Yasuda
 
PDF
Run-time Code Generation and Modal-ML の紹介@PLDIr#2
Masahiro Sakai
 
PDF
DTrace for biginners part(2)
Shoji Haraguchi
 
PDF
Bjarne dont speaking
Akira Takahashi
 
PPTX
.NET micro FrameWork for TOPPERS (.NET基礎)@基礎勉強会
Kiyoshi Ogawa
 
PPTX
なにわテック20180127
Natsutani Minoru
 
第1回勉強会スライド
koturn 0;
 
C++ tips 3 カンマ演算子編
道化師 堂華
 
「C言語規格&MISRA-C:みんなで楽しいCプログラミング」NGK2013B名古屋合同懇親会2013忘年会昼の部
Kiyoshi Ogawa
 
競技プログラミングにおけるコードの書き方とその利便性
Hibiki Yamashiro
 
わんくま同盟大阪勉強会#61
TATSUYA HAYAMIZU
 
C・C++用のコードカバレッジツールを自作してみた話
simotin13 Miyazaki
 
ディープラーニングフレームワーク とChainerの実装
Ryosuke Okuta
 
C++ template-primer
Kohsuke Yuasa
 
C++の復習
Toshihiko Ando
 
C++ tips4 cv修飾編
道化師 堂華
 
君はまだ,本当のプリプロセスを知らない
digitalghost
 
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
Masashi Shibata
 
関数型言語&形式的手法セミナー(3)
啓 小笠原
 
【学習メモ#4th】12ステップで作る組込みOS自作入門
sandai
 
C++でCプリプロセッサを作ったり速くしたりしたお話
Kinuko Yasuda
 
Run-time Code Generation and Modal-ML の紹介@PLDIr#2
Masahiro Sakai
 
DTrace for biginners part(2)
Shoji Haraguchi
 
Bjarne dont speaking
Akira Takahashi
 
.NET micro FrameWork for TOPPERS (.NET基礎)@基礎勉強会
Kiyoshi Ogawa
 
なにわテック20180127
Natsutani Minoru
 
Ad

More from digitalghost (8)

PPTX
ナウなヤングにバカうけのイカしたタグ付き共用体
digitalghost
 
PDF
拡張可能でprintfっぽい書式指定ができて書式指定文字列と引数をコンパイル時に検証できる文字列フォーマット関数を作った
digitalghost
 
PDF
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
digitalghost
 
PDF
C++コンパイラ GCCとClangからのメッセージをお読みください
digitalghost
 
PDF
No skk, no life.
digitalghost
 
PDF
Boost.Preprocessorでプログラミングしましょう
digitalghost
 
PDF
テンプレートメタプログラミング as 式
digitalghost
 
PDF
Preprocess-time Lambda Expression
digitalghost
 
ナウなヤングにバカうけのイカしたタグ付き共用体
digitalghost
 
拡張可能でprintfっぽい書式指定ができて書式指定文字列と引数をコンパイル時に検証できる文字列フォーマット関数を作った
digitalghost
 
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
digitalghost
 
C++コンパイラ GCCとClangからのメッセージをお読みください
digitalghost
 
No skk, no life.
digitalghost
 
Boost.Preprocessorでプログラミングしましょう
digitalghost
 
テンプレートメタプログラミング as 式
digitalghost
 
Preprocess-time Lambda Expression
digitalghost
 

Define and expansion of cpp macro