0

Wikipedia 文章中提到了以下引用:

只有在正常查找非限定名称时找不到匹配的类成员函数时,才会发生 ADL 。在这种情况下, 可以搜索在正常查找期间未考虑的其他名称空间,其中要搜索的名称空间集合取决于函数参数的类型

所以,我期待下面的程序编译得很好,但它没有

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​​ 何时开始?
更详细的答案对我和未来的访客真的很有帮助。

4

5 回答 5

4

它不应该编译。A在命名空间中N1。编译器应该如何知道您要调用N2::foo?n3376 3.4.2/2

对于函数调用中的每个参数类型 T,有一组零个或多个关联的命名空间和一组零个或多个关联的类需要考虑。命名空间和类的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)决定。 用于指定类型的 Typedef 名称和 using-declarations 不构成该集合。命名空间和类的集合通过以下方式确定:

如果 T 是类类型(包括联合),则其关联的类是:类本身;它所属的类别(如有的话);及其直接和间接基类。其关联名称空间是其关联类是其成员的名称空间。此外,如果 T 是类模板特化,则其关联的命名空间和类还包括: 与为模板类型参数(不包括模板模板参数)提供的模板实参类型相关联的命名空间和类;任何模板模板参数都是其成员的命名空间;以及用作模板模板参数的任何成员模板是其成员的类。[注意:非类型模板参数不参与关联命名空间的集合。——尾注]

于 2013-02-22T08:37:08.457 回答
1

只要您的函数采用用户定义的类型,ADL 几乎总是会启动。它在foo这里开始:xa在 中定义N1,因此在全局命名空间中以及在全局命名空间中进行foo搜索。N1(没有 ADL,foo只会在全局命名空间中搜索。)

而且我不明白为什么您会期望第二次调用foo编译。的类型在xa中定义N1,因此 ADL 添加N1到搜索路径中,但表达式中没有任何内容可以暗示N2

于 2013-02-22T08:41:17.653 回答
1

它说搜索“其他名称空间”。它没有说搜索“所有名称空间”。

ADL 中包含哪些额外命名空间的规则有点复杂,但最重要的A是定义的命名空间。这就是为什么你的第一个foo被发现。foo找不到您的第二个,因为命名空间N2与任何内容无关,并且 ADL 不会搜索它。

于 2013-02-22T08:41:51.403 回答
1

如果非限定名称查找失败,则使用函数调用的参数继续查找。

例子

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);   
}

更多在这里 http://msdn.microsoft.com/en-us/library/60bx1ys7.aspx

于 2014-05-02T11:01:57.347 回答
0

一旦找到具有匹配名称的函数,编译器就会停止查找。如果参数类型或可访问性(公共/受保护/私有)实际上阻止在当前上下文中使用该函数,它不会继续搜索。因此,在您的示例中,编译器对 "see" 没有任何更改N2::foo,因为N1::foo首先找到了。

请注意,在您的示例中,N2::foo即使N1::foo不存在也不会找到,因为您没有引用N2内部的任何地方main,因此N2根本不会被搜索。

于 2013-02-22T08:41:23.853 回答