提问人:ilovekonoka 提问时间:4/23/2013 最后编辑:curiousguyilovekonoka 更新时间:1/24/2017 访问量:12215
使用指令与在 C++ 中使用声明交换
using directive vs using declaration swap in C++
问:
请参考以下代码:
#include <algorithm>
namespace N
{
template <typename T>
class C
{
public:
void SwapWith(C & c)
{
using namespace std; // (1)
//using std::swap; // (2)
swap(a, c.a);
}
private:
int a;
};
template <typename T>
void swap(C<T> & c1, C<T> & c2)
{
c1.SwapWith(c2);
}
}
namespace std
{
template<typename T> void swap(N::C<T> & c1, N::C<T> & c2)
{
c1.SwapWith(c2);
}
}
如上所述,代码不会在 Visual Studio 2008/2010 上编译。错误是:
'void N::swap(N::C<T> &,N::C<T> &)' : could not deduce template argument for 'N::C<T> &' from 'int'.
但是,如果我注释掉 (1) 并取消注释 (2),它将编译正常。和 之间有什么区别可以解释这种行为?using namespace std
using std::swap
答:
注意:我已经删除了命名空间 std 中的交换定义。这里无关紧要。即使没有它,代码也会有同样的问题。
这是由于查找 () 和声明
之间的规则差异using directive
using namespace std
using
(using std::swap
)
如果是局部变量 与命名空间变量同名,命名空间变量为 隐藏。具有相同名称的命名空间变量是错误的 作为全局变量。
#include<iostream>
namespace T {
void flunk(int) { std::cout << "T";}
}
namespace V {
void flunk(int) { std::cout << "V";}
}
int main() {
using T::flunk; // makes T::flunk local
// using V::flunk; // makes V::flunk local. This will be an error
using namespace V; // V::flunk will be hidden
flunk(1);
}
据此,由于您的
template <typename T>
void swap(C<T> & c1, C<T> & c2)
std::swap
使用时会隐藏
using namespace std;
因此,唯一可用于模板推导的是,它不适用于 s,因为它需要 as 参数。swap
N::swap
int
template class
但不是什么时候
using std::swap;
在这种情况下,它等同于本地定义。并且可以毫无问题地使用。
评论
swap
swap
<algorithm>
swap
std
swap
using namespace std
显而易见的原因是 using 声明和 using
指令具有不同的效果。using 声明
立即将名称引入当前作用域,因此将名称引入本地作用域;
查找到此为止,您找到的唯一符号是 。
此外,这发生在定义模板时,所以稍后
找不到命名空间中的声明。在下文中
行,唯一要考虑的就是那条
在 中定义,加上 ADL 添加的那些(因此,一个
在命名空间中)。(但 VC++ 是这样吗?编译器
没有正确实现名称查找,所以谁知道呢。using std::swap
std::swap
std
swap
<algorithm>
N
using 指令指定名称将“好像”显示 它们在最近的命名空间中声明,将 指令和指定的命名空间;就您而言,全局 命名空间。它实际上并没有介绍这些名字;它 只是影响名称查找。在受抚养人的情况下 符号(或始终,在 VC++ 的情况下)发生在调用时 网站。
至于为什么你有这个特定的错误消息:可能更多 VC++ 的问题,因为肯定没有不可推导的 代码中的上下文。但没有理由期待两者 无论编译器如何,变体都具有相同的行为。
评论
using namespace x;
using x;
第一种情况是 using 指令 (),它的意思是命名空间中的名称将可用于在 和 当前范围的第一个公共命名空间中进行常规查找。在本例中,和 的第一个公共命名空间祖先是 ,因此 using 指令仅在查找命中 时才可用。using namespace X
X
X
::N
::std
::
std::swap
::
这里的问题是,当查找开始时,它会在函数内部查看,然后在类内部,然后在内部找到。由于检测到潜在的过载,因此常规查找不会继续到外部命名空间。因为是一个函数,编译器将执行 ADL(参数相关查找),但基本类型的关联命名空间集为空,因此不会带来任何其他重载。此时,查找完成,并开始解决过载问题。它将尝试将当前(单个)重载与调用匹配,并且无法找到从参数转换为参数的方法,并且您会收到错误。N
::N::swap
::
::N::swap
int
::N::C
另一方面,using 声明 () 在当前上下文中提供实体的声明(在本例中为函数本身)。查找将立即找到并停止常规查找并将使用它。using std::swap
std::swap
::std::swap
评论
N::swap
std::swap
using namespace std
std