error: no match for ‘operator==’, but indeed defined on base class

error: no match for ‘operator==’, but indeed defined on base class

struct BaseA {
    auto operator==(const BaseA& other) const {return other.a == a;}
    int a;
};

struct B {
    int b;
};

struct A: public BaseA {
    auto operator==(const B& other) const {return other.b == a;}
};

int main() {
    A a{10};
    a == a;

    return 0;
}

它不会编译:

error: no match for ‘operator==’ (operand types are ‘A’ and ‘A’)
note: candidate: ‘auto A::operator==(const B&) const’
note: no known conversion for argument 1 from ‘A’ to ‘const B&’

未将 BaseA::operator== 列为候选人。

但是,如果我注释掉 A::operator== 方法,它会编译。

正因为如此,我认为比较运算符得到一些特殊处理,(有时为 child class 生成,有时不会,就像 rule-of-five 中的那些),但是在快速搜索结果并非如此。

运算符重载的一些规则呢?

auto operator==(const B& other) const隐藏基数,使用using

struct A: public BaseA {
    using BaseA::operator==;
    auto operator==(const B& other) const {return other.b == a;}
};

Demo

这里的运算符没什么特别的,你会得到类似的错误:

struct BaseA {
    auto foo(const BaseA& other) const {return other.a == a;}
    int a;
};

struct B {
    int b;
};

struct A: public BaseA {
    auto foo(const B& other) const {return other.b == a;}
};

int main() {
    A a{10};
    a.foo(a);
}

编译器在 A 中找到 foo 并停在那里。如果您想同时拥有两者,则需要明确地将其拉入范围:

struct A: public BaseA {
    auto foo(const B& other) const {return other.b == a;}
    using BaseA::foo; 
};

我找到了一个修复,没有写出 using 我在子 class:

中添加的每个比较运算符

使运算符成为非成员并将其拉出到 A 的封闭范围(在本例中为全局范围):

auto operator==(const A&, const B&)

如果您想访问 A 的私有成员或其基数 class 的受保护成员,您可以将操作员设为 A 的好友。 (与 B 相同。)

为什么有效

隐藏(意思是如果这个名字在一个范围内找到,它不会在下一个范围内查找,那些查找算法将在下一步中考虑) 不会阻止它工作,因为 对于运算符 ,执行两个单独的查找,随后合并:

For an operator used in expression (e.g., operator+ used in a+b) two separate lookups are performed: for the non-member operator overloads and for the member operator overloads (for the operators where both forms are permitted). Those sets are then merged with the built-in operator overloads on equal grounds.

-- cppreference

因此全局命名空间中的非成员 operator== 不会阻止搜索 BaseA::operator==,它在成员运算符查找中搜索,从 A 开始(但有没有 operator== 现在),所以继续下一个范围,基础 class BaseA.


这种修复方法对我来说很重要,因为我使用了一个强类型库,我只想为强类型添加一个运算符,包装一个整数。我正在使用库 ti 避免自己写出样板,但每次我添加一个运算符时,我都必须 use 库中的那个。