2010-10-24 187 views
15

如果來自C++ FAQ Lite的以下內容爲真:「函數名稱衰減爲指向函數的指針」(因爲數組名稱衰減爲指向其第一個元素的指針);爲什麼我們必須包括&符號?成員函數指針

typedef int (Fred::*FredMemFn)(char x, float y); 
FredMemFn p = &Fred::f; 

而且不只是:

typedef int (Fred::*FredMemFn)(char x, float y); 
FredMemFn p = Fred::f; 

在第二種情況下,弗雷德:: f是一個函數,可以衰減到一個指向功能。

我希望這個問題不是那麼愚蠢。

+0

我的猜測!這將是不明確的,因爲'Fred :: f'也可以表示類中的靜態變量。 – AraK 2010-10-24 14:45:00

+1

+1非愚蠢問題 – fredoverflow 2010-10-24 14:58:20

+0

@FredOverflow:thanks;) – 2010-10-24 18:27:00

回答

16

原來的答覆:

因爲一個成員函數不是一個函數和一個成員函數指針不是一個函數指針。因此衰減規則不適用。

另外,在C++中有函數類型,但不是成員函數類型。所以你可以在需要指向函數的地方使用函數,但是你不能使用成員函數,因爲沒有這種東西,只有指向成員函數的指針。在你的例子中f是一個函數。另一方面,Fred :: f是......好吧,沒什麼。

此外,我會爭辯說「一個函數的名稱會衰減......」。不,名稱不能做任何事情,函數類型的左值可以隱式轉換爲函數指針,並且就重載分辨率而言,這是標識轉換

編輯以澄清我的答案:

C++中的每個表達式都有一個類型和值。一種類型的值偶爾可以轉換爲另一種類型的值。這些轉換的排名使得一次轉換更好,另一次轉換主要用於功能重載分辨率。

其中一種轉換類型稱爲左值到右值轉換。當左值出現在需要右值的上下文中時,會發生此轉換。通常這種轉換不執行任何操作,例如:

int i = 4, j = 5; 
i = j; 

在第二行j是一個左值,但這裏需要一個右值,所以j被轉換爲右值。但這不是一個可觀察的轉換,是嗎?但有些情況下可以觀察左值到右值的轉換。也就是說,N t個的陣列的左值可以被轉換爲T*其值類型的右值是數組的第一元素的地址型「與簽名S函數」的左值右值類型的,其值是該函數的地址

這意味着,當我們分配一個函數的指針到函數的函數左值被隱式轉換到它的地址「指向與簽名S功能」。

void f() {} 
void (*p)() = f; //f is converted to rvalue 

f是一個表達式並且有一個類型。F公司類型是void()

有作爲member-function 沒有這樣的類型在C++有指針到部件的功能,但不成員函數本身。我當然在談論非靜態功能。靜態功能的工作方式與普通功能相同,也就是說,您不必編寫&X::f,而是可以編寫X::f 爲什麼?因爲X :: f有一個類型函數並且發生了上述轉換。但是,如果f是非靜態的,則X :: f是類型的......什麼?哦,是的,它沒有類型,因此也不是一個表達式,因此沒有價值,因此這個價值不能轉化爲任何東西。從標準

引用:5.3.1第3 當使用顯式&和它的操作數是一個合格的-ID不包含在括號中僅形成一個指向部件。 [注意:也就是說,表達式&(qualified-id),其中qualified-id括在圓括號中,不會形成「指向成員的指針」類型的表達式。既沒有隱式轉換,也沒有qualified-id從非靜態成員函數的qualified-id到類型「指向成員函數的指針」,正如從函數類型的左值到類型「指向函數的指針」(4.3)一樣。 &也不是一個指向成員的指針,即使在不合格id的類的範圍內也是如此。 ]

希望這個更清晰...

+0

「在C++中有函數類型,但不是成員函數類型。」 - >你究竟是什麼意思?當然'FredMemFn'有一個類型? – fredoverflow 2010-10-24 14:57:55

+0

@FredOverflow:是的,FredMemFn有一個類型,該類型是「指向成員的指針,包括哪個類和什麼簽名」。 C++中的每個表達式都有一個類型。例如,如果f是獨立函數void f(),則表達式(f)的類型是void(),它是函數類型。另一方面,表達式Fred :: f不是一個表達式,因爲它沒有類型。但是,&Fred :: f是指向成員的類型表達式,等等等等......這就是我的意思 – 2010-10-24 15:30:53

+0

不&&操作符是否需要表達式作爲其操作數? – fredoverflow 2010-10-24 15:44:53