[英]How do I make template type deduction work with references?
我有一個模板函數, func
:
template<typename T>
void func(T p) { f(p); }
還有一組函數f
:
f(SomeType&);
f(int);
...
如果我使用引用作為函數參數p
實例化模板函數func
,而不顯式指定模板參數T
,那么推導出的類型將不是p
的引用類型,而是類型p
是p
的引用,例如:
SomeType s;
SomeType& ref_to_s = s;
func(ref_to_s); // Type deduction results in: func<SomeType>(ref_to_s)
func<SomeType&>(ref_to_s); // Need to explicitly specify type to work with reference
所以,我的問題是:
SomeType&
? func
,因此類型推導與引用類型一起工作,而沒有明確指定模板參數T
? 要清楚,我想要兩者兼顧(參見上面的函數f
):
func(ref_to_s); // Calls func<SomeType&>(ref_to_s)
func(1); // Calls func<int>(1)
第一部分的答案是從值初始化對象並將引用綁定到值被認為是同樣好的(兩者都是重載決策中的“完全匹配”),因此不推導出參數的引用。 相反,您必須准確指定它。 對於相關示例,請考慮假設的構造
T x = f();
其中T
是(在這個思想實驗的持續時間)你應該推斷的東西。 x
應該是什么 - 一個對象或一個引用? 它取決於什么? 當然,右邊的表達式有一個值,該值的類型始終是對象類型。 你應該如何決定? 您可以查詢表達式的值類別,但這太微妙了。 所以相反, 你必須說出你想要的東西:
T x = f(); // x is an object
T & r = f(); // r is a reference
在C ++中,如果將T
替換為auto
,則實際上可以使用此機制。 相同的規則適用於函數模板的模板參數推導。
現在就如何解決你的問題。 通常的習慣用法是讓函數模板始終采用引用,然后將參數轉發給內部調用:
template <typename T>
void func(T && t)
{
f(std::forward<T>(t));
};
現在func
的參數始終是任何特化中的引用(但是由於稱為“引用折疊”的奇怪規則,它可以是左值或右值引用),並且該值使用相同的值類別組轉發到f
,並且當func
的原始參數是左值時, f
上的這個重載決策允許選擇左值引用重載。
使用轉發參考:
template<typename T>
void func(T && p) //notice &&
{
f(std::forward<T>(p)); //notice std::forward
}
現在請在本網站上搜索轉發引用(或之前提到的通用引用 )以及std::forward
以了解更多相關信息。
考慮以下示例:
template<typename T>
void f(T value, T& ref) {// fake swapping
T temp = ref;
ref = value;
value = temp;
}
當編譯器試圖推導出T的類型時,合理的做法是首先從“value”和“ref”中刪除可能的引用,這樣
int i = 1;
int j = 2;
f(i, j); //value of j becomes 1.
//up to here, value of i is still 1
否則,事情會變得很奇怪。 如果T被推導為T&,則f(i,j)的類型將等於f(int&,int &&)。 假設T &&崩潰到T&,那么它變成f(int&,int&)。 這完全違背了程序員的意圖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.