在下面的Wikipedia article中引用了引用:
只有在非限定名称的正常查找失败时才会发生ADL 找到匹配的类成员函数。在这种情况下,其他命名空间 在正常查找期间不考虑可以搜索其中的集合 要搜索的名称空间取决于函数的类型 参数
所以,我期待下面的程序可以正常编译,但doesn't:
namespace N1 {
class A {};
void foo (A *p) {}
}
namespace N2 {
void foo (N1::A &p) {}
}
int main () {
N1::A xa;
foo(&xa); // ok
foo(xa); // error: cannot convert ‘N1::A’ to ‘N1::A*’ for argument ‘1’ to ‘void N1::foo(N1::A*)’
}
我在SO中搜索了几个问题,但找不到哪个列出了简单单词中的要求或情况,这表明:当ADL启动时? 更详细的答案对我和未来的访客都非常有帮助。
答案 0 :(得分:4)
它不应该编译。 A
位于名称空间N1
中。编译器应该如何知道,您要调用N2::foo
?
n3376 3.4.2 / 2
对于函数调用中的每个参数类型T,都有一组零个或多个关联的命名空间和一个 要考虑的零个或多个关联类的集合。 确定名称空间和类的集合 完全由函数参数的类型(以及任何模板模板参数的名称空间)。 用于指定类型的Typedef名称和using-declarations对此集合没有贡献。套 命名空间和类的确定方式如下:
如果T是类类型(包括联合),则其关联的类是:类本身;它所属的类 会员,如果有的话;及其直接和间接基类。 其关联的命名空间是命名空间 其关联的类是其成员。此外,如果T是类模板专门化, 其关联的名称空间和类还包括:名称空间和与之关联的类 为模板类型参数提供的模板参数的类型(模板模板除外) 参数);任何模板模板参数都是成员的名称空间;和班级 其中任何用作模板模板参数的成员模板都是成员。 [注意:非类型 模板参数不会对关联的命名空间集做出贡献。 - 尾注]
答案 1 :(得分:1)
只要您的函数将用户定义为用户定义的类型,ADL就会一直踢。这里的foo
正在进行中:xa
在N1
中定义,因此foo
在N1
以及全局命名空间中进行搜索。 (如果没有ADL,则只会在全局命名空间中搜索foo
。)
我不明白为什么你会期望第二次调用foo
来编译。 xa
的类型在N1
中定义,因此ADL会将N1
添加到搜索路径中,但表达式中没有任何内容暗示N2
。
答案 2 :(得分:1)
它会搜索“其他命名空间”。它没有说“搜索所有命名空间”。
ADL中包含哪些额外命名空间的规则有点复杂,但最重要的是定义A
的命名空间。这就是你找到第一个foo
的原因。无法找到您的第二个foo
,因为命名空间N2
与任何内容无关,并且ADL不会搜索它。
答案 3 :(得分:1)
如果不合格的Name Look-up失败,则使用函数调用的参数进行查找。
实施例
func(A x);
然后编译器将从包括类A的命名空间开始查看命名空间。一个例子就是这个
// argument_dependent_name_koenig_lookup_on_functions.cpp
namespace A
{
struct X
{
};
void f(const X&)
{
}
}
int main()
{
// The compiler finds A::f() in namespace A, which is where
// the type of argument x is defined. The type of x is A::X.
A::X x;
f(x);
}
答案 4 :(得分:0)
编译器找到具有匹配名称的函数后停止查找。它不会继续搜索参数类型或可访问性(public / protected / private)是否实际阻止在当前上下文中使用该函数。因此,在您的示例中,编译器没有“看到”N2::foo
的更改,因为首先找到N1::foo
。
请注意,在您的示例中,即使N2::foo
不存在,也找不到N1::foo
,因为您在N2
内的任何地方都没有引用main
,所以根本不会搜索N2
。