2013-10-06 42 views
3

新书这个例子,我再现参数相关查找(ADL)例如,在396和Stroustrup的书(第4版)的397页下面给出一些澄清:我需要相关的Stroustrup的约ADL

namespace N { 
    struct S { int i; }; 
    void f(S); 
    void g(S); 
    void h(int); 
}; 

struct Base { 
    void f(N::S); 
}; 

struct D : Base { 
    void mf(N::S); 

    void g(N::S x) 
    { 
     f(x); // call Base::f() 
     mf(x); // call D::mf() 
     h(1); // error: no h(int) available 
    } 
}; 

什么上面的评论是正确的(我已经测试过),但是这似乎与笔者在下一段中所说的内容不一致:

在标准中,参数相关查找的规则是短语 根据相关命名空间(iso§3.4.2)。基本上:

  • 如果一个参数是一个类的成员,关联的命名空间是类本身(包括其基类)和类的 包围的命名空间。
  • 如果参数是名称空间的成员,则关联的名称空间是封闭的名称空间。
  • 如果参数是内置类型,则没有关联的名称空间。

在该示例中,x,其具有类型N::S不是D类的成员,也不其基Base的。但它是namespace N的成员。根据上面的第二个项目符号,函数N::f(S)应该是所调用的函数,而不是Base::f()

以上也结果似乎不与在标准中段落3.4.2p2第二子弹,它说同意:

如果T是一个类类型(包括工会),其相关联的类是: 该课程本身;它是其成员的类别(如果有的话);和它的 直接和间接基类。其关联的名称空间是其关联的类是其成员的名称空间的 。此外,如果T是类模板专业化,则其关联的名称空间和类别还包括:与为模板类型参数 (不包括模板模板参数)提供的模板参数类型相关联的名称空间和类。任何 模板模板参数都是成员的名称空间;以及用作模板模板参数的任何 成员的类都是成员。

+1

只有在通过常规查找找不到函数时,ADL才会开始运行。 –

+0

@ n.m不正确。规则是如果正常查找找到本地实际函数声明(即'{void f(); ..')或类成员函数,则ADL被禁用。所有其他正常发现的声明(包括本地使用声明)仍然允许ADL完成。 –

+1

@ n.m。如果这是真的,那么当你在全局命名空间中为你的类实现'operator <<'时,你将不能再编写'std :: cout << std :: string(“Hello”);'。这当然不会发生。 –

回答

4

3.4.2/3X是由不合格查找(3.4.1)中产生的查找组并且让Y是由参数依赖 查找产生的查找集(定义如下)。如果X包含

  • 类成员的声明,或
  • 一个块范围函数声明为不是使用声明,或
  • 宣告既不是一个函数或函数模板

然后Y是空的。否则...

所以基本上,当普通的查找找到成员函数或本地(块范围)函数声明(或不是函数的东西)时,ADL不会启动。当普通的查找找到一个独立的命名空间范围函数时,或者根本没有发现任何东西时,它会启动。

+0

我会接受你的回答。但是我仍然不理解3.4.2p3中的例子:'g(parm,1)',1是一个int,而不是一个float! – Belloc

+0

在'main'中有'extern void g(NS :: T,float);'的局部(块范围)声明。这抑制了ADL,即每秒上面的项目符号点。 –