在什么情况下,Argument Dependent name Look-up(ADL)开始了?

时间:2013-02-22 08:35:25

标签: c++ argument-dependent-lookup

在下面的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启动时? 更详细的答案对我和未来的访客都非常有帮助。

5 个答案:

答案 0 :(得分:4)

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

对于函数调用中的每个参数类型T,都有一组零个或多个关联的命名空间和一个 要考虑的零个或多个关联类的集合。 确定名称空间和类的集合 完全由函数参数的类型(以及任何模板模板参数的名称空间)。 用于指定类型的Typedef名称和using-declarations对此集合没有贡献。套 命名空间和类的确定方式如下:

如果T是类类型(包括联合),则其关联的类是:类本身;它所属的类 会员,如果有的话;及其直接和间接基类。 其关联的命名空间是命名空间 其关联的类是其成员。此外,如果T是类模板专门化, 其关联的名称空间和类还包括:名称空间和与之关联的类 为模板类型参数提供的模板参数的类型(模板模板除外) 参数);任何模板模板参数都是成员的名称空间;和班级 其中任何用作模板模板参数的成员模板都是成员。 [注意:非类型 模板参数不会对关联的命名空间集做出贡献。 - 尾注]

答案 1 :(得分:1)

只要您的函数将用户定义为用户定义的类型,ADL就会一直踢。这里的foo正在进行中:xaN1中定义,因此fooN1以及全局命名空间中进行搜索。 (如果没有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);   
}

更多信息  http://msdn.microsoft.com/en-us/library/60bx1ys7.aspx

答案 4 :(得分:0)

编译器找到具有匹配名称的函数后停止查找。它不会继续搜索参数类型或可访问性(public / protected / private)是否实际阻止在当前上下文中使用该函数。因此,在您的示例中,编译器没有“看到”N2::foo的更改,因为首先找到N1::foo

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