首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >运算符错误: c++ []:2个重载具有类似的转换

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

Stack Overflow用户
提问于 2009-11-13 10:22:06
回答 8查看 9.8K关注 0票数 3
代码语言:javascript
运行
复制
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;
}
EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2009-11-13 10:34:10

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

代码语言:javascript
运行
复制
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>        ]

编译器无法决定是在const T*上使用重载的operator[]还是内置的operator[],它可以通过以下转换函数获得:

代码语言:javascript
运行
复制
operator const T * () const { return _a; }

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

代码语言:javascript
运行
复制
v.operator float*()[0]
v.operator[](0)

您可以通过显式地将整数索引转换为无符号来消除歧义,这样就不需要进行转换:

代码语言:javascript
运行
复制
_a[0] = v[static_cast<unsigned int>(0)];

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

票数 12
EN

Stack Overflow用户

发布于 2009-11-13 10:37:58

简而言之:编译器不知道是将v转换为const float*,然后使用operator[]作为指针,还是将0转换为unsigned int,然后使用operator[]作为const v3

修复方法可能是删除operator[]。我想不出它给你提供了什么,T*的转换运算符已经没有了。如果您打算在operator[]中添加一些边界检查,那么我建议您将转换操作符替换为getPointer函数(因为通常您不希望隐式地将安全的东西转换为不安全的东西),或者做std::vector所做的事情,即用户使用&v[0]获取指针。

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

票数 5
EN

Stack Overflow用户

发布于 2009-11-13 10:43:26

当您执行以下操作时,编译器会编译

代码语言:javascript
运行
复制
v[0]

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

代码语言:javascript
运行
复制
v.operator T*()[0] // built-in []
v.operator[](0)    // overloaded [] 

两个候选者都不会比另一个更好,因为每个候选者都需要转换。第一个变体需要用户定义的从v3<T>T*的转换。第二个变体需要从int (0int)到unsigned int的标准转换,因为重载的[]需要一个unsigned int参数。这使得这些候选者不可比较(根据C++规则,这两个候选者显然都不是更好的),从而使调用变得不透明。

如果您以如下方式调用运算符

代码语言:javascript
运行
复制
v[0U]

歧义将消失(因为0U已经是一个unsigned int),并且您的过载[]将被选中。或者,您可以使用int参数声明重载的[]。或者您可以完全删除转换运算符。或者做一些其他的事情来消除歧义--你来决定。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1726740

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档