运算符函数的重载解析

use*_*486 9 c++

为什么这段代码不能编译?我本以为会选择内置的一元运算符&,这样两个二元运算符& 之间的歧义就不重要了。如果注释掉其中一个二元运算符&,则代码将编译(使用 gcc 11.2)并选择内置一元运算符&。

struct A
{ int operator&(int) const { return 1; }
};

struct B
{ int operator&(int) const { return 2; }
};

struct C : A, B
{};

C* test(C& c)
{ return &c; } //error: request for member 'operator&' is ambiguous
Run Code Online (Sandbox Code Playgroud)

use*_*305 0

这是由于不合格的名称查找造成的。

最初,名称查找从 class 的范围开始Coperator&没有找到任何声明。

然后依次查找基类。在每个A和中B都有一个名为 的不同声明operator&

此时,通过名称查找找到的声明集是A::operator&B::operator&这些在名称查找阶段被认为是不明确的,因此operator&永远不会达到重载解析,即发现一元和二进制之间的差异。

有关更多信息,请参阅 cppreference 中非限定名称查找的示例。

如果仅继承A或之一B,则名称查找集不会是成员函数名称查找集不会有歧义。它将继续重载解析并正确推导一元operator&

using声明添加到 class 的主体中,将它们都带入名称查找的C范围内。C::

struct C : A, B
{
    using A::operator&;
    using B::operator&;
};
Run Code Online (Sandbox Code Playgroud)

在基类之前搜索C的范围,因此永远不会到达不明确的步骤。