VS2012中的ADL错误?

时间:2014-08-06 16:41:57

标签: c++ templates visual-studio-2012

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

以下是代码:

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 ++下编译,而不是警告。

1 个答案:

答案 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