c++错误:运算符 []:2 个重载具有类似的转换

发布于 2024-08-10 21:15:46 字数 887 浏览 16 评论 0原文

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;
}
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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

带上头具痛哭 2024-08-17 21:15:46

如果您阅读错误消息的其余部分(在输出窗口中),它会变得更清晰一些:

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; }

以下两者都是对违规行的潜在有效解释:

v.operator float*()[0]
v.operator[](0)

您可以通过显式消除歧义将整数索引强制转换为无符号,以便不需要转换:

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

或者通过更改重载的运算符[] 来采用 int 而不是 unsigned int< /code>,或者通过删除operator T*() const(为了完整性,也可能删除非常量版本)。

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:

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

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

v.operator float*()[0]
v.operator[](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).

叫嚣ゝ 2024-08-17 21:15:46

简单来说:编译器不知道是否将 v 转换为 const float* 然后使用 operator[] 作为指针,或者将 0 转换为 unsigned int,然后使用 operator[] 表示 const v3

修复可能是删除operator[]。我想不出它能为您提供什么 T* 转换运算符还没有提供的功能。如果您计划在 operator[] 中进行一些边界检查,那么我会说用 getPointer 函数替换转换运算符(因为通常您不希望将安全的事物隐式转换为不安全的事物),或者执行 std::vector 的操作,即用户使用 &v[0] 获取指针。

允许其编译的另一个更改是将 operator[] 更改为采用 int 参数而不是 unsigned int。然后在您的代码中,编译器明确选择解释而不进行转换。根据我的编译器的说法,即使使用无符号索引,仍然没有歧义。这很好。

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.

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.

烟凡古楼 2024-08-17 21:15:46

当编译器编译以下内容时,

v[0]

它必须考虑两种可能的解释,

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

这两种解释都不比另一种更好,因为每种解释都需要转换。第一个变体需要用户定义从 v3T* 的转换。第二个变体需要从 int0int)到 unsigned int 的标准转换,因为您重载了 < code>[] 需要一个 unsigned int 参数。这使得这些候选者无法比较(根据 C++ 规则,两者显然都不是更好),从而使调用变得不明确。

如果您调用该运算符,

v[0U]

歧义就会消失(因为 0U 已经是一个 unsigned int),并且您重载的 [] 将被选择。或者,您可以使用 int 参数声明重载的 [] 。或者您可以完全删除转换运算符。或者采取其他措施来消除歧义 - 由您决定。

When you the compiler compiles the following

v[0]

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.

If you invoke the operator as

v[0U]

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.

友谊不毕业 2024-08-17 21:15:46

罪魁祸首是你的类型转换运算符。 v 转换为浮点指针。现在有两个可能的运算符 [],一个是 float 的内置下标运算符,另一个是您在 v 上定义的运算符,语言应该选择哪一个,因此根据 ISO,这是一种歧义。

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.

写下不归期 2024-08-17 21:15:46

请记住,类是其自身的朋友:

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

当复制相同类型的内容时,您已经暴露了实现细节。因此,如果合适的话,直接访问实现并不是问题。因此,从构造函数中,您可以直接访问正在复制的对象并查看其成员“_a”。

如果你想知道原来的问题:

上下文“v[1]”中的文字“1”是一个整数(这是有符号整数的同义词)。因此,要使用运算符[],从技术上讲,编译器需要插入从 int 到 unisgned 的转换。另一种选择是使用运算符 *() 获取指向内部对象的指针,然后对该指针使用 [] 运算符。不允许编译器做出此选择并出错:

编译器选项:

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

为了使其不那么大,您可以使用无符号文字;

 _a[1] = v[1u];

从长远来看,让用户变得更容易可能是值得的。
将operator[]转换为使用int而不是unsigned int,然后当整数文字时您将获得精确匹配(或者您可以有两组operator[]。一组使用int,一组使用unsigned int)。

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).

夜光 2024-08-17 21:15:46

直到 James McNellis 发布完整的错误消息后我才看到它,但歧义并不在于两个 v3::operator[]() 函数之间,正如看起来的那样。

相反,由于参数类型之间没有完全匹配,编译器无法决定是否:

a) 使用 v3::operator[](unsigned int) const,从而将 int 参数转换为 unsigned ,或

b) 使用 v3::operator const T*() const 转换,后跟内置数组索引运算符。

您可以通过将operator[]参数设置为整​​数而不是无符号整数来避免这种情况。但更好的解决方案是避免隐式转换为 T*,而是提供显式执行此操作的 Data() 函数。

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.

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

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

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.

关于从前 2024-08-17 21:15:46

我遇到了同样的问题:我解决了这个问题,只需将类型转换运算符显式化即可。

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

忘羡 2024-08-17 21:15:46

const 版本不会修改任何内容。非 const 版本允许您使用数组表示法 (v[3] = 0.5;) 来分配内容。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文