ilo*_*oka 14 c++ swap using-directives using-declaration
请参考以下代码:
#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);
}
}
Run Code Online (Sandbox Code Playgroud)
如上所述,代码无法在Visual Studio 2008/2010上编译.错误是:
'void N::swap(N::C<T> &,N::C<T> &)' : could not deduce template argument for 'N::C<T> &' from 'int'.
Run Code Online (Sandbox Code Playgroud)
但是,如果我注释掉(1)并取消注释(2),它将编译好.是什么区别using namespace std,并using std::swap解释了这种行为?
Dav*_*eas 24
第一种情况是using指令(using namespace X),它的含义是命名空间中的名称X可用于常规查找,在第一个公共名称空间X和当前作用域中.在这种情况下,第一公共的命名空间的祖先::N和::std是::的,所以使用指令将使得std::swap只有当查找命中可用::.
这里的问题是,当查找开始时,它将查看函数内部,然后在类内部,然后在内部N,它将在::N::swap那里找到.由于检测到潜在的重载,因此常规查找不会继续到外部命名空间::.因为::N::swap是一个函数,编译器将执行ADL(参数依赖查找),但基本类型的关联命名空间集是空的,因此不会带来任何其他重载.此时查找完成,并开始重载解析.它将尝试将当前(单个)重载与调用匹配,它将无法找到转换int为参数的方法,::N::C并且您得到错误.
另一方面,using declaration(using std::swap)提供当前上下文中实体的声明(在本例中是函数本身).查找将std::swap立即找到并停止定期查找::std::swap并将使用它.
显而易见的原因是using声明和using指令具有不同的效果.using声明会立即将名称引入当前作用域,因此
using std::swap将名称引入本地作用域; 查找在此停止,您找到的唯一符号是std::swap.此外,这在定义模板时发生,因此std未找到命名空间中的后续声明.在下面的行中,唯一 swap考虑的是,在<algorithm>ADL中添加的那些(因此,命名空间中的那个N).(但这对VC++是否正确?编译器没有正确实现名称查找,所以谁知道.)
using指令指定名称将显示为"好像"它们是在最近的命名空间中声明的,该命名空间包含指令和指定的命名空间; 在您的情况下,全局命名空间.它实际上没有引入名称; 它只会影响名称查找.在依赖符号的情况下(或者总是在VC++的情况下)发生在呼叫站点.
至于为什么你有这个特殊的错误信息:VC++可能更多的问题,因为在你的代码中肯定没有不可推断的上下文.但无论编译器如何,都没有理由期望这两个变体具有相同的行为.
| 归档时间: |
|
| 查看次数: |
8370 次 |
| 最近记录: |