为什么B::f不能解决歧义,而A::f可以解决?

namespace A
{
    class X { };
    void f( X );
}

namespace B
{
    void f( A::X );
    void g( A::X x )
    {
        using B::f;   // which expression shall I use here to select B::f?
        f(x);         // ambiguous A::f or B::f
    }
}

最佳答案

using声明充当普通的声明:它隐藏外部作用域声明,但不抑制依赖于参数的查找(ADL)。

当您执行using B::f时,您基本上什么都不会改变。您只需在本地范围内重新声明B::f即可,无论如何它已经是可见的。这也不会阻止ADL也找到A::f,这会在A::fB::f之间造成歧义。

如果执行using A::f,则A::f的本地声明将隐藏B::f的外部声明。因此B::f不再可见,也不再通过不合格的名称查找找到。现在仅找到A::f,这意味着不再存在歧义。

无法抑制ADL。由于您所用的参数为A::X类型,因此ADL始终会为非限定名A::f找到函数f。您不能将其“排除”在考虑范围之外。这意味着您必须在不产生歧义的情况下将B::f考虑在内。唯一的解决方法是使用限定名称。

正如@Richard Smith在注释中正确指出的那样,可以禁止ADL。仅当函数名称本身用作函数调用中的后缀表达式时,才使用ADL。以任何其他方式指定目标函数会吓到ADL。

例如,函数指针的初始化不受ADL的约束

void g( A::X x )
{
    void (*pf)(A::X) = &f;
    pf(x);
}

在上面的示例中,将调用B::f。而且即使在函数名称周围只有一对()也足以抑制ADL,即
void g( A::X x )
{
    (f)(x);
}

已经足以使其称为B::f

关于c++ - 为什么B::f不能解决歧义,而A::f可以解决?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17505457/

10-15 05:46