#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 typeT
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,ifT
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 functionF1
is defined to be a better function than another viable functionF2
if for all argumentsi
,ICSi(F1)
is not a worse conversion sequence thanICSi(F2)
,and then:
- [..]
F1
andF2
are function template specializations,and the function template forF1
is more specialized than the template forF2
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为您的回答做出的宝贵贡献.