2011-07-14 51 views
8

我懷疑下面的函數鏈會根據C++標準(假設C++ 0x)導致未指定的序列。只需要確認,如果有人可以提供解釋,我會很感激。這段代碼是否定義良好?

#include <iostream> 

struct TFoo 
{ 
    TFoo(int) 
    { 
     std::cout<<"TFoo"<<std::endl; 
    }; 
    TFoo foobar1(int) 
    { 
     std::cout<<"foobar1"<<std::endl; 
     return *this; 
    }; 
    TFoo foobar2(int) 
    { 
     std::cout<<"foobar2"<<std::endl; 
     return *this; 
    }; 
    static int bar1() 
    { 
     std::cout<<"bar1"<<std::endl; 
     return 0; 
    }; 
    static int bar2() 
    { 
     std::cout<<"bar2"<<std::endl; 
     return 0; 
    }; 
    static int bar3() 
    { 
     std::cout<<"bar3"<<std::endl; 
     return 0; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    // is the sequence well defined for bar1, bar2 and bar3? 
    TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3()); 
} 

*編輯:刪除__fastcall符的功能(不要求/有關的問題)。

+1

我不是故意要碰到nitpicky,但從技術上講,'__fastcall'不是C++規範的一部分,所以我不認爲規範有什麼可說的。你有什麼理由將它包含在這裏嗎?或者是關於'__fastcall'與序列點的交互的具體問題? – templatetypedef

回答

8

未指定評估順序。草案C++0x spec的相關章節是1.9,第14和15:

14與全表達關聯的每個值計算和副作用與下一相關聯的每個值計算和副作用之前測序完整表達進行評估。

15除非另有說明,個別運算符和個別表達式的操作數的評估是不確定的。

這裏的相關充分表達是:

TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3()); 

所以它的子表達式的評價是未測序(除非有某個地方注意的一個例外,我錯過了)。

我很確定早期的標準包括語言具有相同的效果,但在「序列點」方面。

[編輯]

第15段還表示:

當調用一個函數(函數是否是內聯)中,用任何參數表達相關的每一個值的計算和副作用,或者與指定被調用函數的後綴表達式在執行被調用函數主體中的每個表達式或語句之前被排序。 [注意:與不同參數表達式相關的值計算和副作用是不確定的。 - 注完]

A「後綴表達式指定調用的函數」有點像在foo().bar()foo().bar

這裏的「註釋」只是澄清了參數評估順序是而不是是「未指定順序」默認值的例外。通過推論,與「指定被調用函數的後綴表達式」相關聯的評估順序也不是。或者如果您願意,this參數的表達式的評估順序。 (如果有例外,這是指定它的自然地點,或者可能是關於函數調用的第5.2.2節,這兩個部分都沒有說明關於此示例的評估順序的任何內容,因此未指定。)

+0

'除了注意到的地方, - 這留下了相當多的思考... –

+0

@Zach:的確。但是,如果您打算依賴評估訂單,則需要查找設置訂單的特定規則。 C/C++一直很寬鬆地指出這一點,讓編譯器和CPU空間可以重新排列性能。 – Nemo

+1

IMO值得一提的是'foobar1'在'foobar2'之前被調用。所以順序是有限的(因爲'foobar1()'的結果需要在被用作'operator.'的操作數之前被評估,1.9p15),儘管大部分都沒有針對其他調用指定。 –

1

是的,函數參數的求值順序是未指定的。

對於我來說,在Linux上的gcc 4.5.2生產

bar3 
bar2 
bar1 
TFoo 
foobar1 
foobar2 

但鐺++在Linux和GCC 3.4.6在Solaris上產生

bar1 
TFoo 
bar2 
foobar1 
bar3 
foobar2 

要分析一個簡單的例子,TFoo(0).foobar1(TFoo::bar2());是呼叫到TFoo::foobar1,它有兩個參數:子表達式TFoo(0)(作爲隱藏參數this)的結果和子表達式Tfoo::bar2()的結果。對我來說,gcc首先執行bar2(),然後TFoo的構造函數,然後調用foobar1(),而鏗鏘++例如,首先執行TFoo的構造函數,然後bar2(),然後調用foobar1()

+0

我知道函數參數的求值順序沒有指定,但在這種情況下,對於每個鏈接函數(指定順序),它實際上是函數參數(單數)的eval順序。任何相關的標準說這是真正不明確的? –

+0

@Zaw Saw:成員函數也將'this'當作隱含的參數。 – Cubbi

+0

關心詳細說明?這是否意味着鏈接函數(foobar1和foobar2)的順序也未指定? –