2012-01-17 106 views
3

我很好奇爲什麼在鏈接靜態函數和成員函數之間的參數計算順序的差別。從this question的答案我可以看出它沒有說明在這樣的鏈接函數調用之間參數評估順序是什麼。舉個例子下面的代碼片斷:評估順序調用

#include <iostream> 
class test { 
public: 
    static test& chain_s(test& t, int i) { 
     std::cout << i << " "; 
     return t; 
    } 

    test& chain(test& t, int i) { 
     std::cout << i << " "; 
     return *this; 
    } 
}; 

int main(int, char**) { 
    int x = 2; 
    test t; 
    t.chain(t,++x).chain(t,++x).chain(t,++x); 
    x = 2; std::cout << std::endl; 
    t.chain_s(t,++x).chain_s(t,++x).chain_s(t,++x); 

    return 0; 
} 

在GCC 4.6.2和CL 15.00.30729.01(MSVC 9)的情況下所得到的輸出是對我

5 5 5 
3 4 5 

然而,我想知道是否在說明書中有任何理由,或者如果以其他方式知道爲什麼靜態函數是從左到右(使用它們的參數)進行求值,並且對於非靜態函數,所有參數都是第一個(從我的右向左在其他測試中見過)。

我之所以這麼問,這是因爲我試圖讓用C類似的行爲(使用結構和函數指針)時,第一次注意到這種行爲差異和失敗。我強烈懷疑這是在GCC和MSVC中針對成員函數實現的一些優化,但是我希望這裏有人能夠在這方面多一點點亮。

編輯:
我忘了提及的信息的一個關鍵位,它令我奇怪:GCC將只警告上鍊接的非靜態函數不確定的行爲,而不是靜態函數:

a.cpp: In function 'int main(int, char**)': 
a.cpp:18:45: warning: operation on 'x' may be undefined [-Wsequence-point] 

GCC沒有義務提供這樣的警告,因此可能會錯過第二個表達式,但是這是使我相信一些有趣的事情是怎麼回事。

+0

肯定這樣的事情應該是不相關的任何代碼,你寫... – 2012-01-17 19:38:00

+0

是的,但我想知道爲什麼一些代碼是錯誤的,但不會產生警告,當在類似的情況下,它會。 – harrbharry 2012-01-17 19:48:57

回答

2

沒有理由。就像你說的那樣,這個順序並沒有被語言所指定。

使用從右到左的順序

原因之一是,與可變數量的參數,如printf功能,然後將總是具有在頂部的第一參數。否則它並不重要。

+0

我忘了問爲什麼編譯器輸出的消息不同,有關於此的任何想法?這也是導致整個問題的原因。 – harrbharry 2012-01-17 19:50:51

+0

即使使用'printf',編譯器也可以按任意順序評估參數,甚至交織評估結果。在基於堆棧的機器上,第一個參數可能是最後一個參數,但編譯器也很有可能在堆棧中保留必要的空間,並使用sp相對尋址存儲它所屬的每個參數。以任何順序發佈都很方便。 – 2012-01-17 20:09:50

2

你的代碼是未定義行爲,但我想你知道。另外,根據優化標誌,您可以輕鬆看到差異。但 在這種情況下,其中一個可能的原因是,非靜態函數需要 三個參數,其中包括前一個調用的結果,其中作爲 的靜態函數只需要兩個,並且前一個 調用的結果被忽略。