歧义重载运算符 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;
}

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

我正在尝试了解除了使用 explicit 或使用 B(a) 之外我可以做些什么来避免这种情况。想象一下 AB 是库代码,我如何支持 C++20 而不会破坏较低版本的界面?

解决方法

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

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...