SlideShare a Scribd company logo
1 of 33
Download to read offline
君はまだ,本当のプリプロセスを知らない
C Preprocessor's Counterattack
あいさつ
● でちまる (@decimalbloat)
● http://libdechimal.so/
● http://github.com/dechimal/desalt/
● 仕事募集中
● 本日の誰得発表第2部
今日の話を三行で
● ある型と振る舞いが同じな別の型が欲しい
● できるだけ簡単に生成するマクロ書いたよ
● みなさんと一緒にそのコードを探
検することで,Cプリプロセッサ
の深淵を共有したい
目次
● Strong Typedef とは
● Desalt.Newtype とは
● Desalt.Newtype の内部(今日の主題)
Strong Typedef とは
よくある事例
● “A:” >> qi::int_ % ','
| “B:” >> qi::int_ % ','
| “C:” >> qi::string
● 結果は variant<vector<int>, string> 相当
● しかし A: と B: の場合で区別したい
● variant<vector<int>, vector<int>,
string> になりませんか?
よくある事例
● struct player {
unsigned hp;
unsigned atk;
void attack(player & target) {
target.hp -= this->hp;
}
};
_人人人人人人_
> 体力勝負 <
 ̄Y^Y^Y^Y^Y ̄
解決法
● 単純に元の型の値をメンバに持つだけのラッパを書く
– おもんない
– 取り出したあとは同じ型なので後者の例だとやはり取り違える
可能性がある
● 元の型と同じI/Fと振る舞いを持つ型で代用する
– その型を作るのが果てしなく面倒
– Strong Typedef を使えば楽
– 既存の実装は整数限定だし汎用的に使えるの作ろう
Desalt.Newtype とは
Desalt.Newtype
● https://github.com/dechimal/desalt/blob/master/te
st/newtype.cpp
● Strong Typedef の一種
● Boost.Serialization のものとは違って整数以外に適用で
きる
お詫び
● 今 github に上がってるコードは gcc のバージョン上げたら
動かなくなってました☆(・ω<)
– マクロではなく TMP の部分でエラーになってるので C++ コンパ
イラ各位にはデバッグをお願いしたく
コード例
● std::vector<int> の begin と end メンバと全ての
コンストラクタのみを公開し,as_base という名前で元
の型の値として扱える ivector クラスの定義
● DESALT_NEWTYPE(ivector, std::vector<int>,
as_base,
begin,
end,
this
);
コード例
● std::basic_string<T> の機能のうち, append と
ostream への出力だけができる mystring 型
– (append は引数も戻り値も mystring 型)
● DESALT_NEWTYPE(mystring, std::string,
as_base,
this,
auto append,
namespace explicit (operator<<)
(std::ostream &, mystring const &)
);
↑ここまで
C++ Advent Calendar 2012 への投稿 +α
今日の本題
↓ここから
Desalt.Newtype の内部
構文要素 this
● DESALT_NEWTYPE(hoge, fuga,
as_fuga,
piyo, // using fuga::piyo;
this // using fuga::fuga;
);
● this は Inheriting Ctor を使うための(このマクロに
とっての)キーワードで,つまり中で using
fuga::fuga; をしている
● どうなってるのか?
構文要素 this
● ある識別子(らしきもの)がトークン列の先頭に含
まれているかを調べればよい
● #define KEYWORDthis ,
IS_EMPTY(TUPLE_ELEM(0, (CAT(KEYWORD,
this))))
● 要するに,KEYWORD をトークン連結した相手が
this だった場合のみ空トークンになるようにして判
定している
構文要素 this
● DESALT_NEWTYPE(hoge, fuga,
as_fuga,
piyo, // using fuga::piyo;
this // using fuga::fuga;
);
● 先の方法で this 以外の未知のトークンも判定
できるので,知らないトークンだったらそのま
ま using する
構文要素 auto
● struct fuga {
fuga piyo(int, fuga const &);
};
DESALT_NEWTYPE(hoge, fuga,
as_fuga,
auto piyo // hoge piyo(int x, hoge const & y) {
); // return piyo(x, y);
// }
● auto キーワードを使うと元の関数の引数と戻り値型を新しい型で置
き換えた関数を定義する(関係ない型はそのまま)
● これをするには auto piyo から piyo を取り出す必要がある
構文要素 auto
● this の件でやった方法をそのまま流用
● #define KEYWORDauto ,
IS_EMPTY(BOOST_PP_TUPLE_ELEM(1,
(CAT(KEYWORD, auto piyo))))
● 要するに KEYWORD をくっ付けたら auto が消
えてカンマになるのでそれをタプルとして扱っ
て最初の要素(空トークン)を読み飛ばす
オンデマンド括弧
● template<typename T, typename U>
DESALT_NEWTYPE(hoge, (fuga<T, U>),
as_fuga
);
● クラステンプレートの場合だけ元のクラスの周
りに括弧が必要
● 括弧があるときだけ外す必要がある
オンデマンド括弧
● トークン列の先頭に括弧があるかどうかを調べられたらよい
● #define IS_PAREN(...) 
IS_PAREN_I(CAT(A, B __VA_ARGS__))
#define B(...) OK
#define AB 0,
#define AOK 1,
#define IS_PAREN_I(...) 
IS_PAREN_II(__VA_ARGS__)
#define IS_PAREN_II(x, ...) x
● トークン列の前にテスト用の関数マクロを置くと,展開され
たときは OK に,されなかったときはそのまま残るの
で,this のときと同じ手法で判定すればよい
空トークン
● DESALT_NEWTYPE(hoge, fuga,
as_fuga,
, // do nothing
piyo ,
);
● 何も定義しない行が存在してもよい
● ところが任意のトークン列が空かどうかを判定す
るのに Boost.PP の IS_EMPTY は使えない
空トークン
● Boost.PP の IS_EMPTY の実装
● #define IS_EMPTY(x) 
IS_EMPTY_I(x A)
#define IS_EMPTY_I(y) 
TUPLE_ELEM(2, 1, B ## y ())
#define A() , 0
#define BA() 1, 1 EMPTY
#define EMPTY()
空トークン
● この実装の問題
– カンマを扱えない
– 先頭のトークンが識別子(の一部になれる)でない
といけない
● 今の時代 __VA_ARGS__ 使えばよい
空トークン
● 先頭に何があるのか分からない場合,連結での
チェックはできない
● そこで IS_PAREN を使って実装することで連
結せずに空トークンかどうかを判定する
空トークン
● #define IS_EMPTY(...) 
IF(IS_PAREN(__VA_ARGS__ ()), 
IS_EMPTY_I, 
0 TUPLE_EAT())(__VA_ARGS__)
#define IS_EMPTY_I(...) 
IF(IS_PAREN(__VA_ARGS__), 
0 TUPLE_EAT(), 
IS_EMPTY_II)(__VA_ARGS__)
#define IS_EMPTY_II(...) 
IS_PAREN(CAT(A, __VA_ARGS__) ())
#define A() ()
空トークン
● 重要な部分はこの2つ
– IS_PAREN(__VA_ARGS__()) … A
– IS_PAREN(__VA_ARGS__) … B
● A が 1 である場合
– 空
– 括弧で始まっている
– 末尾の括弧により展開されて上のどちらかになる … α
● 上の場合で,かつ,B が 0 になる場合
– 空
– α によって A が 1 になった場合
空トークン
● A が 1 で B が 0 になるケースでは,次のどちらかになる
– 空
– 識別子っぽいもの
● IS_PAREN(CAT(A, __VA_ARGS__) ())
#define A() ()
● ここまでくるとトークン連結が使えるので,補助マクロを使っ
て,__VA_ARGS__ が空であれば () になるようにすれば判定
できる
空トークン
● 実は Desalt.Newtype では有効に使ってない
ことに気付いた
終わりに
● Cプリプロセッサを使えばまぁまぁそれっぽい
DSLを作れる
● Template だけではコピペを軽減できないとき
には迷わず使おう
● Cプリプロセッサは(まだ)友達
このマクロを書いた人は
こんなマクロを書いています
● PPLambda
– #define で定義せずにマクロを作って適用する
– http://patch-tag.com/r/digitalghost/pplambda/home
● InitWithTuple
– std::tie みたいにタプルを使って複数の変数を初期化する
– https://github.com/dechimal/init-with-tuple
● AttoTest
– 自分用ユニットテストフレームワーク
– https://github.com/dechimal/atto-test
Special Thanks (アルファベット順)
● Cryolite さん
– 本日私の隣で同じく資料を作成する傍ら励ましをいただいた
● fadis_ さん
– LibreOfficeのダウンロードを手伝っていただいた
● Flast_RO さん
– LibreOfficeのダウンロードを手伝っていただいた
● melponn さん
– 無線LAN環境を貸していただいた
● ボレロさん,昼食で遅れたみなさん
– おかげで発表資料を書く時間をいただいた

More Related Content

What's hot

Effective Modern C++ 勉強会#1 Item3,4
Effective Modern C++ 勉強会#1 Item3,4Effective Modern C++ 勉強会#1 Item3,4
Effective Modern C++ 勉強会#1 Item3,4Takashi Hoshino
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプKohsuke Yuasa
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性Hibiki Yamashiro
 
C++ tips 3 カンマ演算子編
C++ tips 3 カンマ演算子編C++ tips 3 カンマ演算子編
C++ tips 3 カンマ演算子編道化師 堂華
 
最新C++事情 C++14-C++20 (2018年10月)
最新C++事情 C++14-C++20 (2018年10月)最新C++事情 C++14-C++20 (2018年10月)
最新C++事情 C++14-C++20 (2018年10月)Akihiko Matuura
 
C++ tips2 インクリメント編
C++ tips2 インクリメント編C++ tips2 インクリメント編
C++ tips2 インクリメント編道化師 堂華
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードShigenori Sagawa
 
静的型付け言語Python
静的型付け言語Python静的型付け言語Python
静的型付け言語Pythonkiki utagawa
 
エラーハンドリング
エラーハンドリングエラーハンドリング
エラーハンドリング道化師 堂華
 
C# 8.0 null許容参照型
C# 8.0 null許容参照型C# 8.0 null許容参照型
C# 8.0 null許容参照型信之 岩永
 
F#によるFunctional Programming入門
F#によるFunctional Programming入門F#によるFunctional Programming入門
F#によるFunctional Programming入門bleis tift
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61TATSUYA HAYAMIZU
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14Ryo Suzuki
 
C++入門?
C++入門?C++入門?
C++入門?tsudaa
 

What's hot (20)

Effective Modern C++ 勉強会#1 Item3,4
Effective Modern C++ 勉強会#1 Item3,4Effective Modern C++ 勉強会#1 Item3,4
Effective Modern C++ 勉強会#1 Item3,4
 
C++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプC++ ポインタ ブートキャンプ
C++ ポインタ ブートキャンプ
 
C++ tips1 #include編
C++ tips1 #include編C++ tips1 #include編
C++ tips1 #include編
 
C++ tips4 cv修飾編
C++ tips4 cv修飾編C++ tips4 cv修飾編
C++ tips4 cv修飾編
 
競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性競技プログラミングにおけるコードの書き方とその利便性
競技プログラミングにおけるコードの書き方とその利便性
 
C++ tips 3 カンマ演算子編
C++ tips 3 カンマ演算子編C++ tips 3 カンマ演算子編
C++ tips 3 カンマ演算子編
 
最新C++事情 C++14-C++20 (2018年10月)
最新C++事情 C++14-C++20 (2018年10月)最新C++事情 C++14-C++20 (2018年10月)
最新C++事情 C++14-C++20 (2018年10月)
 
C++ tips2 インクリメント編
C++ tips2 インクリメント編C++ tips2 インクリメント編
C++ tips2 インクリメント編
 
プログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコードプログラムの処方箋~健康なコードと病んだコード
プログラムの処方箋~健康なコードと病んだコード
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
 
Map
MapMap
Map
 
静的型付け言語Python
静的型付け言語Python静的型付け言語Python
静的型付け言語Python
 
エラーハンドリング
エラーハンドリングエラーハンドリング
エラーハンドリング
 
C# 8.0 null許容参照型
C# 8.0 null許容参照型C# 8.0 null許容参照型
C# 8.0 null許容参照型
 
Emcpp0506
Emcpp0506Emcpp0506
Emcpp0506
 
F#によるFunctional Programming入門
F#によるFunctional Programming入門F#によるFunctional Programming入門
F#によるFunctional Programming入門
 
わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61わんくま同盟大阪勉強会#61
わんくま同盟大阪勉強会#61
 
Emcjp item21
Emcjp item21Emcjp item21
Emcjp item21
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
C++入門?
C++入門?C++入門?
C++入門?
 

Similar to 君はまだ,本当のプリプロセスを知らない

組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由kikairoya
 
Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~CHY72
 
(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話Masanori Masui
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexprGenya Murakami
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるHideyuki Tanaka
 
とあるFlashの自動生成
とあるFlashの自動生成とあるFlashの自動生成
とあるFlashの自動生成Akineko Shimizu
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッドKohsuke Yuasa
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語るAkira Takahashi
 
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALegtra
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
第2回勉強会スライド
第2回勉強会スライド第2回勉強会スライド
第2回勉強会スライドkoturn 0;
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Rubymitim
 
C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料真一 北原
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようShinsuke Sugaya
 
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践LINE Corporation
 
SEH on mingw32
SEH on mingw32SEH on mingw32
SEH on mingw32kikairoya
 

Similar to 君はまだ,本当のプリプロセスを知らない (20)

組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 
Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~Unity2015_No10_~UGUI&Audio~
Unity2015_No10_~UGUI&Audio~
 
(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話
 
C++14言語編
C++14言語編C++14言語編
C++14言語編
 
中3女子でもわかる constexpr
中3女子でもわかる constexpr中3女子でもわかる constexpr
中3女子でもわかる constexpr
 
C++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISるC++コミュニティーの中心でC++をDISる
C++コミュニティーの中心でC++をDISる
 
とあるFlashの自動生成
とあるFlashの自動生成とあるFlashの自動生成
とあるFlashの自動生成
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
Visual C++コード分析を支えるSAL
Visual C++コード分析を支えるSALVisual C++コード分析を支えるSAL
Visual C++コード分析を支えるSAL
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
第2回勉強会スライド
第2回勉強会スライド第2回勉強会スライド
第2回勉強会スライド
 
Start!! Ruby
Start!! RubyStart!! Ruby
Start!! Ruby
 
C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料C++勉強会in広島プレゼン資料
C++勉強会in広島プレゼン資料
 
C++の復習
C++の復習C++の復習
C++の復習
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめよう
 
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践
コンパイルターゲット言語としてのWebAssembly、そしてLINEでの実践
 
SEH on mingw32
SEH on mingw32SEH on mingw32
SEH on mingw32
 
Processing
ProcessingProcessing
Processing
 

More from digitalghost

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

More from digitalghost (7)

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

君はまだ,本当のプリプロセスを知らない