2015-10-05 83 views
21

我有一個模板與typename T模板。它包含一個函數,爲什麼我的模板函數不能將'int'提升爲'T',其中'T'='double'?

template <typename T, size_t a> 
myClass<T,a> operator+(myClass<T,a> lhs, const T& rhs) { 
    return lhs += rhs; 
} 

myClass<T,a> myClass<T,a>::operator+=(const T& rhs) { 
    // Do addition, depends on 'a'. 
    return *this; 
} 

當我調用此方法,例如

myClass<double, 2> myObj_double_2(constructor args); 
myObj_double_2 = myObj_double_2 + 5.2; 

我沒有問題。

如果我打電話然而

myObj_double_2 = myObj_double_2 + 5; 

那麼編譯器給了我這樣的消息 - No match for 'operator+' (operand types are 'myClass<double, 2ul>' and 'int'). Candidates are ... note: deduced conflicting types for parameter 'const T' ('double' and 'int')

我可以通過某種方式編寫代碼以允許通過轉換爲T的其他類型(例如,double(5)是一個有效的構造函數調用)嗎?

+0

嘗試'myObj_double_2 = myObj_double_2 + 5.0;' – 101010

+1

是的 - 這將毫無困難地工作,但它不能解決我所問的問題(雖然它是簡單明顯的解決方案) – chrisb2244

+1

沒有int-> double「推廣「存在。 –

回答

32

當您使用模板參數推導,對於一個模板參數的所有扣除項目必須具有相同的結果

在你的情況下,T產生的兩個扣除產生doubleint,這是不一樣的,所以扣除失敗。

你可以做的是隻使用一個模板參數推導函數參數,使另一個undeduced

template <typename T, std::size_t A> 
void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2); 
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

注意std::common_type<T>::type本質上只是T,但由於類型arg2現在是依賴類型(它的名稱出現在::的右側),因此不會推導出來。因此,只有第一個參數參與推導並明確生成T = double,然後第二個函數參數的類型爲double,並且發生常規轉換。

作爲一個經驗法則,模板參數扣除不會穿越::

+0

這是完美的,但我認爲你的意思是'typename std :: common_type :: type'。你的解決方案還允許添加'const'和'&',這非常棒 – chrisb2244

+0

@ chrisb2244:謝謝,修正。我將參考修改留給您;它們對問題不重要。 –

+1

'common_type'衰減類型;可能在這裏沒有關係,但是要記住。 –

17

超載分辨率編譯器無法找到operator+因爲T一個合適的人選已經被扣除double和文字5是一個整數。解決方案:

template <typename T1, typename T2, size_t a> 
myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) { 
    return lhs += T1(rhs); 
} 
+0

在'T1'和'T2'是相等的情況下,這將可能導致不必要的拷貝 - 將值取參數允許移動(這將是很可能是任何更快int'的'的情況下和'double'?) – chrisb2244

+4

@ chrisb2244你可以部分專門爲案件'T1 == T2' – BeyelerStudios

+0

構造風格的類型轉換是很危險的,如果你想只允許隱式轉換,然後初始化本地型T1'的'。 –

8

您遇到了模板類型扣除的問題。推斷的T值時

兩個參數都給出「平等地位」,在這種情況下這兩個參數不同意 - 一個說:Tint,對方稱T應該double

解決此問題的正確方法是使用Koenig操作員。

製作+=+之類friend是你的類並實現在線:

template<class T, size_t a> 
class myClass { 
    // etc 
public: 
    friend myClass operator+(myClass lhs, const T& rhs) { 
    lhs += rhs; 
    return std::move(lhs); 
    } 
    friend myClass& operator+=(myClass& lhs, const T& rhs) { 
    // do addition, depends on `a` 
    return *this; 
    } 
}; 

這個技術確實有些奇怪。它根據類的模板類型創建非template運算符。然後在調用++=時,通過ADL(Koenig查找)找到這些文件。

你得到每個模板實例,這些運營商之一,但他們都沒有模板的運營商,所以const T&不是推斷,而且發生轉換預期。

相關問題