最近看到有人出了一個考初學者的問題,於是我改了一個複雜化的版本,應該蠻適合拿來鑑別初學者的程度。假設使用的語言為 C++,下面這個 expression 有幾種可能性?

   (f(a) && f(b))

任何一個有把教科書第一章念完的人差不多都會回答,執行順序類似於:

   if (f(a) == true) {
       if (f(b) == true) {
           return true;
       }
   }
   return false;

如果再仔細追問,就只有這樣嗎?有沒有別種可能?多讀幾章的人會想到 f 可能是 macro,而 macro 可能被代換成任何文字,因此執行順序會和表面上看起來很不一樣。

排除掉 macro,先假設 f 是個函數,這時 f 的回傳型態就非常重要。假如 f 回傳的型態相容於bool,那麼順序大概會同上面示意的流程。不過要是 f 回傳其他型態,那就要進一步了解這個型態有沒有定義 operator&&。

內建的 && 很嚴格的遵守 C++ 的短路運算精神,但自行定義的 operator&& 則是不折不扣的函數,亦即所有的參數都會在進入函數前演算出來,但是參數演算順序由編譯器決定,於是就和上面示意的順序不同了。

f也有可能不是函數,而是其他定義了operator() 的物件,道理和函數相同,不過這個情況下 f 有可能在每次呼叫的時候都改變自己內部狀態。

另一個可能,f 是類別名稱,於是 f(a) 實際上會建立一個臨時物件。同樣的,這個 f 究竟定義了 operator&& 或 operator bool 會對執行流程造成不同的效果。

事情還沒完,a 和 b 各自有可能是 macro,於是也可能展開成任何東西。

以上只是與流程相關的部分,至於副作用要講起來就沒完沒了了。

我的原則是讓 expression 的語意和你第一印象一樣,儘管任何對 C++ 有基本熟練度的人都可以在幾秒鐘之內想出上面這一大串,但是為了這種事情而中斷更重要的思路完全不值得。


註:原問題是 (b=f(a)) && (a=f(b))。誰寫出這麼爛的程式?這不就是我嗎?

假如f是函數而且不考慮operator&&,這題順序其實很明確,因為在呼叫f還有執行&&運算時各自有定義明確sequence point。但副作用這種東西一言難盡。

novus 發表在 痞客邦 PIXNET 留言(0) 人氣()