原文及評論見: 《混沌 In C++::是類型?還是函數調用?》http://blog.csdn.net/Jinhao/archive/2004/06/29/29021.aspx
看了原文的評論,發現有不少人誤解“函數聲明怎麼能當形參”。一開始,我也是一頭霧水,但後來總算是理解了,就在這裏稍微總結一下,也算是給自已提個醒吧。
作者的代碼我在 VC++.NET2003編譯過。就目前來說,微軟正式發佈的C++編譯器中,VC++.NET2003是最貼近C++標準的。也正因爲如此,VC++.NET2003在編譯VC++.NET2002和VC++6的時候,千萬不要忽略其警告,因爲這些警告往往是在指出VC++.NET2003與以前版本的不同(甚至是不兼容)之處,如果簡單的忽略,代碼的行爲就可能不是你想要的。由於不是準備討論這個問題,所以只給一個常見的例子:
bool bIsOk = nFlags & 0x02 == 0x02;
//warning C4554: “&” : 檢查運算符優先級可能存在的錯誤;使用圓括號闡明優先級
在編譯時,你應該注意到這個“警告”(我認爲這是一個“錯誤”),並將代碼改爲:
bool bIsOk = (nFlags & 0x02) == 0x02;
- A a( A()) 到底是什麼?
目前存在兩種說法:
- 函數聲明
- 變量聲明
支持 “(2) 變量聲明” 這個觀點的人認爲,A()是調用“默認構造函數”構造一個A類型的臨時變量,然後再調用A的“拷貝構造函數”構造一個A類型的變量a。
讓我們先看看下面的代碼表示什麼:
A a();
這是變量聲明嗎?不是的,用默認構造函數聲明一個變量應該寫作:A a;;它應該是函數聲明:該函數名稱爲a,沒有參數,返回值爲A類型。
我們再看看 A() 是什麼?實際上,在不同場合,A() 有不同的意義:
- 單獨使用: A();
表示:struct A __cdecl(void),這是一個匿名的函數聲明。 - 函數聲明中:void func(A());
表示:void __cdecl func(struct A (__cdecl*)(void)) ,很顯然,這裏A()就變成了一個函數指針聲明:struct A (__cdecl*)(void)。 - 在表達式中:?for_each(arr, arr+3, A());
在這裏,A() 才能當作一個表達式,很顯然,唯有“默認構造函數”才能符合該用途。
現在再來解決 A a( A()) 是什麼東西?在這裏,當同時可以解釋成函數聲明和變量聲明的場合,函數聲明優先。
A a (A(), 3) ,就只能解釋成變量聲明(調用一般構造函數)。
A a = A(),也只能解釋成變量聲明(調用拷貝構造函數)。
- 這篇文章的意義在哪裏?
有一部份人認爲這篇文章沒有意義,甚至無聊,更甚者認爲是在混淆視聽。理由是,寫程序者要有好的編碼風格,比如:
- A a (A()) 如果是變量聲明,就應該寫成: A a = A()。
- A a (A()) 如果是函數聲明,就應該寫成: A a(A (*) ())。
這說法沒錯,而且好的風格極其重要。
但是,許多人卻常常犯下類似的錯誤,並不是因爲編碼風格不好,而恰恰是對該文章要表達的內容不瞭解造成的。一個最常見的錯誤如下:
A a()
本意可能是想聲明一個變量,結果卻變成函數聲明。就是因爲習慣性的加上了括號造成的。而如果沒有意識到這是一個函數聲明的話,可能就不太清楚到底錯在哪裏。