Preprocess-time Lambda Expression

Preview:

Citation preview

λ 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

ありがとう

●kothaさん

●http://www.kotha.net/

●アドバイスなどいただきました

終わり

Recommended