c++ - unordered_map 迭代器比较中出现意外错误

标签 c++ unordered-map

我有一个简单的映射 std::map,我使用的是 c++11,因此出于性能原因我将其替换为 unordered_map。将迭代器与 end() 进行比较时出现以下错误。

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; T2 = 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/

相关文章:

unordered_map 上的 C++ 未定义行为作为基于范围的 for 循环中的右值

c++ - 使用 std::unordered_map 的散列函数有什么限制

c++ - 'catkin_make' 期间 ROS hydro opencv2 链接错误

c++ - 使用 ofstream 写入文件时出错

c++ - 我如何使 gtest 工作

c++ - 为什么 unordered_map 由于 "reserve"有足够的桶时会增加大小?

c++ - 使用 boost::unordered_map 作为查找表似乎非常慢

c++ - STL + typedefs 与 OOP,最佳实践?

c++ - g++ 4.4 中 std::atomic<const memberfunctionpointer*>::store() 的 undefined reference

c++ - unordered_map 元素被删除