'use of overloaded operator is ambiguous' 在带有 libc++ 的 Clang 中使用反向向量迭代器时
'use of overloaded operator is ambiguous' when using reverse vector iterators in Clang with libc++
据我了解 C++ ADL,这个编译错误是合法的。
但同时我不明白为什么这种失败只发生在 clang + libc++ 配置上,并且只发生在我们使用反向迭代器时。普通向量迭代器不会导致这种情况。
#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;
}
}
错误是:
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)
~~ ^ ~~~~~~~~
有谁知道是否可以使 clang + libc++ 配置的行为与其余配置(gcc、msvc)一样?
这里有一个关于 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
好吧,如果检查错误消息,就会发现操作数的实际类型是这个的一些变体
std::__1::reverse_iterator<std::__1::__wrap_iter<NS1::Foo *>>
它是一些用于生成反向迭代器的模板的实例。由于您了解 ADL,您知道当操作数是 class 模板特化时,关联的命名空间集也由模板参数的命名空间组成。这就是将您的 NS1::operator!=
考虑在内的原因。由于它是一个不受约束的函数模板,因此它可能是重载决议的可行候选者。因此冲突。
原因是前向迭代器不会发生,这可能取决于它们的实现细节。他们可以
- 不是某些模板本身的专业化。即,向量专业化的常规嵌套 classes。 vector 的关联名称空间不会继承。
- 根本就不是 class。矢量的迭代器可以实现为指向矢量缓冲区的简单指针。
我会认真地重新检查您对这种不受约束的 operator!=
的需求。这将是一种非常直接的解决问题的方法。
据我了解 C++ ADL,这个编译错误是合法的。 但同时我不明白为什么这种失败只发生在 clang + libc++ 配置上,并且只发生在我们使用反向迭代器时。普通向量迭代器不会导致这种情况。
#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;
}
}
错误是:
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)
~~ ^ ~~~~~~~~
有谁知道是否可以使 clang + libc++ 配置的行为与其余配置(gcc、msvc)一样?
这里有一个关于 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
好吧,如果检查错误消息,就会发现操作数的实际类型是这个的一些变体
std::__1::reverse_iterator<std::__1::__wrap_iter<NS1::Foo *>>
它是一些用于生成反向迭代器的模板的实例。由于您了解 ADL,您知道当操作数是 class 模板特化时,关联的命名空间集也由模板参数的命名空间组成。这就是将您的 NS1::operator!=
考虑在内的原因。由于它是一个不受约束的函数模板,因此它可能是重载决议的可行候选者。因此冲突。
原因是前向迭代器不会发生,这可能取决于它们的实现细节。他们可以
- 不是某些模板本身的专业化。即,向量专业化的常规嵌套 classes。 vector 的关联名称空间不会继承。
- 根本就不是 class。矢量的迭代器可以实现为指向矢量缓冲区的简单指针。
我会认真地重新检查您对这种不受约束的 operator!=
的需求。这将是一种非常直接的解决问题的方法。