使用声明隐藏名称

Name hiding by using declaration

#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 声明,则无法编译代码,因为 class H 中没有可用的带两个参数的交换函数。

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

所以这是我的问题:

  1. 为什么没有using声明我不能调用swap?(我猜是因为class中没有带两个参数的swap函数。但我不确定。)
  2. 为什么会调用我定义的交换而不是 H::swap 中的 STL 交换?
  1. Why can't I invoke swap without a using declaration?

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

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

不合格 swap 找到 H::swap()。然后我们进行参数依赖查找。但规则是,从 [basic.lookup.argdep]:

Let X be the lookup set produced by unqualified lookup (3.4.1) and let Y be the lookup set produced by argument dependent lookup (defined as follows). If X contains
— a declaration of a class member, or
— a block-scope function declaration that is not a using-declaration, or
— a declaration that is neither a function or a function template
then Y is empty. Otherwise Y is the set of declarations found in the namespaces associated with the argument types as described below. [...]

由于非限定查找集找到了 class 成员,因此依赖于参数的查找集为空(即没有找到 swap(H&, H&))。

  1. Why will the swap of my definition be invoked instead of the STL swap in the H::swap?

当您添加:

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

now unqualified swap 找到 std::swap()not H::swap(),因为前者是在更内部的范围内声明的。 using std::swap; 不符合上述规则中任何导致 Y 为空的条件(它不是 class 成员,它 一个using-declaration,它是一个函数模板)。因此,依赖于参数的查找集确实包含在关联命名空间中找到的声明 - 其中包括 swap(H&, H&)(因为 H 在全局命名空间中)。我们最终有两个过载候选者——你的是首选,因为它是非模板。


请参阅 Xeo's answer 了解将交换添加到 class 的首选方法。基本上,你想写:

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

这将由 ADL 找到(并且只能由 ADL 找到)。然后每当有人 呼叫 交换正确:

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

查找会在适当的地方找到您的。