VS2012中的ADL错误

ADL bug in VS2012?

本文关键字:错误 ADL 中的 VS2012      更新时间:2023-10-16

我怀疑以下是编译器错误,但我正在寻找验证。我见过其他类似的问题,但不是完全匹配的。

代码如下:

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
          ]

如果取消my命名空间顶部的using std::swap的注释,它就可以工作。无论哪种方式,相同的代码在clang和g++下编译时都不会出现警告。

是,这段代码是有效的。但是using namespace std;应该是using std::swap;。目前在您的代码中,就好像在全局作用域中声明了std::swap函数(因为这是包含stdmy的最小封闭作用域)。对于using namespace指令,所有声明在该作用域中都是可见的。如果您在doSwap之前移动了另一个swap过载,那么Clang和GCC也会失败。

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,并且int不可能提供ADL。在实例化时,不允许再次执行普通查找,而只允许执行ADL。因此,结果将保持全局swap,并且事情将正常工作。

但是MSVC似乎也在实例化时对调用进行正常查找(可能是因为它的模板解析模型)。当模板被定义时,MSVC不解析模板,而只在使用具体类型实例化模板时解析。可能名称空间my中当时可见的swap重载会干扰并阻止查找考虑全局swap