2012-03-27 63 views
4
template <typename T> void f(T&) {} 
template <typename T> void f(T&&) {} 
int main() 
{ 
    int x; 
    f(x); //ambiguous 
} 

爲什麼這個調用不明確?第一個模板專業化是f <int>(int &),第二個是f <int&>(int &)。由於參數相同,根據偏序排列規則更加專門化的函數模板更好。然後根據標準14.8.2.4/9帶參考參數的重載功能模板

如果,對於給定類型,扣除在兩個方向成功(即,類型是相同的上述轉換之後)和兩個P和A分別引用類型(即前替換爲上面提到的類型):
- 如果參數模板中的類型是一個左值引用,並且參數模板中的類型不是,則參數類型被認爲比另一個更專用; ...

第一個模板是T &和第二是T & &,所以首先應該是更加專業化。這裏有什麼問題?


編輯: 該代碼以g測試++ 4.6.1和VC++ 2010 Express中,既得到不明確的錯誤。

+0

有一個關於歧義的缺陷報告和您引用的規則被添加。不幸的是我現在在我的手機上,所以我不能給你鏈接。 – 2012-03-27 08:19:04

回答

4

您對標準的解釋看起來是正確的。

template <typename T> void f(T&) {} // #1 
template <typename T> void f(T&&) {} // #2 

在#1,T成功推導出int,並在#2,T成功推導出int&,所以偏序被執行以選擇要調用的函數。在呼叫f(x)的部分訂購期間,第一個(僅在本例中)參數的類型將被排序([temp.deduct.partial]/3 bullet 1)。在兩個方向扣除時,類型P將爲T,並且類型A將是代表T[temp.deduct.partial]/5)的合成類型,因此扣減在兩個方向都成功。

正如你所觀察到的,[temp.deduct.partial]/9然後適用,並且說#1的第一個參數是更專門的。因此,通過[temp.deduct.partial]/10,選擇#1作爲最專用的模板,其專門化是重載解析的結果。

你沒有提到你正在使用哪個編譯器。我認爲它是g ++ - 這似乎是該編譯器中的一個錯誤(我已經測試了4.4.3和4.7之間的版本,並且它們都拒絕了這個代碼)。鐺接受你的代碼,並按你的意願調用f(T &)過載。

4

指南

不要超載:

template <typename T> void f(T&) {} 
template <typename T> void f(T&&) {} 

原因

沒有爲模式的特定模板扣除規則:

template <typename T> void f(T&&) {} 

這條規則的存在是爲了實現所謂的「完美轉發」。它有助於像bindmake_shared這樣的事物完美地轉發它們的參數,保留cv限定符和「值類別」(左值/右值)。

這種特殊的規則指出,當f(T&&)調用與左值參數(例如int),是t被推導出一個左值參考(例如int&)代替int。左值引用int的右值引用向下摺疊爲左值引用int。即

f(x) 

調用

f<int&>(int& && x); 

其簡化爲:

f<int&>(int& x); 

編輯

這不是多於或少於f<int>(int&)專業化程度較低。

感謝Johannes Schaub的糾正(見評論)。

解決方案

你可以做任何你想用單一功能:

template <typename T> void f(T&&) {} 

如果T演繹爲一個左參考,做任何你想要在你的第一個過載不這樣做,在第二次過載時做任何你想做的事情:

template <class T> void f_imp(T&, std::true_type) {std::cout << "lvalue\n";} 
template <class T> void f_imp(T&&, std::false_type) {std::cout << "rvalue\n";} 

template <typename T> void f(T&& x) 
{ 
    f_imp(std::forward<T>(x), std::is_lvalue_reference<T>()); 
} 

並使用std::forwardx完美轉發到實現細節函數。

+0

雖然指出不應該寫這樣的重載,但是從內存中我記得第一個模板是爲了更專業化(在C++ 0x草稿中並不總是這種情況),並且出現了措辭以反映這一意圖。 – 2012-03-27 08:08:33

+0

@ JohannesSchaub-litb:謝謝,我已根據您的評論更正了我的答案。 – 2012-03-27 13:09:17