【问题标题】:Resolving ambiguous overload of operator[]解决 operator[] 的模棱两可的重载
【发布时间】:2012-12-08 09:23:23
【问题描述】:

我有这门课:

class MyClass {

    public:

        int operator[](const std::string&);
        const std::string& operator[](const int&) const;

    ...
};

但是,如果我用 const 字面量 0 调用第二个运算符:

MyClass myclass;
std::cout << myclass[0] << std::endl;

我收到了这个错误:

In function 'int main()':
ambiguous overload for 'operator[]' in 'myclass[0]'
note: candidates are:
note: const int MyClass::operator[](const string&)|
note: const string& MyClass::operator[](const int&) const

我想我理解是什么情况(0 可以是字符串或整数?),但我的问题是:有没有办法解决这个问题并保持运算符重载?

【问题讨论】:

  • 为什么要打扰const int&amp;?只需发送int
  • string 版本匹配,因为 const 文字零可以隐式转换为空 const char* 指针,然后从那里转换为 std::string。仍在考虑如何避免这种情况。
  • 我很惊讶这些被视为同等排名的转化。
  • 返回 const int 很奇怪(而且毫无意义)。
  • @sftrabbit:这是因为实例上的const 资格。没有它会是一个更好的过载。

标签: c++ operators operator-overloading


【解决方案1】:

调用MyClass::operator[](const std::string&amp;) 涉及转换:

myclassMyClass&amp;MyClass&amp;:完美匹配

0intconst char*std::string:用户定义的转换

调用MyClass::operator[](const int&amp;) const 涉及转换:

myclassMyClass&amp;const MyClass&amp;:常量限定

0intint:完美匹配

在这种情况下,当一个重载对参数 X “更好”,但另一个重载对参数 Y “更好”时,这两个重载都不能被认为是最佳重载,编译器必须抱怨(假设没有第三个重载击败两者)。

是否可以将两个重载更改为constnon-const?如果没有,您可以添加第三个重载来处理这种情况:

const std::string& operator[](int n) {
    return static_cast<const MyClass&>(*this)[n];
}

【讨论】:

  • const限定转换是标准转换,而string(0)是自定义转换,所以没有歧义。
  • 谢谢!正如我在对 Kerrek 的回答的评论中提到的那样,我将第二个重载更改为非常量,并且它起作用了。
  • @GeneBushuyev:仅比较相同参数的 ICS-es。模棱两可的重载错误是正确的。
【解决方案2】:

0 不能是string,但它可以是一个指针,这意味着它可以隐式转换string。请注意,这不适用于其他常量积分,例如 142 ——具体来说只是 0

4.10 指针转换

1/空指针常量是一个整型常量表达式(5.19) 求值为零的整数类型的右值。空指针常量 可以转换为指针类型;结果是空指针 该类型的值,并且可以与其他所有值区分开来 指向对象的指针或指向函数类型的指针。两个空指针值 相同类型的应该比较相等。空指针的转换 指向 cv 限定类型的指针的常量是单次转换,并且 不是指针转换后跟限定的顺序 转换 (4.4)。

因此,对于myclass[0]0 可以是int,也可以是`空指针常量。

标准还规定std::string 有一个非explicit 构造函数,它采用char 指针:

size_type find_last_not_of (const charT* s, size_type pos = npos) const;

现在,由于您的 operator&amp; 方法都采用 const 引用类型的参数,因此可以将它们临时传递。这就是编译器感到困惑的原因——它不知道你想要哪个——接受int的那个,或者接受通过string(const char*)构造的临时string的那个。

至于如何解决这个问题,我会退后一步。在我看来,您的两个 operator[] 函数做了截然不同的事情。或者也许他们会做同样的事情,给定不同的输入。如果他们做不同的事情,那么我将提供具有不同(适当)名称的成员函数,并跳过尝试使用 operator[] 语法。也许其中一种方法会返回真正被索引的东西——在这种情况下,我会为那个方法使用operator[] 语法,但只使用那个。

如果他们确实做同样的事情,并且那个事情是返回一个项目按索引,那么我将为此只提供一种方法,并让它按值获取size_t .然后,您还可以提供某种类型的转换函数(最好采用免费的非成员函数的形式),例如将string 转换为size_t。这样做,您可以在通过string 进行索引时编写这样的代码:

myPos[str_to_index(str)];

【讨论】:

    【解决方案3】:

    文字0 是特殊的。除了作为八进制常量外,它还可以转换为任何指针类型的空指针。这使得0 对于char const *-构造函数std::string 是可行的。

    两个重载都不是更好的原因是因为运算符的 int 重载具有 const 实例 CV 限定符。这样一来,两个重载都需要转换并且同样糟糕。

    明显的解决方法是明确要求 const 重载:

    static_cast<MyClass const &>(myclass)[0]
    

    【讨论】:

    • 谢谢!现在,我刚刚删除了 const CV 限定符作为解决方法。
    • 对于那些感到困惑的人,有两个参数:this 指针和括号内的参数。运算符的第一个版本不需要对第一个参数进行转换,并且需要进行 int 到指针的转换,然后对第二个参数进行用户定义的转换。运算符的第二个版本要求对第一个参数进行 const 转换,而对第二个参数不进行转换。所以第一个版本在第一个参数上更好,第二个版本在第二个参数上更好。由于所有论点都不相同或更好,因此它是模棱两可的
    猜你喜欢
    • 2012-07-14
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多