使用声明隐藏名称
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)
被调用了。
所以这是我的问题:
- 为什么没有using声明我不能调用swap?(我猜是因为class中没有带两个参数的swap函数。但我不确定。)
- 为什么会调用我定义的交换而不是
H::swap
中的 STL 交换?
- 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&)
)。
- 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);
查找会在适当的地方找到您的。
#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)
被调用了。
所以这是我的问题:
- 为什么没有using声明我不能调用swap?(我猜是因为class中没有带两个参数的swap函数。但我不确定。)
- 为什么会调用我定义的交换而不是
H::swap
中的 STL 交换?
- 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&)
)。
- 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);
查找会在适当的地方找到您的。