24
C++ TIPS 3 カカカカカカカ Boost. 勉勉勉 #8 勉勉 ( 2012-02-11 )

C++ tips 3 カンマ演算子編

  • Upload
    -

  • View
    3.360

  • Download
    3

Embed Size (px)

DESCRIPTION

主に cppll ML でご紹介してきた tips をC++の仕様をより掘り下げた形でまとめ直してみました。 今回はカンマ演算子にフォーカスした内容です。

Citation preview

Page 1: C++ tips 3 カンマ演算子編

C++ TIPS 3 カンマ演算子編Boost. 勉強会 #8 大阪 ( 2012-02-11 )

Page 2: C++ tips 3 カンマ演算子編

概要 主に cppll ML でご紹介してきた tips

を C++ の仕様をより掘り下げた形でまとめ直してみました。

今回はカンマ演算子にフォーカスした内容です。

C++ Tips Boost. 勉強会 #8 大阪 2

Page 3: C++ tips 3 カンマ演算子編

カンマ演算子C++ Tips

Page 4: C++ tips 3 カンマ演算子編

カンマ演算子ってなに? セミコロン ( ; ) が文の区切りとして使える

ように、カンマ ( , ) が文節として使えます。 日本語文章で例えると「;」が「 。 」に対応す

るのに対して「,」は「、」に対応しています。 この用法で使われるカンマはカンマ演算子

と呼ばれます。

C++ Tips Boost. 勉強会 #8 大阪 4

Page 5: C++ tips 3 カンマ演算子編

カンマ演算子ってなに? 関数呼び出しのカンマや初期化ブロック

内のカンマ区切りはカンマ演算子ではありません。

関数呼び出しのカンマ区切りと違って評価順は左側の項目が先と決まってます。

カンマ演算子はもっとも優先順位の低い演算子となります。

C++ Tips Boost. 勉強会 #8 大阪 5

Page 6: C++ tips 3 カンマ演算子編

カンマ演算子の動き

C++ Tips Boost. 勉強会 #8 大阪 6

int a() { puts("a"); return 1; }int b() { puts("b"); return 2; }int c() { puts("c"); return 4; }void func() { int x = (a(),b(),c()); printf("%d\n",x);}

■ 実行結果abc4

左から順に評価され最も右側の値が式の評価値となります。( オーバーロードされていない場合 )

Page 7: C++ tips 3 カンマ演算子編

余談というか落とし穴

C++ Tips Boost. 勉強会 #8 大阪 7

int x = (a(),b(),c());… のつもりで…int x = a(),b(),c();… と書くとカンマ演算子ではなく、宣言のカンマ区切りだとコンパイラに解釈され…int x = a(); // a() を実行して x に初期値にする。int b(); // 戻り型が int の関数 b() の宣言。int c(); // 戻り型が int の関数 c() の宣言。… の意味になってしまいます。

Page 8: C++ tips 3 カンマ演算子編

使用例: if

C++ Tips Boost. 勉強会 #8 大阪 8

if (a(),b(),c()) // c() 結果で分岐{ ... }elseif (d(),e(),f()) // f() 結果で分岐{ ... }elseif (g(),h(),i()) // i() 結果で分岐{ ... }else{ ... }

Page 9: C++ tips 3 カンマ演算子編

使用例: if

C++ Tips Boost. 勉強会 #8 大阪 9

if (x=a(),b(x),c()) // c() の結果で分岐{ ... }elseif (d(),e=x+i,f(e)) // f(e) の結果で分岐{ ... }elseif (g(),i=h(),i++) // i++ の結果で分岐{ ... }else{ ... }

Page 10: C++ tips 3 カンマ演算子編

使用例: switch

C++ Tips Boost. 勉強会 #8 大阪 10

if (a(),b(),c()) // c() の結果で分岐{ ... }elseswitch(d(),e(),f()) // f() の結果で分岐{case 0: ...default: ...}

Page 11: C++ tips 3 カンマ演算子編

使用例: while,do/while

C++ Tips Boost. 勉強会 #8 大阪 11

while(a(),b(),c()) // c() の結果で分岐{ ... }

do{ ... }while(d(),e(),f()); // f() の結果で分岐

Page 12: C++ tips 3 カンマ演算子編

使用例: for

C++ Tips Boost. 勉強会 #8 大阪 12

