読む人いるのかなあなんて思いつつ。
BOOL と bool と 0 と 1
歴史的事情でしばしば typedef int BOOL なわけだけど、これを比較したいことがある。具体的に書くと:
BOOL foo(); BOOL bar();
とかいう関数があって。
返戻値は大抵「真の場合はゼロ以外、偽の場合はゼロを返す」という仕様になっている。そんなわけで、素直に比較すると
if ( foo() == bar() ){ /*foo() が 2 で bar() が 3 だとここに来ない*/ }
ということになる。いやいやBOOLなんだから0か1を返せよと思わなくはないが、関数の仕様として「真の場合は1を返す」となっていないんだから仕方ない。
じゃあどうするのかといことで
if ( !foo() == !bar() ){ /*foo() と bar() が論理値として同じなら必ずここに来る*/ }
とまあこんなことをしたりする。
さらに。int を返す関数 baz() か何かがあって、foo() と baz()<3 を比較したいとする。
先ほどと同じ手を使うと
if ( !bar() == !(baz()<3) ){ /*bar() と baz()<3 が論理値として同じなら必ずここに来る*/ }
これでうまくいく。もちろん
if ( !bar() != (baz()<3) ){ /*bar() と baz()<3 が論理値として同じなら必ずここに来る*/ }
これでもいい。しかし、特にこのバージョンは何がしたいのかわかりにくいように思う。私は ! 記号をもう一つ前に移動した
if ( !!bar() == (baz()<3) ){ /*bar() と baz()<3 が論理値として同じなら必ずここに来る*/ }
がわかりやすいように感じている。この「!!」は、真偽値としての値を維持しつつ bool に変換するという便利なイディオムで、昔 dankogai も書いていたような気がする。
素直に cast しても正しく動くように見える
if ( static_cast<bool>( bar() ) == (baz()<3) ){ /*bar() と baz()<3 が論理値として同じなら必ずここに来るんじゃないかな*/ }
が、なんとなくキャストには罪悪感が伴うので書きたくないし、2がtrueになるのが処理系依存なのか仕様なのか寡聞にして知らないのであんまり好きじゃない。まあ素直に書くと
if ( (FALSE != bar() ) == (baz()<3) ){ /*bar() と baz()<3 が論理値として同じなら必ずここに来るんじゃないかな*/ }
なんだろうけど、やっぱり !! が好き。
このイディオムに慣れてしまうと、ついつい
if ( !!foo() == !!bar() ){ /*foo() と bar() が論理値として同じなら必ずここに来る*/ }
と書きたくなってしまうが(実際何度か書いた)、これは書きすぎ。
今日の写真は、本文とは無関係な針穴写真。長時間露光のエスカレータ。
というわけで、今年の更新はこれが最後の予定。
良いお年を。