2015-04-19 51 views
2

我已告知here這兩個簽名之間的差異不是左值/右值相關的。這兩個函數簽名有什麼區別?

#include <iostream> 

template <typename RET_TYPE, typename...ARGs> 
void takeFunction(RET_TYPE(*&& /*function*/)(ARGs...)) 
{ 
    std::cout << "RValue function" << std::endl; 
} 

template <typename RET_TYPE, typename...ARGs> 
void takeFunction(RET_TYPE(*& /*function*/)(ARGs...)) 
{ 
    std::cout << "LValue function" << std::endl; 
} 

void function() 
{ 
} 

int main() 
{ 
    void(*f)() = function; 
    takeFunction(&function); 
    takeFunction(f); 
    return 0; 
} 

但是,如果不是這樣,那麼它在匹配上有什麼區別?

+0

在我看來,第一個是對函數的引用,第二個是對函數指針的引用。 – Galik

回答

3

函數和指向函數的指針有一個區別。

功能是不同的,因爲它們不是對象(在這個詞的標準意義上)。 函數 rvalues(涉及非靜態成員函數的某些奇怪情況之外)沒有這種東西。實際上,函數的右值引用是左值是否命名。

指向函數的指針就是指針,它們是對象。你可以有指向函數類型的指針,或指向函數類型的指針的xvalue,或指向函數類型的指針的左值。 &function創建一個指向函數的prvalue指針;在void (*f)() = function;中,應用函數到指針的轉換來將函數左值function轉換爲函數的前值指針,其中f被初始化。

現在考慮這一組重載:

template <typename RET_TYPE, typename...ARGs> 
void takeFunctionRef(RET_TYPE(&& /*function*/)(ARGs...)) // #1 
{ 
    std::cout << "RValue function" << std::endl; 
} 

template <typename RET_TYPE, typename...ARGs> 
void takeFunctionRef(RET_TYPE(& /*function*/)(ARGs...)) // #2 
{ 
    std::cout << "LValue function" << std::endl; 
} 

takeFunctionRef(function); // calls #2 
takeFunctionRef(std::move(function)); // still calls #2! 

重載#2被選擇,因爲[over.ics.rank]特殊決勝局的,子彈3.1.4有利於左值參照結合到功能左值將右值引用綁定到函數左值。但是兩者都會成功綁定(即,如果刪除#2,則會在兩種情況下都會看到#1)。

+0

因此,在您指定的一組重載中,如果兩者都存在(#2),則只有一個可用,但是如果聲明沒有另一個,則可以使用其中一個?我知道這並不是真的含糊不清,但至少它不應該產生一個永遠不會被調用的警告嗎? – Adrian

+0

@Adrian是的,但我懷疑這種情況在真正的代碼中並不真正發生,這足以證明實施警告的成本。 –

+1

「功能rvalues沒有這樣的事情。」 - 好吧,如果我們嚴格按照標準進行談話,我認爲有一些函數類型的價值,但是它們的使用是非常小心的,以至於在實際上它們的價值類別實際上很重要。考慮'struct A {void f(){}}; a';表達式'A :: f'和'a.f'分別是根據[5.1.1p9]和[5.2.5p4.3.2]的函數類型的前值。 – bogdan

1

RET_TYPE(*&& /*function*/)(ARGs...)是對函數指針的右值引用。

RET_TYPE(*& /*function*/)(ARGs...)是對函數指針的左值引用。

&function創建一個右值臨時函數指針。所以takeFunction(&function);解析爲RET_TYPE(*&& /*function*/)(ARGs...)

void(*f)() = function;定義了一個名爲左值的函數指針。所以takeFunction(f);解析爲RET_TYPE(*& /*function*/)(ARGs...)

除了這個左值/右值的差異,這兩個函數沒有其他區別。

+0

如果我有第三個'RET_TYPE(&/ *函數* /)(ARGs ...)',那將是一個函數的引用,這是一個左值? – Adrian

+0

正確。此外,我似乎還記得所有右函數的函數實際上都被解析爲左值引用。換句話說,你不可能真的有一個右值引用的功能。會找到一些標準的參考。 – Lingxi