2012-10-05 99 views
1

考慮這個非常簡單的例子,在那裏我有被定義運營商模板包裝類:爲什麼參數匹配適用於非模板版本,但不適用於模板版本?

template <class T> 
struct W { 
    W(const T&) {} 
}; 
template <class T> 
T operator + (const W<T>& w1, const W<T>& w2) { return T(); } 

這令人驚訝的無法比擬的包裝類型,從gcc4.5.1簡單的錯誤是無法找到operator + (A,A)

struct A {}; 
int main() { 
    A a1, a2; 
    A a3 = a1 + a2; 
} 

我試圖找到測試非模板包裝的原因,但這個版本的作品:

struct A {}; 
struct WA { 
    WA(const A&) {} 
}; 
A operator + (const WA& w1, const WA& w2) { return A(); } 
int main() { 
    A a1, a2; 
    A a3 = a1 + a2; 
} 

這些參數匹配差異的原因是什麼,以及如何使模板版本起作用?

[更新]

我把你的答案考慮,我已經改變的例子是有點相反的方式,仍具有相同的結果 - 模板版本抱怨缺少運營商+,而非模板工作正常。現在我有明確的轉換操作員明確的包裝類:

模板版本

template <class T> 
struct W { 
}; 
template <class T> 
T operator + (const W<T>& w1, const W<T>& w2) { return T(); } 

struct A { 
operator W<A>() const { return W<A>(); } 
}; 

沒有模板

struct WA { 
}; 
struct A { 
operator WA() const { return WA(); } 
}; 

A operator + (const WA& w1, const WA& w2) { return A(); } 

我試圖避免這種情況的解決方案:

A a3 = W(a1) + W(a2); 

沒有希望這個工作?

A a3 = a1 + a2; 

回答

4

模板參數推導來重載決議。但模板參數推導不考慮隱式轉換,因此您的模板化運算符甚至不會被考慮。

隱式轉換僅適用後的過載已被選定

你可以說A a3 = W(a1) + W(a2);,雖然。因爲標準說,它必須失敗,模板

+0

所以編譯器是正確的,但這是我想要避免的。也許還有另外一種方法通過模板包裝實現'A a3 = a1 + a2'? – PiotrNycz

+0

我已經對我的問題進行了更新。你的答案仍然適用? – PiotrNycz

+0

@PiotrNycz:No;你仍然依靠隱式轉換。爲什麼不用「is_constructible_from」提供一個SFINAE-ed模板呢? –

2

你的第一個例子失敗。依賴於參數的名稱查找存在潛在的問題,模板會加劇這些問題。解決這個問題的一個方法是排除這種查找模板,除非您明確了使用模板。下面是從C++ 03標準的相關文字,部分14.8.1條第6款:

對於簡單的函數名,參數依賴查找(3.4.2)系統也將使用該函數名稱不是內可見通話範圍。這是因爲調用仍然具有函數調用的語法形式(3.4.1)。但是,如果使用帶有顯式模板參數的函數模板,則調用不具有正確的語法形式,除非在調用時有一個名稱可見的函數模板。如果不存在這樣的名稱,則該調用在語法上不是格式良好的,並且依賴於參數的查找不適用。如果某些此類名稱可見,則會應用依賴於參數的查找,並且可能會在其他名稱空間中找到其他函數模板。

更新:
問題已被編輯用的附加信息。

我試圖避免這種情況的解決方案:
A a3 = W(a1) + W(a2);

爲什麼,就是這樣,你想避免這種情況?你的這段代碼違反了編程的兩個關鍵規則。

  1. 代碼就好像下一個維護你的代碼的人是一個知道你住在哪裏的殺人狂。
  2. 最不驚訝的原則。

即使您的非模板版本也違反了這些規則。您通過(隱藏)轉換到無關類W來計算a1+a2,其中operator+返回A而不是W。這不是最令人驚訝的原則。至少可以這麼說,這是令人驚訝的。 爲什麼你不認爲明確地進行轉換是一種更好的方法?

依賴於參數的查找是一個非常強大的工具,但存在很多與此功能相關的問題。將ADL與自動類型轉換結合在一起,問題就會放大。將它與自動類型轉換和模板結合在一起,你就會陷入混亂。標準委員會決定就夠了。除非明確地進行轉換,否則你不能做你想做的事情。

+0

什麼是否意味着「在該調用點可見的名稱的功能模板」 – PiotrNycz

+0

我之前沒有注意到您的更新。我同意,但是...這不是真正的代碼。我只是用它來舉例說明問題不是所有的「環境」。考慮到這裏的海報總是被要求發佈一個只顯示問題的代碼,但之後他們被批評爲愚蠢的編程方式......我會記得補充說明,代碼只是人造插圖。 – PiotrNycz

相關問題