Win*_*Ray 3 c++ swap using name-lookup argument-dependent-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);
}
Run Code Online (Sandbox Code Playgroud)
这就是结果:
swap(H &t1, H &t2)
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我尝试定义一个交换函数H.在函数中void H::swap(H &rhs),我使用using声明使名称std :: swap可见.如果没有using声明,则无法编译代码,因为类中没有可用的带有两个参数的交换函数H.
我在这里有一个问题.在我看来,在我使用using声明之后 - using std::swap它只是使std :: swap - STL中的模板函数可见.所以我认为应该调用STL中的交换H::swap().但结果显示,void swap(H &t1, H &t2)而是调用了它.
所以这是我的问题:
H::swap?
- 为什么我不能在没有使用声明的情况下调用swap?
我们从最近的封闭范围开始,然后向外工作,直到找到一些东西.有了这个:
void H::swap(H &rhs)
{
swap(*this, rhs);
}
Run Code Online (Sandbox Code Playgroud)
不合格的swap发现H::swap().然后我们做依赖于参数的查找.但是规则来自[basic.lookup.argdep]:
设X是由非限定查找(3.4.1)产生的查找集,并且让Y是由参数相关查找产生的查找集(定义如下).如果X包含
- 类成员的声明,或 -
不是using声明的块作用域函数声明,或者
- 既不是函数也不是函数模板的声明,
则Y为空.否则Y是在与参数类型相关联的名称空间中找到的声明集,如下所述.[...]
由于非限定查找集找到了一个类成员,因此依赖于参数的查找集为空(即,它找不到swap(H&, H&)).
- 为什么要调用我的定义的交换而不是调用STL交换
H::swap?
当你添加:
void H::swap(H &rhs)
{
using std::swap;
swap(*this, rhs);
}
Run Code Online (Sandbox Code Playgroud)
现在是不合格的swap发现std::swap()而不是 H::swap(),因为前者是在更内在的范围内宣布的.using std::swap;不符合上述规则中任何会导致Y为空的标准(它不是类成员,它是一个using声明,它是一个函数模板).因此,依赖于参数的查找集确实包含在关联命名空间中找到的声明 - 其中包括swap(H&, H&)(因为H它位于全局命名空间中).我们最终得到了两个重载候选者 - 而你的首选是非首选,因为它是非模板.
请参阅Xeo关于将swap添加到您的类的首选方法的答案.基本上,你想写:
struct H {
friend void swap(H&, H&) { ... }
};
Run Code Online (Sandbox Code Playgroud)
这将由ADL(仅由ADL)发现.然后每当有人调用 swap正确时:
using std::swap;
swap(a, b);
Run Code Online (Sandbox Code Playgroud)
Lookup会在适当的时候找到你的.