preprocess-time lambda expression
TRANSCRIPT
λ expression for PPを作ってみました
digitalghosthttp://d.hatena.ne.jp/DigitalGhost/
http://twitter.com/DecimalBloat
自己紹介
●きりんさんがすきです。
でもC++のほうがもーっとすきです。
●プリプロセッサで遊んでます
●実は仕事でC++を使ったことは一度もない
●他の方の発表見てから資料作成余裕でした
今日の話
1.前提2.この発表に説得力を付ける努力
1.どーきらしきもの2.簡単な例
3.使い方1.基本2.構文糖
4.実用例1.BOOST_PP_REPEATで
5.その他の話1.ChaosPreprocessor2.中途半端に形式的な文法3.今回のブツ4.ありがとう
前提
前提
●ラムダ式をなんとなく知っている
前提
●ラムダ式をなんとなく知っている
●Boost.Preprocessorのお世話になったことが
ある
前提
●ラムダ式をなんとなく知っている
●Boost.Preprocessorのお世話になったことが
ある
●BOOST_PP_ADD相当の機能が作れる
(もちろんプリプロセッサで)
この発表に説得力を
付ける努力
どーきらしきもの
●こんなことありませんか?
どーきらしきもの
●こんなことありませんか?
●BOOST_PP_REPEATを使うときステップごとの展
開用マクロをいちいち定義するのめんどくさい
どーきらしきもの
●こんなことありませんか?
●BOOST_PP_REPEATを使うときステップごとの展
開用マクロをいちいち定義するのめんどくさい
●引数がtupleのとき全要素にアクセスするためマクロ
を二段構えにするのめんどくさい
どーきらしきもの
●こんなことありませんか?
●BOOST_PP_REPEATを使うときステップごとの展
開用マクロをいちいち定義するのめんどくさい
●引数がtupleのとき全要素にアクセスするためマクロ
を二段構えにするのめんどくさい
※なければ何の役にも立たない話なので適当に時
間を潰してください。
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL, fun)
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL, fun)
展開結果void f0();void f1();…void f9();
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL, fun)
この#define FWD_DECLを定義するのが嫌だ
展開結果void f0();void f1();…void f9();
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL, fun)
この#define FWD_DECLを定義するのが嫌だ
ラムダ式使えればいいんじゃね?
展開結果void f0();void f1();…void f9();
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL, fun)
この#define FWD_DECLを定義するのが嫌だ
ラムダ式使えればいいんじゃね?
作ってみました
展開結果void f0();void f1();…void f9();
どーきらしきもの
例:void fun0() 〜 void fun9()のfowarding
declarationを作る
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL, fun)
この#define FWD_DECLを定義するのが嫌だ
ラムダ式使えればいいんじゃね?
作ってみました
●http://patch-tag.com/r/digitalghost/pplambda/home
展開結果void f0();void f1();…void f9();
簡単な例
さっきのfun0〜fun9をラムダ式で
簡単な例
さっきのfun0〜fun9をラムダ式で
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
簡単な例
さっきのfun0〜fun9をラムダ式で
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
●PP_LAMBDA_EVAL_Zはラムダ式の評価器
簡単な例
さっきのfun0〜fun9をラムダ式で
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
●PP_LAMBDA_EVAL_Zはラムダ式の評価器
●LAMBDA3から(();)までがラムダ式本体
簡単な例
さっきのfun0〜fun9をラムダ式で
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
●PP_LAMBDA_EVAL_Zはラムダ式の評価器
●LAMBDA3から(();)までがラムダ式本体
●#defineとか最初からいらんかったんや!
使い方
基本1
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
基本1
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
●PP_EVAL_LAMBDA(expr, params)はラムダ式
の評価器
基本1
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
●PP_EVAL_LAMBDA(expr, params)はラムダ式
の評価器
●第一引数がラムダ式
基本1
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
●PP_EVAL_LAMBDA(expr, params)はラムダ式
の評価器
●第一引数がラムダ式
●第二引数はラムダ式の引数
展開すると
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
展開すると
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
↓
BOOST_PP_CAT ( Azniyan , Kawaiinar )
展開すると
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
↓
BOOST_PP_CAT ( Azniyan , Kawaiinar )
↓
AzniyanKawaiinar
展開すると
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
↓
BOOST_PP_CAT ( Azniyan , Kawaiinar )
↓
AzniyanKawaiinar
※http://twitter.com/azniyan
基本2
●LAMBDAnは「n引数のラムダ式」という意味
(nは1〜3)
●以下のルール
●(hoge) → hoge●LPAREN → (●RPAREN → )●COMMA → ,●ARGn → ラムダ式のn個目の引数
の組み合わせ(nは1〜3)
もう一度あずにやんかわいいなあ
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
↓
BOOST_PP_CAT ( Azniyan , Kawaiinar )
↓
AzniyanKawaiinar
もう一度あずにやんかわいいなあ
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
↓
BOOST_PP_CAT ( Azniyan , Kawaiinar )
↓
AzniyanKawaiinar
LPARENやRPARENを並べた結果がマクロ呼び出しの形ならそれも展開される
LPARENとか書くのめんどくさい…
LPARENとか書くのめんどくさい…
●構文糖あります
LPARENとか書くのめんどくさい…
●構文糖あります
●APPLYn(f)(expr1, expr2, …)
= (f) LPAREN expr1 COMMA expr2 COMMA …
RPAREN
LPARENとか書くのめんどくさい…
●構文糖あります
●APPLYn(f)(expr1, expr2, …)
= (f) LPAREN expr1 COMMA expr2 COMMA …
RPAREN
●n(expr1, expr2, …)
= LPAREN expr1 COMMA expr2 COMMA …
RPAREN
LPARENとか書くのめんどくさい…
●構文糖あります
●APPLYn(f)(expr1, expr2, …)
= (f) LPAREN expr1 COMMA expr2 COMMA …
RPAREN
●n(expr1, expr2, …)
= LPAREN expr1 COMMA expr2 COMMA …
RPAREN
※ただしnは1〜3
あずにやん with 構文糖
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
あずにやん with 構文糖
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
は、こう書き換えられる
あずにやん with 構文糖
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
は、こう書き換えられる
PP_EVAL_LAMBDA(
LAMBDA2
APPLY2(BOOST_PP_CAT) (ARG1, ARG2),
(Azniyan, Kawaiinar))
あずにやん with 構文糖
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) LPAREN ARG1 COMMA ARG2 RPAREN,
(Azniyan, Kawaiinar))
こうも書き変えられる
PP_EVAL_LAMBDA(
LAMBDA2
(BOOST_PP_CAT) 2(ARG1, ARG2),
(Azniyan, Kawaiinar))
●APPLYを使うより短く書けるけど見た目がキモ
い
実用例
BOOST_PP_REPEATで
●導入で登場した例
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
BOOST_PP_REPEATで
●導入で登場した例
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
●ポイントは PP_LAMBDA_EVAL_Z
PP_LAMBDA_EVAL_Z
●ラムダ式で繰り返しを書くときに使う、EVALの
ラッパ
PP_LAMBDA_EVAL_Z
●ラムダ式で繰り返しを書くときに使う、EVALの
ラッパ
●「Z」はBOOST_PP_REPEATの繰り返し用関数
マクロの一つ目の引数に由来
PP_LAMBDA_EVAL_Z
●ラムダ式で繰り返しを書くときに使う、EVALの
ラッパ
●「Z」はBOOST_PP_REPEATの繰り返し用関数
マクロの一つ目の引数に由来
●BOOST_PP_REPEAT_FROM_TO や、
BOOST_PP_ENUMでもこのマクロを使えます
PP_LAMBDA_EVAL_Z
●ラムダ式で繰り返しを書くときに使う、EVALの
ラッパ
●「Z」はBOOST_PP_REPEATの繰り返し用関数
マクロの一つ目の引数に由来
●BOOST_PP_REPEAT_FROM_TO や、
BOOST_PP_ENUMでもこのマクロを使えます
●マジンガーもドラゴンボールも関係ないです
PP_LAMBDA_EVAL_Z
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL,
fun)
PP_LAMBDA_EVAL_Z
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL,
fun)
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
PP_LAMBDA_EVAL_Z
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL,
fun)
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
PP_LAMBDA_EVAL_Z
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL,
fun)
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
繰り返し用マクロをEVAL_Zに変更
PP_LAMBDA_EVAL_Z
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL,
fun)
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
繰り返し用マクロをEVAL_Zに変更
PP_LAMBDA_EVAL_Z
#define FWD_DECL(z, n, d) \
void BOOST_PP_CAT(d, n)();
BOOST_PP_REPEAT(10, FWD_DECL,
fun)
BOOST_PP_REPEAT(10, PP_LAMBDA_EVAL_Z,
(LAMBDA3 (void)
APPLY2(BOOST_PP_CAT)(3_, 2_)
(();),
fun))
繰り返し用マクロをEVAL_Zに変更
三つ目の引数をラムダ式と繰り返しマクロの引数のタプルにする
その他の話
Chaos Preprocessor
Chaos Preprocessor
●http://sourceforge.net/projects/chaos-pp/
Chaos Preprocessor
●http://sourceforge.net/projects/chaos-pp/
●Boost.PPの作者によるプリプロセッサメタプロ
グラミングライブラリ
例:Active Argument
●ドキュメントの一番最初に紹介されている機能
例:Active Argument
●ドキュメントの一番最初に紹介されている機能#define A(n) \ CHAOS_PP_DEFER(A_INDIRECT)()(CHAOS_PP_INC(n)) \ /**/#define A_INDIRECT() A
#define X(arg) arg#define Y(arg) X(arg)#define Z(arg) Y(arg)
A(0) // A_INDIRECT()(1)X( A(0) ) // A_INDIRECT()(2)Y( A(0) ) // A_INDIRECT()(3)Z( A(0) ) // A_INDIRECT()(4)
例:Active Argument
●ドキュメントの一番最初に紹介されている機能#define A(n) \ CHAOS_PP_DEFER(A_INDIRECT)()(CHAOS_PP_INC(n)) \ /**/#define A_INDIRECT() A
#define X(arg) arg#define Y(arg) X(arg)#define Z(arg) Y(arg)
A(0) // A_INDIRECT()(1)X( A(0) ) // A_INDIRECT()(2)Y( A(0) ) // A_INDIRECT()(3)Z( A(0) ) // A_INDIRECT()(4)
●どう使うんだろう…
中途半端に形式的な文法
pp-lambda: LAMBDA n pp-lambda-expr
pp-lambda-expr: pp-lambda-term pp-lambda-expr pp-lambda-term
pp-lambda-term: pp-lambda-literal pp-lambda-parameter pp-lambda-macro-call COMMA LPAREN RPAREN pp-lambda-tuple
pp-lambda-macro-call: APPLY n ( balanced-pp-tokens ) ( pp-lambda-expr-list )
pp-lambda-expr-list: pp-lambda-expr pp-lambda-expr-list , pp-lambda-expr
pp-lambda-parameter: digit underscore
pp-lambda-literal: ( balanced-pp-tokens )
pp-lambda-tuple: digit ( pp-lambda-expr-list )
underscore: 直前に空白文字がない _
n: 直前に空白文字がない digit
今回のブツ
●http://patch-tag.com/r/digitalghost/pplambda/home
●darcs get http://patch-tag.com/r/digitalghost/pplambda
●http://sites.google.com/site/ilikemanaka/code/pplambda.tar.bz2
終わり