这是VC 2010编译器的错误吗?

使用Visual Stu@R_404_410@ 2010 SP1:
#include <vector>

//namespace XXX {
  struct Test
  {
    bool operator==(const Test& r) const  { return true; }
  };
//}
//typedef XXX::Test Test;

template <typename T> inline bool operator!=(const T& l,const T& r) 
{ return !(l==r); }

int main()
{
  std::vector<Test> vt;
  std::vector<Test> vt2 = std::move(vt);
  return 0;
}

如果我按原样编译上面的代码,它会失败并显示以下错误

1>C:\apps\MVS10\VC\include\vector(609): error C2593: 'operator !=' is ambiguous
1>          C:\apps\MVS10\VC\include\xmemory(268): could be 'bool std::operator !=<_Ty,_Ty>(const std::allocator<_Ty> &,const std::allocator<_Ty> &) throw()'
1>          with
1>          [
1>              _Ty=Test
1>          ]
1>          test.cpp(11): or       'bool operator !=<std::allocator<_Ty>>(const T &,const T &)' [found using argument-dependent lookup]
1>          with
1>          [
1>              _Ty=Test,1>              T=std::allocator<Test>
1>          ]
1>          while trying to match the argument list '(std::allocator<_Ty>,std::allocator<_Ty>)'
1>          with
1>          [
1>              _Ty=Test
1>          ]
1>          C:\apps\MVS10\VC\include\vector(606) : while compiling class template member function 'void std::vector<_Ty>::_Assign_rv(std::vector<_Ty> &&)'
1>          with
1>          [
1>              _Ty=Test
1>          ]

… vector(609)解析为此行:

else if (get_allocator() != _Right.get_allocator())

OTOH,如果我取消注释名称空间与XXX相关的行,它会毫无怨言地编译.

我不得不认为这是一个编译器错误,但我正在寻找一些独立的验证.

编辑:只是作为解释,我第一次使用VS2010重新编译一些旧代码时遇到了这种情况.全球操作符从过去几年开始(现已删除).我只是无法理解为什么有些代码失败而其他代码没有.上面的代码是我对失败案例的精炼(显然,旧代码不会包含对std :: move()的调用).

更新:我记录了MS的一个错误,他们回答说这已经修复了“在编译器的下一个版本中” – 我认为这意味着Visual C 11.参见:http://connect.microsoft.com/VisualStudio/feedback/details/731692/regression-involving-global-operator-and-std-vector

解决方法

这是一个错误.

您决定为所有类型提供operator!=,这显然会导致与已经定义了这样的运算符的类型发生冲突.

在解析对运算符的调用期间的参数依赖查找!=在库实现[1]中的两个std :: allocator< Test>之间允许在尝试查找运算符时搜索Test的命名空间(以及std) !=使用[2].

所以:

>在破碎的情况下,该命名空间是全局命名空间,它还包含匹配的运算符!=.现在,这应该无关紧要,因为命名空间std中的函数是更好的匹配[3]; VS错误是提出歧义.
>但是当测试代替名称空间XXX(尽管是typedef)时,由于上述规则而搜索名称空间是名称空间XXX,其中不包含运算符!=的冲突定义.

在任何情况下,最好不要为所有类型定义运算符.

[1]你的行std :: vector< Test>的实现的某些部分. vt2 = std :: move(vt);在你的编译器/库impl上调用bool operator!=< std :: allocator< Test>>(const std :: allocator< Test>&,const std :: allocator< Test>&).

[2]引文如下:

[C++11: 3.4.2/1]: When the postfix-expression in a function call (5.2.2) is an unqualified-id,other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched,and in those namespaces,namespace-scope friend function declarations (11.3) not otherwise visible may be found. These modifications to the search
depend on the types of the arguments
(and for template template arguments,the namespace of the template argument).

[C++11: 3.4.2/2]: For each argument type T in the function call,there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are determined in the following way:

  • [..]
  • If T is a class type (including unions),its associated classes are: the class itself; the class of which it is a member,if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. Furthermore,if T is a class template specialization,its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces of which any template template arguments are members; and the classes of which any member templates used as template template arguments are members. [ Note: Non-type template arguments do not contribute to the set of associated namespaces. —end note ]
  • [..]

[3]引文如下:

[C++11: 13.3.3/1]: Given these definitions,a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i,ICSi(F1) is not a worse conversion sequence than ICSi(F2),and then:

  • [..]
  • F1 and F2 are function template specializations,and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.

[C++11: 14.5.6.2/2]: Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so,the more specialized template is the one chosen by the partial ordering process.

我的解释是,这个过程确定std中的函数比全局命名空间中的函数“更专业”,所以实际上不应该是歧义.

感谢@BoPeRSSon和@DavidRodríguez为您的回答做出的宝贵贡献.

相关文章

/** C+⬑ * 默认成员函数 原来C++类中,有6个默认成员函数: 构造函数 析构函数 拷贝...
#pragma once // 1. 设计一个不能被拷贝的类/* 解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运...
C类型转换 C语言:显式和隐式类型转换 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译...
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try...
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问...
目录&lt;future&gt;future模板类成员函数:promise类promise的使用例程:packaged_task模板类例程...