过载解析:为什么它不会有歧义?

3
假设我们有以下代码,复制自另一个问题:
namespace x 
{
    void f()
    {
    }

    class C 
    {
        void f() 
        {
            using x::f;
            f();         // <==
        }
    };
}

在指示的那一行,名称f明确地指代x::f(至少根据gcc和clang)。在这种情况下,为什么会优先选择x::f而不是x::C::f呢?两个名称都是可见的,难道不应该是模棱两可的吗?
3个回答

10

由于using声明将x::f带入了f的作用域,使其比C更为狭窄。未经限定的查找会考虑到局部块级作用域,找到匹配项并在考虑更广泛的类作用域之前停止。由于没有函数参数,因此不存在参数相关的查找,因此不考虑其他作用域。


7
@MikeSeymour的回答很到位,以下是相关的标准引用(C ++11,重点是我自己加的):
13.3.1.1.1 / 3:
在非限定函数调用中,名称未经由“->”或“.”运算符限定,具有更一般的形式primary-expression。根据函数调用上下文按照函数调用的名称查找普通名称的规则进行查询(3.4)。由该查找找到的函数声明构成候选函数集。由于名称查找的规则,候选函数集包括(1)仅由非成员函数或(2)某个类T的成员函数完全组成。...
3.4.1/1:
在3.4.1中列出的所有情况中,分别按照每个类别中列出的顺序搜索范围;只要找到名称的一个声明,名称查找就会结束。如果没有找到声明,则程序不正确。
3.4.1/8
在类X的成员函数定义(9.3)中使用的名称f的声明符号之后...应以以下方式之一声明:
  • 在其所使用的块或封闭块(6.3)中使用之前声明;或
  • 应为类X的成员或类X的基类的成员(10.2),或
  • ...
  • 从3.4.1/8中我们可以看到,在使用的块(例如声明using x :: f;的情况)中声明名称f(如类C的成员)早于在类中声明f。根据3.4.1/1,选择前者,因此整个查找解析为由using声明引入的x :: f。

    1
    我认为C++标准中的这些引用将是相关的:
    来自C++标准(7.3.3使用声明):
    13.由于使用声明是一个声明,在同一声明区域(3.3)中具有相同名称的声明的限制也适用于使用声明。
    而且(3.3.7类作用域):
    4. 在成员函数内声明的名称隐藏了一个在其作用域扩展到或过去的成员函数类末尾具有相同名称的声明。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接