2011-08-18 123 views
8

對不起,如果這之前已被問過,但我無法找到它。通過值(?)傳遞函數而不是函數指針?

所以即時嘗試教育自己關於模板和新的C++ 11功能(主要是lambda,我總是喜歡用其他語言)。

但在我的測試中,我來到事我不知道它的工作,和我想要了解它是如何工作的,但不能圖出來..

下面的代碼:

template <class Func> 
void Test(Func callback) { 
    callback(3); 
} 

void Callback(int i) { 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) { 
    Test(&Callback); // this I was expecting to work, compiler will see its a pointer to a function 
    Test(Callback); // this also works, but how?! 
    return 0; 
} 

如果我理解模板是如何工作的,那麼基本上它們是編譯器知道要構建什麼的方案,所以我期待着第一次調用Test(&Callback);,因爲編譯器會看到模板接收到函數地址並將假設參數應該成爲一個指針。

但是第二個電話是什麼?假設它是什麼模板?功能的副本(如果這甚至有意義)?

回答

14

函數可隱式轉換爲指向自身的指針;這種轉換髮生在任何地方。 Test(Callback)Test(&Callback)完全相同。沒有區別。在這兩種情況下,推導出Funcvoid(*)(int)

函數指針很奇怪。您可以在"Why do all these crazy function pointer definitions all work?"

+0

感謝您的回答。所以如果我沒有使用模板和聲明測試如:無效測試(無效(*回調)(INT)){...}這兩個調用也將工作。這是很好的知道。虐待確定我讀了你鏈接的線程。 – sap

3

中找到更多關於它們的函數在C++中,函數不是一類對象,這意味着「函數作爲值」在其中沒有任何意義。這就是爲什麼函數名一直可以隱式轉換爲它的指針。

+0

也許值得注意的是,有些語言中的「功能按價值」確實有意義。 – hamstergene

2

函數可隱式轉換爲函數指針。如果事實上沒有辦法獲得函數值或引用。雖然奇怪你可以創建一個函數值類型,但你不能指定任何東西。

Here is code snippit演示了lambda和各種回調函數如何與模板作出反應。

+0

感謝您的代碼,真的很有幫助。 – sap

+0

這是錯誤的。函數引用很好。如果'Test'被聲明爲'void Test(Func&callback)',那麼'Func'將被推斷爲'void(int)',並且'Callback'將被引用傳遞而不被轉換爲指針, Test'。 –

+0

哇!我認爲應該支持引用以及指針是有道理的,因爲它們非常相似。是否可以聲明一個函數值,併爲它分配一些東西? –

0

在C++ 11(以及boost和tr1)中,我們使用std :: function作爲模板類型來存儲函子,lambdas和函數。所以你可以肯定有一個保持函數值在std :: function類型的變量中的概念。該變量也可以是「空的」,這意味着沒有函數(參考)存儲在其中。然後它不能被調用。

原來的問題與C相反,C++允許函數引用。另外,出於C兼容性的原因,函數名可以退化爲函數指針。但是因爲過載,C++中的事情比C更「有趣」。