As far as I understand C++ ADL this compilation error is legit. But at the same time I dont understand why this failure happens only on clang + libc++ configuration, and only when we use reverse iterators. Normal vector iterators dont lead to this.
#include <vector>
#include <iostream>
namespace NS1
{
struct Foo
{
explicit Foo(const int i): m_i(i)
{}
bool operator==(const Foo& that) const
{
return this->m_i == that.m_i;
}
int m_i;
};
template <typename T>
bool operator!=(const T& a, const T& b)
{
return !(a == b);
}
}
int main(void)
{
std::vector<NS1::Foo> n;
// error: use of overloaded operator '!=' is ambiguous (with operand types 'std::__1::reverse_iterator
for(auto it = n.rbegin(); it != n.rend(); ++it)
{
std::cout<<it->m_i;
}
}
The error is:
error: use of overloaded operator '!=' is ambiguous (with operand types 'std::__1::reverse_iterator<std::__1::__wrap_iter<NS1::Foo *>>' and 'std::__1::vector<NS1::Foo, std::__1::allocator<NS1::Foo>>::reverse_iterator' (aka 'reverse_iterator<__wrap_iter<NS1::Foo *>>'))
for(auto it = n.rbegin(); it != n.rend(); ++it)
~~ ^ ~~~~~~~~
Does anyone know if it is possible to make clang + libc++ configuration behave like the rest of configurations (gcc, msvc)?
Here is a small example on godbolt: https://godbolt.org/z/8cKPY6
As far as I understand C++ ADL this compilation error is legit. But at the same time I dont understand why this failure happens only on clang + libc++ configuration, and only when we use reverse iterators. Normal vector iterators dont lead to this
Well, if one examines the error message, one sees the actual types of the operands are some variant of this
std::__1::reverse_iterator<std::__1::__wrap_iter<NS1::Foo *>>
It's an instance of some template that is used to generate the reverse iterators. Since you understand ADL, you know that the set of associated namespaces is composed also of the namespaces of template arguments, when an operand is a class template specialization. This is what pulls your NS1::operator!=
into consideration. Since it's an unconstrained function template, it could be a viable candidate for overload resolution. Hence the conflict.
The reason is doesn't occur with forward iterators is likely subject to their implementation details. They could
I'd seriously re-examine your need for such an unconstrained operator!=
. That would be a way to deal with the problem that is pretty straight-forward.