2012-06-21 35 views
11

爲什麼的std ::在C++標準功能<> ::運算符()的定義是:C++ 11的std ::功能和完美轉發

R operator()(ArgTypes...) const; 

和不

R operator()(ArgTypes&&...) const; 

有人會認爲,要正確轉發參數,我們需要& &,然後在轉發呼叫時在函數體中使用std::forward<ArgTypes>...

我部分地重新實現的std ::功能來測試這一點,我發現,如果我用& &,我得到「無法綁定‘XXX’左值到‘XXX & &’」從G ++,當我嘗試後通過參數按值運算符()。我認爲我對右值/轉發概念有足夠的把握,但我仍然無法理解這一點。我錯過了什麼?

回答

13

完美轉發僅在函數本身(在此例中爲operator())被模板化並且推導出模板參數時才起作用。對於std::function,您可以從本身的模板參數中獲得operator()參數類型,這意味着它們將永遠不會從任何參數推演出來。

完美轉發背後的全部訣竅是模板參數扣減部分,它與參考摺疊一起是完美轉發。

我只是在這裏方便地鏈接到my other answer about std::forward,我在這裏解釋完美的轉發(和std::forward)是如何工作的。

請注意,std::functionoperator()不需要完美的轉發,因爲用戶自己決定參數應該是什麼。這也是你不能只將&&加到operator();以此爲例:

void foo(int){} 

int main(){ 
    // assume 'std::function' uses 'ArgTypes&&...' in 'operator()' 
    std::function<void(int)> f(foo); 
    // 'f's 'operator()' will be instantiated as 
    // 'void operator()(int&&)' 
    // which will only accept rvalues 
    int i = 5; 
    f(i); // error 
    f(5); // OK, '5' is an rvalue 
} 
+0

謝謝,現在一切都變得非常有意義。 – airman

+0

@Xeo,你的代碼編譯正確... http://ideone.com/7TyCB8 f(i)沒有錯誤,你能解釋「/ /錯誤」是什麼意思嗎,或者我正在使用編譯器錯誤。謝謝。 –

+0

@WillBradley:重讀'main'頂部的註釋:***假設***'std :: function :: operator()'的簽名實際上是'R(Args && ...)' - 這可以通過'function '產生'operator()'的'void(int &&)',現在只接受rvalues。 – Xeo