使用声明隐藏名称

时间:2016-03-09 14:54:08

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

#include <iostream>

struct H
{
    void swap(H &rhs); 
};    

void swap(H &, H &)
{
    std::cout << "swap(H &t1, H &t2)" << std::endl;
}

void H::swap(H &rhs)
{
    using std::swap;
    swap(*this, rhs);
}


int main(void)
{
    H a;
    H b;

    a.swap(b);
}

这就是结果:

swap(H &t1, H &t2)

在上面的代码中,我尝试定义H的交换函数。在函数void H::swap(H &rhs)中,我使用using声明使名称std :: swap可见。如果没有using声明,则无法编译代码,因为类H中没有可用的带有两个参数的交换函数。

我在这里有一个问题。在我看来,在我使用using声明 - using std::swap后,它只是使std :: swap - STL中的模板函数可见。所以我认为应该在H::swap()中调用STL中的交换。但结果显示调用了void swap(H &t1, H &t2)

所以这是我的问题:

  1. 为什么我不能在没有使用声明的情况下调用swap?(我想这是因为在类中没有带有两个参数的交换函数。但我不确定。)
  2. 为什么要调用我的定义的交换而不是H::swap中的STL交换?

1 个答案:

答案 0 :(得分:7)

  
      
  1. 为什么我不能在没有使用声明的情况下调用swap?
  2.   

我们从最近的封闭范围开始,然后向外工作直到我们发现某些东西。有了这个:

void H::swap(H &rhs)
{
    swap(*this, rhs);
}

不合格的swap找到H::swap()。然后我们做依赖于参数的查找。但是规则来自[basic.lookup.argdep]

  

X 成为非限定查找(3.4.1)生成的查找集,让 Y 成为由   参数依赖查找(定义如下)。如果 X 包含
   - 集体成员的声明,或
   - 块范围函数声明,它不是 using-declaration
   - 既不是功能模板也不是功能模板的声明
  那么 Y 是空的。否则 Y 是在与参数类型相关联的名称空间中找到的声明集,如下所述。 [...]

由于非限定查找集找到了一个类成员,因此依赖于参数的查找集为空(即,它找不到swap(H&, H&))。

  
      
  1. 为什么要调用我的定义的交换而不是H::swap中的STL交换?
  2.   

添加:

void H::swap(H &rhs)
{
    using std::swap;
    swap(*this, rhs);
}

现在不合格swap找到std::swap() H::swap(),因为前者是在更内部的范围内声明的。 using std::swap;与上述规则中任何导致 Y 为空的标准都不匹配(它不是类成员, a < em> using-declaration ,它是一个函数模板)。因此,依赖于参数的查找集确实包含在关联命名空间中找到的声明 - 其中包括swap(H&, H&)(因为H位于全局命名空间中)。我们最终得到了两个重载候选者 - 而你的首选是非首选,因为它是非模板。

有关将交换添加到班级的首选方式,请参阅Xeo's answer。基本上,你想写:

struct H {
    friend void swap(H&, H&) { ... }
};

这将由ADL(仅由ADL)发现。然后,当任何人调用交换正确时:

using std::swap;
swap(a, b);

查找会在适当的时候找到你的。