我怀疑以下是编译器错误,但我正在寻找验证。我已经看到了其他类似的问题,但并不完全匹配。
以下是代码:
namespace my {
// using std::swap;
// Convenience utility
template<typename T> void doSwap(T& l, T& r)
{
using namespace std;
swap(l,r);
}
template<typename T> struct Container
{
T t;
void swap(Container<T>& r) { doSwap(this->t,r.t); }
};
// Specialize swap() for Container<T>
template<typename T> void swap(Container<T>& l, Container<T>& r)
{ l.swap(r); }
}
void stuff()
{
my::Container<int> one;
my::Container<int> two;
one.swap(two);
}
当我使用Visual Studio 2012编译它时,我收到以下错误:
error C2784: 'void my::swap(my::Container<T> &,my::Container<T> &)' : could not deduce template argument for 'my::Container<T> &' from 'int'
see reference to function template instantiation 'void my::doSwap<T>(T &,T &)' being compiled
with
[
T=int
]
如果我取消注释我的命名空间顶部的using std::swap
,它就可以了。无论哪种方式,相同的代码在clang和g ++下编译,而不是警告。
答案 0 :(得分:2)
是的,此代码有效。但是您的using namespace std;
应为using std::swap;
。目前在您的代码中,就好像在全局范围内声明了std::swap
函数一样(因为这是包含std
和{{1}的最小封闭范围所有声明在my
指令的范围内都可见。如果你在using namespace
之前移动了另一个swap
重载,那么Clang和GCC也会失败。
doSwap
在原始代码中,在符合标准的编译器上,这应该查找template<.....> void swap(....); // from namespace std
namespace my {
// using std::swap;
// Convenience utility
template<typename T> void doSwap(T& l, T& r)
{
using namespace std;
swap(l,r);
}
// ...
一次,并在全局命名空间中找到swap
。然后在实例化时,它应该再次查看调用,并注意调用参数是swap
,并且int
不存在ADL。在实例化时,不允许再次进行正常查找,而只允许进行ADL。因此,结果将保持全局int
并且事情将起作用。
但MSVC似乎在实例化时正常查找调用(也许是因为它的模板解析模型.MSVC在定义模板时不解析模板,但只有当它们用具体类型实例化时)。可能是名称空间swap
中当时可见的swap
重载会干扰并阻止查询考虑全局my
。