難度:
文前提醒:看這篇文章時須家長陪同並引導,以免走火入魔
先看看下面的代碼?
struct A
{
A(){}
};
template<typename T>
void func(T() )
{}
int main()
{
A a( A() ); //(1), OK
func( A() ); //(2), Wrong
a = 5; //(3), Wrong
}
(1)、 A a( A() ); 是什麼意思?
在這裏是用A()創建一個對象,然後初始化對象a嗎?這裏真正的語義是a是一個參數爲返回A對象的無參函數指針的函數,所以它的真面目應該是A a( A (*)() ),其中的A()是個函數類型,在實際作參數時會退化爲一個A(*)()指針 。而這句僅僅起到聲明函數的作用。重點就在於A()並不是創建對象,而是一個無參的、返回爲A的函數類型
(2)、 func( A() ); 爲什麼會出錯呢?
這裏雖然函數模板func的參數同樣也是一個函數類型,那爲什麼會出錯呢? 其實在這裏A()就不是一個函數類型了,而是創建一個匿名對象。那麼這個函數即成了 void func( A ),而原本的函數模板func 類型是void ( T (*)() ),很明顯參數類型不匹配。
(3)、 a = 5; 現在應該沒有任何疑問了
把int 傳遞給 A ()( A (*)() ),地球人都知道是錯的。
千萬別走火入魔!
是什麼導致了(1)和(2)中的A()表現出不同的語義呢?
答:在這裏的 A() 就具有二義性:它即可以解釋爲新創建的類 A 的一個臨時對象(在此過程中要調用 A 的構造函數),也可以解釋爲一種函數類型聲明:其返回值爲A類型的對象,函數參數爲空。如果是前種解釋,則 a 爲類 A 的一個對象;如果是後一種,則整句就是一個函數聲明:聲明瞭一個函數 a,其返回值類型爲 A,函數參數(省略了參數名。對於函數聲明這樣做是可以的)是上述的一個函數類型。到底是前一種還是後一種解釋取決於它所在的語義環境。
更多
struct A
{
A(int ){}
};
A a(A(1)); 在這裏A(1) 就不可能是“類型”了,因爲其中有個1,而A(1)就成了一個轉換函數調用形式,所以A(1)這裏是調用的A(int)。
非常感謝whyglinux,爲本文指出錯誤並作出修改。
//The End