不明确的重载运算符 C++20

wKa*_*vey 4 c++ operator-overloading ambiguous spaceship-operator c++20

我正在尝试在最新的 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;
}
Run Code Online (Sandbox Code Playgroud)

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

我试图了解除了使用explicit或使用B(a). 想象一下AB如果是库代码,我如何在不破坏较低版本中的界面的情况下支持 C++20?

Bar*_*rry 7

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


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

bool B::operator==(B const&);
bool A::operator==(A const&); // reversed
Run Code Online (Sandbox Code Playgroud)

成员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
};
Run Code Online (Sandbox Code Playgroud)

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

  • @wKavey 衍生到基础?访问控制是在重载决策之后检查的,而不是之前。 (3认同)