Using Visual Studio 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;
}
If I compile the code above as is, it fails with this error:
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> ]
… where vector(609) resolves to this line:
else if (get_allocator() != _Right.get_allocator())
OTOH, if I uncomment the namespace XXX-related lines, it compiles without complaint.
I have to think this is a compiler bug but I’m looking for some independent verification.
EDIT: Just by way of explanation, I came across this situation when recompiling some old code with VS2010 for the first time. The global operator was some cruft from years past (now removed). I just couldn’t understand why some code failed and others didn’t. The code above is my distillation of the failed case (obviously, old code would not contain calls to std::move()).
UPDATE: I logged a bug with MS and they responded that this has been fixed “in the next release of the compiler” – which I presume means Visual C++ 11. See: http://connect.microsoft.com/VisualStudio/feedback/details/731692/regression-involving-global-operator-and-std-vector
It’s a bug.
You’ve decided to provide
operator!=for all types ever which is obviously going to cause conflicts with types which already have such an operator defined.Argument Dependent Lookup during the resolution of a call to
operator!=between twostd::allocator<Test>s inside your library implementation [1] allows the namespace ofTestto be searched (as well asstd) when trying to find theoperator!=to use [2].So:
in your broken case, that namespace is the global namespace, which also contains a
operator!=that matches. Now, this shouldn’t matter, because the function in namespacestdis a better match [3]; the VS bug is that an ambiguity is raised instead.but when
Testis instead in namespaceXXX(despite thetypedef), the namespace searched due to the above rule is instead the namespaceXXX, which contains no conflicting definition foroperator!=.Best not define operators for all types ever like that, in any case.
[1] Some part of the implementation for your line
std::vector<Test> vt2 = std::move(vt);on your compiler/library impl is invokingbool operator!=<std::allocator<Test>>(const std::allocator<Test>&, const std::allocator<Test>&).[2] Citations follow:
[3] Citations follow:
My interpretation is that this process determines that the function in
stdis “more specialised” than the one in the global namespace, so there in fact should not be an ambiguity.Thanks @BoPersson and @DavidRodríguez for your valuable contributions to this kick-ass answer.