忍者ブログ

どっかのゆとりのチラシの裏

plasma_effectのメモ帳的ブログのようなsomething

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

gccとVC++でプリプロセッサの挙動が違う問題

世の中にはいろいろC++のコンパイラが存在するがとりわけgccとclangとMSVCが使われてると思う(あくまで著者の主観です、あとMSVCがC++コンパイラかどうかは議論がわかれます)。闇の言語であるC++の機能の中でも特に闇であるプリプロセッサだが、これがgccとMSVCで挙動が違う。以下のコードを見てほしい。これをgccで展開すればこうなる
>
> xy
一方でMSVCで展開すれば以下のようになる(/P /EPオプション使用)
> cat main.i
>
>
>
>
>
> xB (y)
これはつまり展開の順番が違うということである。同一のプリプロセッサでもコンパイラによって挙動が違ってくる。これを知らずにコードを書くと死あるのみである。
ていうか普通に死にそうなのでやめてほしい。

ちなみにだがこれはAの定義をA(a) B(a)に、最後の行をCAT(x,A(y))にするとgccとMSVCで挙動が一致する調査の必要性を感じる。
PR

TMP

知り合いがTMPについて解説してたので我もTMPのテクニックの解説をするなり。
とりあえずサンプルコードはgistに置いといた。ここ

Template Meta Programming(略してTMP)とはC++の機能のtemplateを利用してほげほげするほげである。Wikipediaに「コンパイラがテンプレートを使って一時的ソースコードを生成し、それを他のソースコードと結合してコンパイルする方式である。」と書いてあるがわけがわからなかったら無視していい。templateでほげほげすることは確かである。

通常TMPといえば「値に関する操作」「型に関する操作」の2種類あるが値に関する操作はconstexprでことがすむので型に関する操作の話をしていく。型に関する操作とはいかにという話だが例えばサンプルコードのexam1.cpp。
これはtorio型が渡されたらその真ん中の型を取り出してtypedefするクラスである。要するにこんな感じで型で遊んでいくわけ。もちろんただ遊ぶのではなく有意義に遊ぶ。
TMPには様々なテクニックがあるがよく知られているテクニックを2つ紹介する。

1つ目はExpression Template。式をtemplateで表すテクニックである。
例えばサンプルコードのexam2.cpp。これが要素数1万とかになってくると普通にoperator+を実装したのでは一時オブジェクトでその分メモリを消費したりするのでよろしくない。
exam2.cppのようにoperator+の返り値をadd_vectorにすることでoperator[]が呼び出されるまで計算されないようにするのである。遅延評価をするという話だ。
上では数値計算に使ったがそれ以外にも使い道はある。例えばexam3.cpp。C++にはコンパイル時ラムダ式がコア言語でサポートされてないのでそれをライブラリで対応したりできる。まぁこれでコンパイル時ラムダ式を完全にサポートするのは割とめんどくさそうなので暇な人は頑張ってください。
上のコードでは演算子オーバーロードにADLを使っている。ここらへんの解説はめんどくさいので自分で検索して下さい。なんかADLは邪悪らしいとか地雷原がいっぱいとか聞いたことあるので地雷原回避する方法誰か教えてくださいお願いします。

2つ目はType Erasure。型の情報を必要最低限まで抹消するテクニックである。例えばexam4.cpp。この他にも自作のVTableのほげほげをほげする方法はあるらしいがそれは参考リンクを参照。
これはすなわち基底クラスのポインタに派生クラスのポインタを入れれることを利用する(ここでは派生クラスのunique_ptrは基底クラスのunique_ptrにキャストしている)
ほとんど説明することもないと思う。読めば分かるという感じ。

TMPはまだまだ奥が深い、他にも色々テクニックがあるので色々調べればいいと思う。


間違ってること言ってたら誰か教えて欲しいですはい。
あとgist無理矢理使おうとしてこんな感じになってしまった。

参考ページ(Cryolite先生のはてなダイアリー)
http://d.hatena.ne.jp/Cryolite/20040506
http://d.hatena.ne.jp/Cryolite/20051003

typedef-nameでのコンストラクタ

以下のコードについて考える。このコードは規格でill-formedらしい($12.1にThe class-name shall not be a typedef-name.とある)
とりあえずこれはclangやgccでは通らない。
一方でMSVC12.0(VS2013)では通った。相変わらずの規格無視っぷり。
これなにが問題かというと割と便利なので思わず使ってしまうところ。

カレンダー

03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

フリーエリア

最新CM

[02/12 kariya_mitsuru]
[10/14 どっかの京大生o]
[10/04 どっかのZ会生y]
[07/31 どっかのZ会生y]
[07/31 GNR]

プロフィール

HN:
plasma_effect
性別:
非公開

バーコード

ブログ内検索

最古記事

(06/08)
(06/18)
(06/21)

P R