#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)
。
所以这是我的问题:
H::swap
中的STL交换?答案 0 :(得分:7)
- 为什么我不能在没有使用声明的情况下调用swap?
醇>
我们从最近的封闭范围开始,然后向外工作直到我们发现某些东西。有了这个:
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&)
)。
- 为什么要调用我的定义的交换而不是
醇>H::swap
中的STL交换?
添加:
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);
查找会在适当的时候找到你的。