我有一个简单的映射 std::map
auto cit = str_map_.find(str);
if (cit != str_map_.end()) {
...
}
在 'bool my_namespace::operator!=(const T1&, const T2&) 的实例化中 [with T1 = std::__detail::_Node_iterator
我将其调试为 my_namespace::MyType 的相当有创意的比较运算符:
template <class T>
struct MyType {
T* mt_;
};
struct MyTempClass {
std::string mtc_;
static int Compare(MyType<MyTempClass> const& lhs, MyType<MyTempClass> const& rhs) {
return lhs.mt_->mtc_.compare(rhs.mt_->mtc_);
}
static int Compare(std::string const& lhs, MyType<MyTempClass> const& rhs) {
return lhs.compare(rhs.mt_->mtc_);
}
static int Compare(MyType<MyTempClass> const& lhs, std::string const& rhs) {
return lhs.mt_->mtc_.compare(rhs);
}
};
template <class T1, class T2>
bool operator !=(T1 const& lhs, T2 const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
template <class T1, class T2>
bool operator ==(T1 const& lhs, T2 const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
static std::unordered_map<std::string, MyType<MyTempClass>> my_map;
但我仍然很困惑为什么会发生这种情况:相同的代码在普通映射上工作正常,并且值类型不应该参与迭代器比较?
最佳答案
您定义了一个operator!=
重载,它接受任何类型作为参数。该重载与类型 MyType
位于同一命名空间中。因此,可以通过 ADL 找到它。
如错误消息所示,标准库使用的 std::unordered_map
迭代器是类模板特化,专门针对 std::unordered_map
模板参数。因此,当您将迭代器与 !=
进行比较时,ADL 会对参数执行,并且 ADL 搜索的命名空间还包括参数类型的类型模板参数的命名空间。因此,您在 MyType
命名空间中的 operator!=
重载也将被发现并参与重载解析。
根据错误消息,假设您使用 libstdc++ 作为标准库实现,您可以查看 it's implementation哈希表迭代器的operator!=
,您将看到它为这些迭代器使用基类,并定义了对基类对象的引用的比较运算符。
因此,迭代器比较的标准重载需要在其参数中进行派生到基的引用转换,而您的重载则不需要。
因此,您的重载更好,并且将被选择进行 cit != str_map_.end()
比较。您的重载尝试传递参数 MyTempClass::Compare
,但这显然不起作用,因为这些函数不需要 std::unordered_map
迭代器。
解决方案是不要重载不依赖于用户定义类型的类型对的运算符。将重载限制为您自己的类型:
template <class T1, class T2>
bool operator !=(MyType<T1> const& lhs, T2 const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
template <class T1, class T2>
bool operator !=(T1 const& lhs, MyType<T2> const& rhs) {
int res = MyTempClass::Compare(lhs, rhs);
return (res != 0);
}
(相当于operator==
)。
据我所知,不禁止重载标准库类型对的运算符,但我也不认为标准库需要解决这在代码中产生的冲突。
使用 std::map
标准库实现可能会选择不同的方式来实现迭代器比较,这使得它更适合重载决策,或者避免 ADL 通过不进行重载来找到您的重载迭代器是专门针对键/值类型的模板。
关于c++ - unordered_map 迭代器比较中出现意外错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70559065/