template <typename T>
class v3 {
private:
T _a[3];
public:
T & operator [] (unsigned int i) { return _a[i]; }
const T & operator [] (unsigned int i) const { return _a[i]; }
operator T *() { return _a; }
operator const T *() const { return _a; }
v3() {
_a[0] = 0; // works
_a[1] = 0;
_a[2] = 0;
}
v3(const v3<T> & v) {
_a[0] = v[0]; // Error 1 error C2666: 'v3<T>::operator []' : 2 overloads have similar conversions
_a[1] = v[1]; // Error 2 error C2666: 'v3<T>::operator []' : 2 overloads have similar conversions
_a[2] = v[2]; // Error 3 error C2666: 'v3<T>::operator []' : 2 overloads have similar conversions
}
};
int main(int argc, char ** argv)
{
v3<float> v1;
v3<float> v2(v1);
return 0;
}
回答
如果你讀了錯誤消息的其餘部分(在輸出窗口),它成爲一個更清楚一點:
1> could be 'const float &v3<T>::operator [](unsigned int) const'
1> with
1> [
1> T=float
1> ]
1> or 'built-in C++ operator[(const float *, int)'
1> while trying to match the argument list '(const v3<T>, int)'
1> with
1> [
1> T=float
1> ]
編譯器不能決定是否使用過載operator[]
或內置operator[]
上const T*
,它可以由下面的變換功能獲得:
operator const T *() const { return _a; }
兩個違規線的下面是潛在有效解釋:
通過改變你的超載operator[]
s到採取
int
,而不是
unsigned int
_a[0] = v[static_cast<unsigned int>(0)];
,或者:
v.operator float*()[0]
v.operator[](0)
您可以通過顯式鑄造整數索引,這樣,不需要轉換到無符號消除不確定性或者通過刪除operator T*() const
(也可能是非const版本,爲了完整性)。
你如何閱讀該聲明? 「T是指向函數的常量指針,它不帶任何參數和...」 – 2009-11-13 02:39:21
更確切地說,造成歧義的原因是,例如,文字'1'(用作索引)的類型是'int',而不是'unsigned int',所以它需要轉換來調用overloader'operator [](unsigned int)'。換句話說,兩種選擇是'v.operator float *()[0]'和'v.operator []((unsigned int)0)'。 – 2009-11-13 02:41:46
@Shakedown:哪個聲明? – 2009-11-13 02:42:36
const
版本不會修改任何內容。非const
版本允許您使用數組表示法分配事物(v[3] = 0.5;
)。
簡單來說:編譯器不知道是否v
轉換爲const float*
然後用operator[]
爲指針,或將0
轉換爲unsigned int
,然後使用operator[]
爲const v3
。
修復可能是要刪除operator[]
。我想不出任何它給你的轉換操作符到T *還沒有。如果您打算在operator[]
中進行一些邊界檢查,那麼我會說用getPointer
函數替換轉換運算符(因爲通常您不希望將安全的事情隱式轉換爲不安全的東西),或者做什麼std::vector
確實,這是用戶得到一個指針&v[0]
。
讓它編譯的另一個更改是將operator[]
更改爲int
參數而不是unsigned int
。然後在你的代碼中,編譯器毫不含糊地選擇沒有轉換的解釋。根據我的編譯器,即使使用無符號索引,仍然沒有歧義。這很好。
這是你的類型轉換運算符是罪魁禍首。 v轉換爲浮點型指針。現在有兩個運算符[],一個是內置的下標運算符,另一個是你在v上定義的運算符,哪一個是語言選擇的,所以它是根據ISO的模糊性。
記住一類是自身的朋友:
v3(const v3<T> & v)
{
_a[0] = v._a[0];
_a[1] = v._a[1];
_a[2] = v._a[2];
}
當複製的東西你已經暴露在實施細則相同類型的。因此,如果適當,直接訪問實施並不是問題。因此,從構造函數中,您可以直接訪問要複製的對象並查看其成員'_a'。
如果你想知道最初的問題:
在上下文中的文字「1」,「V [1]」是一個整數(這是有符號整數的代名詞)。因此要使用操作符[],編譯器在技術上需要插入從int到unisgned的轉換。另一種方法是使用運算符*()來獲取指向內部對象的指針,然後在指針上使用[]運算符。編譯器是不允許做出這樣的選擇和錯誤的:
編譯器選項:
_a[1] = v[1];
// Options 1:
_a[1] = v.operator[]((unsigned int)1);
// Options 2:
_a[1] = v.operator*()[1];
爲了讓unabigious你可以使用一個無符號的文字;
_a[1] = v[1u];
從長遠來看,它可能是值得使用戶更容易。
將運算符[]轉換爲使用int而不是unsigned int,那麼當整數文字(或者可以有兩組運算符[]。一個使用int,另一個使用unsigned int)時,您將得到完全匹配。
當你的編譯器編譯以下
v[0]
它必須考慮兩個可能的解釋
v.operator T*()[0] // built-in []
v.operator[](0) // overloaded []
兩位候選人比其他更好的,因爲每一個需要一個轉換。第一個變體需要用戶自定義的從v3<T>
到T*
的轉換。第二個變體需要從int
(0
是int
)到unsigned int
的標準轉換,因爲您的超載[]
需要unsigned int
參數。這使得這些候選人無法比擬(由C++規則來看,這兩者都顯然更好),並因此使呼叫變得非常具有說服力。
如果調用運營商爲
v[0U]
的模糊性將消失(因爲0U
已經是一個unsigned int
)和您超載[]
將被選中。或者,您可以用int
參數聲明您的超載[]
。或者你可以完全刪除轉換操作符。或者做一些其他的事情來消除模糊 - 你決定。
@litb:P.S.我應該使用*無與倫比的*,因爲我現在看到... :))) – AnT 2009-11-13 17:23:57
@AndreyT,以及我讀到「每個人都需要轉換......這使得這些候選人無法比擬」,因爲兩個轉換同樣不好。所以我想我指出,由於不同的立場,它只是模棱兩可:不同的立場是無法比擬的。 – 2009-11-14 02:49:01
我沒有看到它,直到James McNellis發佈了完整的錯誤消息,但模糊不在兩個v3::operator[]()
函數之間,因爲它似乎是。
相反,由於參數類型之間沒有精確匹配,編譯器無法決定是否要:
a)使用v3::operator[](unsigned int) const
,從而int參數轉換爲無符號,或
B)使用v3::operator const T*() const
轉換後跟內置的數組索引操作符。
你可以通過使用operator []參數int而不是unsigned int來避免這種情況。但更好的解決方案是避免對T *的隱式轉換,而是提供一個明確做到的Data()函數。
我有這個相同的問題:我解決它只是簡單地使類型轉換運算符顯式。
- 1. 2過載有類似的轉換
- 2. C++轉換運算符過載
- 3. C++類轉換運算符
- 4. C++轉換運算符錯誤?
- 5. C++過載運算符<錯誤
- 6. C++模糊運算符過載錯誤
- 7. 運算符重載中的類型轉換錯誤
- 8. C++轉換運算符超載問題
- 9. 運算符重載和類型轉換
- 10. 錯誤的運算符()過載調用
- 11. 重載運算符+ C++的錯誤
- 12. C++:重載操作符。好奇類型轉換運算符
- 13. 沒有在C#中的類的類型轉換運算符?
- 14. verilog轉換運算符基本錯誤
- 15. C++運算符重載奇怪的類型轉換
- 16. C++運算符重載錯誤
- 17. 運算符重載錯誤C++
- 18. C++運算符重載錯誤
- 19. 重載運算符C++:錯誤:沒有可行的重載'='
- 20. C++過載運算符[] []
- 21. C++過載運算符++
- 22. 錯誤與轉換運算符和的std :: string類中的
- 23. 運算符重載,沒有明確的類型轉換
- 24. 涉及運算符過載函數的C++鏈接器錯誤
- 25. C++函數重載類似的轉換
- 26. 運算符重載錯誤?
- 27. Long.Tryparse過載和轉換錯誤C#
- 28. C++用戶定義的轉換運算符沒有類?
- 29. 有沒有類似於mysql中的運算符重載機制?
- 30. (boost.python)公開重載運算符+()的錯誤。 「類型錯誤:沒有to_python(按值)轉換器找到了」
問題是? – Tom 2009-11-13 02:25:26
這是一個衆所周知的轉換函數使事情出錯的例子。它也出現在「C++模板 - 完整指南」中。 – 2009-11-13 06:44:21
這就是爲什麼'std :: string'有'data'和'c_str'成員並且沒有轉換操作符的原因。它避免了不必要的痛苦。 – 2009-11-13 10:35:17