【问题标题】:Ambiguous Overloaded Operator C++20歧义重载运算符 C++20
【发布时间】:2021-05-02 22:15:51
【问题描述】:

我正在尝试在最新的 Visual Studio 和 Clang 版本中测试我的项目。弹出的错误之一与不明确的运算符(with reversed parameter order) 有关。这似乎不会在 C++17 中弹出。

例如:(https://godbolt.org/z/Gazbbo)

struct A {
    bool operator==(const A& other) const { return false; }
};

struct B : private A {
    B(const A&);
    bool operator==(const B& other) const { return false; }
};

bool check(A a, B b) {
    return b == a;
}

我不确定为什么这会是一个问题。在我看来,这里唯一可行的函数是bool operator==(const B& other) const,因为A 可以隐式转换为B,但不能反过来。事实上,如果我用explicit 标记B(const A&),我会得到一个错误,即B 无法转换为A 的私有基数。

除了使用explicitB(a) 之外,我正在努力了解我可以做些什么来避免这种情况。想象一下AB 是库代码,如何在不破坏低版本接口的情况下支持C++20?

【问题讨论】:

  • @Barry 我不确定这是否与飞船操作员有关...如果我用默认飞船替换我的重载,我会得到相同的编译器错误。
  • 这与作为宇宙飞船功能的一部分采用的规则有关。

标签: c++ operator-overloading c++20 ambiguous spaceship-operator


【解决方案1】:

在 C++17 中,是的,唯一可行的候选者是 b.operator==(B(a))


但在 C++20 中,比较运算符具有更多功能。平等现在也可以考虑颠倒和重写的候选人。因此,当考虑表达式b == a 时,我们也会考虑表达式a == b。因此,我们有两个候选者:

bool B::operator==(B const&);
bool A::operator==(A const&); // reversed

B 成员函数在左侧完全匹配,但需要转换第二个参数。 A 成员函数在右侧完全匹配,但需要转换第一个参数。没有一个候选人比另一个更好,所以结果变得模棱两可。

至于如何解决。这是一种奇怪的场景(B 都继承自 A 并且可以从 A 构造?)。如果您放弃继承,您将删除 A 成员候选人。如果您删除B(A const&) 构造函数,那么您会遇到访问冲突,因为唯一的候选者是比较A 的那个,它需要将b 转换为其A(这表明这是有问题的)。

或者,您可以在B 中添加与A 的直接比较,以定义其实际含义。由于这里的问题是有两个选择,编译器不知道哪个最好,所以只提供一个更好的:

struct B  : private A {
    B(const A&);
    bool operator==(B const&) const;
    bool operator==(A const&) const; // <== add this one
};

现在这个新的在两个论点中都是完全匹配的,并且是绝对优越的候选者。

【讨论】:

  • 我很困惑为什么A::operator==(A const&amp;) 被认为是有效的候选人。据我所知,没有从B 获取A 的有效路径。
  • @wKavey 派生到基础? 重载决议之后检查访问控制,而不是之前。
  • 感谢您的帮助。我同意这是一个独特的情况。事后看来,构造函数应该是显式的(或者继承不应该存在)。既然我们在这里,我们非常希望不破坏库现有用户的界面,同时支持 C++20 中的其他用户。
  • Also derived-to-base B->A 比用户定义的 A->B 好(但这些是不同的论点,所以仍然是一个纵横交错的情况)。
猜你喜欢
  • 1970-01-01
  • 2010-09-27
  • 2017-03-24
  • 2021-02-05
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
相关资源
最近更新 更多