[英]c++ error: operator []: 2 overloads have similar conversions

template <typename T>
class v3 {
    T _a[3];

    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;

8 个解决方案



If you read the rest of the error message (in the output window), it becomes a bit clearer:


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>        ]

The compiler can't decide whether to use your overloaded operator[] or the built-in operator[] on the const T* that it can obtain by the following conversion function:

編譯器不能決定是否使用重載的運算符[]或在const T*上的內置運算符[],它可以通過以下轉換函數獲得:

operator const T * () const { return _a; }

Both of the following are potentially valid interpretations of the offending lines:


v.operator float*()[0]

You can remove the ambiguity by explicitly casting the integer indices to be unsigned so that no conversion is needed:


_a[0] = v[static_cast<unsigned int>(0)];

or by changing your overloaded operator[]s to take an int instead of an unsigned int, or by removing the operator T*() const (and probably the non-const version too, for completeness).

或者通過更改重載的操作符[],將int改為int,或者刪除操作符T*() const(也可能是非const版本)。



In simple terms: the compiler doesn't know whether to convert v to const float* and then use the operator[] for a pointer, or to convert 0 to unsigned int and then use the operator[] for const v3.

簡單地說:編譯器不知道是否要將v轉換為const float*,然后使用操作符[]作為指針,或者將0轉換為unsigned int,然后使用操作符(const v3)。

Fix is probably to remove the operator[]. I can't think of anything it gives you that the conversion operator to T* doesn't already. If you were planning to put some bounds-checking in operator[], then I'd say replace the conversion operators with getPointer functions (since in general you don't want to implicitly convert a safe thing to an unsafe thing), or do what std::vector does, which is that users get a pointer with &v[0].


Another change that lets it compile, is to change operator[] to take an int parameter instead of unsigned int. Then in your code, the compiler unambiguously chooses the interpretation with no conversion. According to my compiler, there is still no ambiguity even when using an unsigned index. Which is nice.

另一個讓它編譯的更改是,更改操作符[],以獲取int參數,而不是unsigned int.然后在代碼中,編譯器明確地選擇不轉換的解釋。根據我的編譯器,即使使用無符號索引,仍然沒有歧義。這是不錯的。



When you the compiler compiles the following



it has to consider two possible interpretations


v.operator T*()[0] // built-in []
v.operator[](0)    // overloaded [] 

Neither candidate is better than the other because each one requires a conversion. The first variant requires a user-defined conversion from v3<T> to T*. The second variant requires a standard conversion from int (0 is int) to unsigned int, since your overloaded [] requires an unsigned int argument. This makes these candidates uncomparable (neither is clearly better by C++ rules) and thus makes the call ambuguous.

兩個候選人都沒有比另一個更好,因為每個候選人都需要轉換。第一個變量需要由v3 到T*的用戶定義轉換。第二個變體要求從int(0)到unsigned int的標准轉換,因為您的重載[]需要一個無符號的int參數。這使得這些候選人無法與之相比(因為c++的規則,兩者都不是很好),從而使呼叫成為“伏擊”。

If you invoke the operator as



the ambiguity will disappear (since 0U is already an unsigned int) and your overloaded [] will be selected. Alternatively, you can declare your overloaded [] with int argument. Or you can remove the conversion operator entirely. Or do something else to remove the ambiguity - you decide.

歧義將消失(因為0U已經是一個unsigned int),您的重載[]將被選中。或者,您可以使用int參數聲明您的重載[]。或者您可以完全刪除轉換操作符。或者做些別的事情來消除歧義——你決定。



It is your type conversion operator that is the culprit. v transformed to a float pointer. Now there are two operator []s possible, one is the built in subscript operator for float and the other being the one you defined on v, which one should the language pick, so it is an ambiguity according to ISO.




Remember a class is a friend of itself:


v3(const v3<T> & v)
     _a[0] = v._a[0]; 
     _a[1] = v._a[1]; 
     _a[2] = v._a[2];

When copy something of the same type you are already exposed to the implementation details. Thus it is not a problem to access the implementation directly if that is appropriate. So from the constructor you can access the object you are copying directly and see its member '_a'.


If you want to know the original problem:


The literal '1' in the context 'v[1]' is an integer (this is a synonym of signed integer). Thus to use the operator[] the compiler technically is required to insert a conversion from int to unisgned. The other alternative is to use the operator*() to get a pointer to the internal object and then use the [] operator on the pointer. Compiler is not allowed to make this choice and error out:


Compiler options:


 _a[1] = v[1];
 // Options 1:
 _a[1] = v.operator[]((unsigned int)1);
 // Options 2:
 _a[1] = v.operator*()[1];

To make it unabigious you can use an unsigned literal;


 _a[1] = v[1u];

In the long run it may be worth making this easier for the user.
Convert the operator[] to use int rather than unsigned int then you will get exact matches when integer literals (or you can have two sets of operator[]. One that uses int and one that uses unsigned int).

從長遠來看,讓用戶變得更容易是值得的。轉換操作符[]使用int而不是unsigned int,那么當整型文字(或者您可以有兩組操作符[])時,您將得到精確的匹配。一個使用int和一個使用unsigned int的方法。



I didn't see it untill James McNellis posted the full error message, but the ambiguity is not between the two v3::operator[]() functions as it appears to be.

我沒有看到,直到James McNellis發布了完整的錯誤消息,但是這兩個v3::操作符()函數看起來是不明確的。

Instead, since there is no exact match between argument types, the compiler can't decide whether to:


a) Use v3::operator[](unsigned int) const, thereby converting the int argument to unsigned, or

a)使用v3::運算符[](unsigned int) const,從而將int參數轉換為unsigned,或。

b) Use the v3::operator const T*() const conversion followed by the built-in array indexing operator.

b)使用v3::操作符const T*() const轉換,然后是內置數組索引操作符。

You can avoid this by making the operator[] arguments int's rather than unsigned ints. But a better solution would be to avoid an implicit conversion to T* and instead provide a Data() function that did that explicitly.




I had this same issue: I resolved it simply making the typecast operator explicit.




The const version doesn't modify anything. The non-const version allows you to assign things using array notation (v[3] = 0.5;).

const版本不修改任何東西。非const版本允許您使用數組表示法(v[3] = 0.5)來分配事物。



粤ICP备14056181号  © 2014-2020 ITdaan.com