我的困惑来自" C ++ Primer第5版"第13.3节,第518页。
非常谨慎的读者可能想知道为什么
using
内的swap
声明不会隐藏HasPtr
版本swap
的声明。
我试图阅读它的参考但仍然不明白为什么。有人可以解释一下吗?谢谢。以下是问题的代码示例。
假设班级Foo
有一个名为h
的成员,其成员类型为HasPtr
。
void swap(HasPtr &lhs, HasPtr &rhs)
{...}
void swap(Foo &lhs, Foo &rhs)
{
using std::swap;
swap(lhs.h, rhs.h);
}
为什么swap
HasPtr
未被隐藏,而using std::swap
位于内部范围内似乎是在外部范围内声明的?感谢。
答案 0 :(得分:10)
因为using std::swap;
并不意味着“从此以后,每个'交换'应该使用std::swap
”,但“将swap
的所有重载从std
带入当前范围” 。
在这种情况下,效果与在函数内部编写using namespace std;
的效果相同。
答案 1 :(得分:6)
using-declaration using std::swap
不会隐藏您声明为交换HasPtr
和Foo
的函数。它将名称swap
从std
命名空间带到声明性区域。有了这个,std::swap
可以参与重载决策。
来自C ++ 11标准:
7.3.3使用声明
1 using-declaration 在声明区域中引入了一个名称,其中出现了using声明。
using-declaration:
using typename
opt nested-name-specifier unqualified-id;
using ::
unqualified-id;using-declaration 中指定的成员名称在 using-declaration 出现的声明区域中声明。 [注意:只声明指定的名称;在 using-declaration 中指定枚举名称不会在 using-declaration 的声明性区域中声明其枚举数。 -end note ]如果 using-declaration 命名一个构造函数(3.4.3.1),它会在类中隐式声明一组构造函数,其中使用 - 宣言出现(12.9);否则 using-declaration 中指定的名称是在其他地方声明的某个实体的名称的同义词。
在您的情况下,您有:
void swap(Foo &lhs, Foo &rhs)
{
using std::swap;
swap(lhs.h, rhs.h);
}
using std::swap;
声明将swap
命名空间中的名称std
引入声明性区域,该区域是swap(Foo&, Foo&)
函数的主体。全局命名空间中的名称swap
仍可在函数体中访问。
如果你发布的是整个功能,那么你就不需要using std::swap
声明。你可以只用:
void swap(Foo &lhs, Foo &rhs)
{
swap(lhs.h, rhs.h);
}
因为函数可以看到swap(HasPtr &lhs, HasPtr &rhs)
。
现在,看一下下面的例子。
struct Bar {};
void swap(Bar& lhs, Bar& rhs)
{
}
struct Foo
{
int a;
Bar b;
};
void swap(Foo& lhs, Foo& rhs)
{
swap(lhs.a, rhs.a); // A problem
swap(lhs.b, rhs.b);
}
标记为A problem
的行是一个问题,因为没有名为swap
的函数可以使用两个类型为int&
的对象作为参数。您可以使用以下方法之一解决此问题:
明确使用std::swap
。
void swap(Foo& lhs, Foo& rhs)
{
std::swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
在函数中引入std::swap
。
void swap(Foo& lhs, Foo& rhs)
{
using std::swap;
swap(lhs.a, rhs.a);
swap(lhs.b, rhs.b);
}
答案 2 :(得分:0)
Scott Meyers的有效C ++第三版(第24项)
当编译器看到对swap的调用时,他们会搜索正确的swap 调用。 C ++的名称查找规则确保这将找到任何 特定于T的交换在全局范围或与该类型相同的命名空间中 吨。
在这种情况下,在第二个代码块中,编译器会查找HasPtr交换,如果找不到它们,它们将回退到std中的通用版本。
答案 3 :(得分:0)
using声明意味着考虑所有std :: swap重载,就好像它们是在与函数相同的命名空间中定义的一样。由于using声明出现在函数体中,因此它只会暂时生效:在该范围内。
它与以下内容相同:
isPalindrome()
定期的重载规则确保第一个交换是被调用的交换。这与声明一个名为" swap"的局部变量形成对比,其中将隐藏第一个重载。
答案 4 :(得分:0)
实际上,HasPtr的swap
在内部范围内隐藏using std::swap
,但在这种情况下,内部范围中的std::swap
与swap
相同对于外部范围内的HasPtr。