c ++普通查找与参数依赖查找

时间:2017-08-01 11:57:45

标签: c++ argument-dependent-lookup name-lookup

考虑http://en.cppreference.com/w/cpp/language/adl中描述的此示例:

namespace A {
      struct X;
      struct Y;
      void f(int);
      void g(X);
}

namespace B {
    void f(int i) {
        f(i);   // calls B::f (endless recursion)
    }
    void g(A::X x) {
        g(x);   // Error: ambiguous between B::g (ordinary lookup)
                //        and A::g (argument-dependent lookup)
    }
    void h(A::Y y) {
        h(y);   // calls B::h (endless recursion): ADL examines the A namespace
                // but finds no A::h, so only B::h from ordinary lookup is used
    }
}

我想知道为什么出现歧义,因为如果

不考虑ADL规则
  

"通常的非限定查找生成的查找集包含以下任何一个"。

这里B :: g可以通过http://en.cppreference.com/w/cpp/language/unqualified_lookup中解释的非限定查找找到,这要归功于规则

  

对于函数定义中使用的名称,无论是在其主体中还是作为default参数的一部分,其中函数是用户声明的或全局命名空间的成员,之前搜索使用该名称的块使用该名称,然后在该块的开始之前搜索封闭块等,直到到达作为函数体的块。然后搜索声明函数的名称空间,直到使用该名称的函数的定义(不一定是声明),然后是封闭的名称空间等。

然后我的问题是为什么在这种情况下会考虑ADL规则?

2 个答案:

答案 0 :(得分:6)

完整的引用是

  

首先,如果通常的非限定查找生成的查找集包含以下任何内容,则不考虑依赖于参数的查找:

     
      
  1. 类成员的声明
  2.   
  3. 块范围内的函数声明(不是使用声明)
  4.   
  5. 任何非函数或函数模板的声明(例如,函数对象或其名称与正在查找的函数名称冲突的其他变量)
  6.   

这意味着只有当非限定查找产生上述三个结果之一时,才会忽略ADL。由于我们不处理类成员,因此函数在命名空间范围内声明,而不是块作用域,我们只查找继续使用的函数并使用ADL。

答案 1 :(得分:1)

  

为什么在这种情况下会考虑ADL(参数依赖查找)规则?

因为关联的命名空间中可能存在更好的匹配。 E.g:

void f(void*);

namespace A {
struct X;
void f(X*);
}

int main() {
    A::X* x = 0;
    f(x); // A::f is the best match.
}

此机制通常用于swap function

  对于用户定义的类型,

std::swap可能专门用于名称空间std,但ADL找不到此类特化(名称空间std不是用户定义的关联名称空间类型)。 使用户定义类型可交换的预期方法是在与类型相同的命名空间中提供非成员函数交换:有关详细信息,请参阅Swappable。

     

此类型的任何左值或右值都可以与任何其他类型的左值或右值交换,在swap()和用户定义的{{1}的上下文中使用非限定函数调用std::swap s是可见的。