2015-06-29 96 views
5

我正在努力理解將參考函數作爲通用參考傳遞給函數時會發生什麼(正在推導哪種類型)。讓我們假設我們有一個函數foo接受一個PARAM作爲通用參考:將參考函數作爲通用參考傳遞

template<typename T> 
void foo(T&& param) 
{ 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
} 

然後讓我們做到以下幾點:

void(&f)(int) = someFunction; 
foo(f); 

結果將是:

void foo(T&&) [with T = void (&)int]

這是完全可以理解的:我們將lvalue傳遞給函數foo,所以推導的類型是void(&)int,並且參數的類型將爲「void(& & &)int」,其參考摺疊規則變爲無效(&)int。參數將只是一個函數的左值引用。

但是,當我做到以下幾點:

void(&f)(int) = someFunction; 
foo(std::move(f)); 

foo將打印:

void foo(T&&) [with T = void (&)int]

這也正是像以前一樣!這裏發生了什麼?爲什麼結果與傳遞左值相同?我期望,因爲我們傳遞右值到foo,所推導的類型應該是T = void(int),並且參數應該變爲void(int323)。對於所有其他「常規」類型(如類,基本類型等),這總是會發生。爲什麼在處理函數引用時它有所不同?

+0

Nah。 'param'有一個名字,根據定義它是一個左值。 –

+3

@KerrekSB抱歉,這是錯誤的 - http:// stackoverflow。com/questions/7016777/what-is-rvalue-reference-to-function-type –

+0

@rubix_addict:我的不好,謝謝!刪除。我是在聲明之後,這是答案的一部分,但我沒有把它說清楚。 –

回答

6

A std::move是一個光榮的static_cast右值引用類型。該標準表示,對函數類型的右值引用依然會產生左值。每[expr.static.cast]/P1:

表達static_cast<T>(v)的結果是將所述表達v鍵入T的結果。 如果T是一個左值引用類型或對函數類型的右值引用,則結果爲左值;

關於std::move()函數調用,該函數返回一個右值參考指定轉換的結果的值的類別,我們也可以從[expr.call]/P10看到的函數調用是一個左值如果返回類型是一個rvalue參考函數類型:

函數調用是一個左值如果結果類型是左值引用類型或一個rvalue參考函數類型,一個x值如果結果的類型是對象類型的右值引用,以及其他值rwise。

+0

非常好的答案。直觀的意義是,對函數類型的引用會被區別對待;函數沒有狀態,因此不能移動,並且對函數的引用永遠不會改變函數。有效引用函數類型總是表現爲const&。雖然它仍然讓我想知道爲什麼有必要明確說明這些轉換髮生。在沒有這個規則的情況下,可以編造出什麼奇怪的,無意義的代碼示例? –

+0

啊,真好!當有多種方式來獲得什麼是函數xvalue時,看起來有點複雜,對於每種方式來說,它實際上都會產生一個函數左值,但實際上卻是這樣。 :) – hvd