请参考下面的代码:
#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),它会编译OK。 是什么区别using namespace std
和using std::swap
,解释这种行为?
第一种情况是用指令( using namespace X
),并且它的意思是,从命名空间中的名称X
将可以定期查询,在第一公共命名空间X
和电流范围。 在这种情况下,第一公共的命名空间的祖先::N
和::std
是::
,所以使用指令会使std::swap
仅当查找命中::
。
这里的问题是,查找启动时它会寻找里面的函数,那么类里面,那里面N
,它会找到::N::swap
在那里。 由于检测到潜在的过载,定期查找没有继续在外命名空间::
。 因为::N::swap
是一个函数,编译器会做ADL(参数依赖查找),但该组相关联的命名空间为基本类型是空的,所以不会带来任何其他重载。 在这一点上查找完成,并重载启动。 它会尝试匹配与呼叫当前(单)过载和它将无法找到转化的方式int
的说法::N::C
,你会得到错误。
在另一方面using声明( using std::swap
)提供在当前上下文中的实体的声明(在这种情况下,函数本身的内部)。 查找就会发现std::swap
立即停止定期查找与::std::swap
,并会使用它。
最明显的原因是,using声明和using指令有不同的效果。 using声明立即介绍了名称到当前的范围,因此using std::swap
介绍了名称到本地范围; 查找到此为止,你找到的唯一符号std::swap
。 此外,这发生在定义模板时,在空间中,因此后来的声明std
都没有发现。 在下面的行中, 只 swap
将要考虑的是在所定义的一个<algorithm>
那些由ADL(因此,一个命名空间中添加加N
)。 (不过,这是真的用VC ++?编译器不正确执行名称查找,所以谁知道。)
A,使用指令指定的名称将出现“好像”他们在封闭两个指令和提名命名最近的命名空间中声明; 在你的情况下,全局命名空间。 而实际上它并不引入的名字; 它只是影响名称查找。 这在相关符号的情况下(或总是在VC ++的情况下)发生在调用点。
至于为什么你有这个特殊的错误消息:可能更多的与VC ++的一个问题,因为肯定在你的代码没有非deduceable上下文。 但是,没有任何理由期待两个变体是具有相同的行为,无论编译器。
注 : 我已删除std下您的交换定义。 这是不是与此有关。 即使出它的代码都会有相同的问题。
这是由于查找之间差异的规则using directive
( using namespace std
)和using
declaration
( 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;
因此,只有在swap
可用模板扣除N::swap
,它不会对工作, int
,因为它预计A S template class
作为参数。
但不是当
using std::swap;
在这种情况下,它变成相当于本地定义 。 并且可以在没有问题地使用。