for(int i=0,j=0; a(i),b(j); c(&i),d(&j)){ ... } // b() の結果で分岐

※ 最初のカンマはカンマ演算子ではなく宣言のカンマ区切りとなります。

Page 13: C++ tips 3 カンマ演算子編

使用例:引数

C++ Tips Boost. 勉強会 #8 大阪 13

x((a(),b(),c()), (d(),e(),f()), (g(),h(),i()));

この場合、( )各グループ内では… a()→b()→c()、d()→e()→f()、 g()→h()→i() …の順で実行されますが、abc、def、ghiの各グループの実行される順番は処理系依存となる為、処理系によって abc→def→ghi だったり ghi→def→abc だったりします。 この順番は通常、関数の引数がどのような順番でスタックに積

まれるか依存します。

Page 14: C++ tips 3 カンマ演算子編

使用例: || と && 組み合わせて

C++ Tips Boost. 勉強会 #8 大阪 14

( (a(),b(),c()) || (d(),e(),f()) // c() が false の場合に実行) && (g(),h(),i()); // c()||f() が true の場合に実行

Page 15: C++ tips 3 カンマ演算子編

\ ヒャッハー! /

C++ Tips Boost. 勉強会 #8 大阪 15

int x = ( (++i,y=a(),b(y),c(i)) || (++i,y=d(),e(i),z=f(y,i) ? g(): h())) && ( (++i,y=a(),b(y),c(i)) || (++i,y=d(),e(i),y<=f(y,i)));

Page 16: C++ tips 3 カンマ演算子編

スタック領域の圧迫について

C++ Tips Boost. 勉強会 #8 大阪 16

カンマ演算子を多用して頑張ると一文で結構な量のコードが書けてしまうのですが、あんまり調子扱いてると一時変数の量が膨大になってスタック領域を圧迫し状況によってはスタックオーバーフローを招くことにもなりかねない観点からもほどほどに。

Page 17: C++ tips 3 カンマ演算子編

インラインロック カンマ演算子は左側の項目から評価され

るという事と、一時オブジェクトの寿命は文の終了時までという事を利用し、コンストラクタでロック、デスクトラクタでアンロックを行うクラスを用意しておけばインラインでの手軽なロック / アンロックができます。

C++ Tips Boost. 勉強会 #8 大阪 17

Page 18: C++ tips 3 カンマ演算子編

インラインロック

C++ Tips Boost. 勉強会 #8 大阪 18

auto_lock(),func();

■ 実行される順番1.auto_lock::auto_lock()2.func()3.auto_lock::~auto_lock()

Page 19: C++ tips 3 カンマ演算子編

インラインロック

C++ Tips Boost. 勉強会 #8 大阪 19

if (auto_lock(),func()) { func2(); }

■ 実行される順番1.auto_lock::auto_lock()2.func()3.auto_lock::~auto_lock()4.func2() →func() が true の場合にのみ実行される。

Page 20: C++ tips 3 カンマ演算子編

オーバーロード カンマ演算子はオーバーロードしてその

挙動をユーザー定義することも可能です。

C++ Tips Boost. 勉強会 #8 大阪 20

inline hoge operator,(hoge a, hoge b) { return a; // b の代わりに a を返す。}

Page 21: C++ tips 3 カンマ演算子編

初期化リスト代わり カンマ演算子のオーバーロードを頑張れ

ば C++11 の初期化リストの代わりになるような類いのもの実装可能です。

C++ Tips Boost. 勉強会 #8 大阪 21

Page 22: C++ tips 3 カンマ演算子編

オーバーロード 注意点 その他演算子オーバーロード違い、カンマ演算子のオーバー

ロードは見た目からはオーバーロードされていることが予測し辛い為、容易くメンテナンス性の悪いコードになってしまいますので、乱用は厳禁です。

C++03 時代であればまだ初期化リスト代わりの用途としてカンマ演算子のオーバーロードが有効なシーンもあったものの C++11 では素直に初期化リストを使ったほうがいいです。

さらに C++03 でも昔のコンパイラではカンマ演算子のオーバーロードまわりはコンパイラの挙動がバギーで使い物にならなかったり・・・

C++ Tips Boost. 勉強会 #8 大阪 22

Page 23: C++ tips 3 カンマ演算子編

質疑応答C++ Tips

Page 24: C++ tips 3 カンマ演算子編

ご清聴ありがとうございました。C++ Tips