在运算符查找中,成员不会优先于非成员

In operator lookup no preference is given to members over nonmembers

Stroustrup 写道:

考虑一个二元运算符@。如果x是X类型,y是Y类型,x@y这样解析:

• 如果 X 是 class,则查找 operator@ 作为 X 的成员或作为 X 的基数的成员;和

• 在 x@y 周围的上下文中查找 operator@ 的声明;和

• 如果X 在命名空间N 中定义,则在N 中查找operator@ 的声明;和

• 如果 Y 在命名空间 M 中定义,则在 M 中查找 operator@ 的声明。

可能会找到多个 operator@ 的声明,并且重载解析规则 (§12.3) 用于查找最佳匹配(如果有)。仅当运算符具有至少一个用户定义类型的操作数时才应用此查找机制。因此,将考虑用户定义的转换(§18.3.2、§18.4)。 请注意,类型别名只是同义词,而不是单独的用户定义类型(第 6.5 节)。 一元运算符的解析类似。

请注意,在运算符查找中,成员不会优先于非成员。这不同于命名函数的查找

所以加粗的表达是什么意思。如果class有member同时有context中可以使用的非member函数,那么不给member优先?例如

class A
{
public:
    bool operator==(const A&)
    {
        return true;
    }
};

bool operator==(const A&, const A&)
{
    return true;
}

int main()
{
    A a, b;
    a == b;
}

我认为(编译器同意我的观点:))应该调用成员函数,但如上所述,不应优先考虑成员运算符。那么这句话中的 Stroustrup 到底是什么意思?

您的代码之所以能够编译,是因为您的运算符在此上下文中不等效。一个比一个好,按照隐式转换序列排序的规则。

请注意,您的成员运算符的第一个(左)参数缺少 const 限定。它实际上代表 bool operator==(A&, const A&).

由于main中的ab未声明为const,因此左侧操作数的隐式转换序列为 member 运算符的更短(更好)。它不需要 aAconst A 的限定转换。这就是使它成为更好的候选人的原因。这就是你的成员函数版本被选中的原因。

要使两个版本等同,您必须将 const 添加到您的成员运算符声明中

class A
{
public:
    bool operator==(const A&) const
    {
        return true;
    }
};

这会立即使您的 a == b 比较含糊不清。