为什么B :: f不解决歧义,但A :: f呢?

时间:2013-07-06 17:39:35

标签: c++ argument-dependent-lookup

为什么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
    }
}

3 个答案:

答案 0 :(得分:21)

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

答案 1 :(得分:10)

当编译器尝试解析f中的f(x)时,它会找到B::f,因为我们位于命名空间B中。 它还使用argument dependent lookup找到A::f,因为xX的一个实例,它在命名空间A中定义。因此含糊不清。

使用B::f的声明没有任何效果,因为我们已经在命名空间B中。

要解决歧义,请使用A::f(x)B::f(x)

答案 2 :(得分:1)

您应该每次都明确地编写命名空间。只是做

#include <iostream>

namespace A
{
    class X { };
    void f( X ) {
        std::cout << "A";
    }
} 

namespace B
{
    void f( A::X ) {
        std::cout << "B";
    }
    void g( A::X x )
    {
        // using B::f;
        B::f(x);        
    }
}

int main() {
    B::g(A::X()); // outputs B
}