如何使用 std::string 作为 QHash 的键?

How to use std::string as key of QHash?

本文关键字:QHash 的键 作为 string 何使用 std      更新时间:2023-10-16

我想使用std::string作为QHash的键:

QHash<std::string, QString> m_hash;
m_hash.insert("ABC", "DEF");

我实现了所需的qHash:

inline qHash(const std::string& key, uint seed = 0)
{
qHash(QByteArray::fromRawData(key.data(), key.length()), seed);
}

一切都使用 MSVC 正确编译,但 gcc 生成以下错误:

错误:调用qHash(const std::__cxx11::basic_string<char>&)没有匹配函数

我应该如何解决这个问题?

Qt 6.1 及更高

版本开箱即用地支持使用std::string作为键,因为Qt现在使用std::hash作为qHash的后备。

Qt 6.1 之前

简答题

std命名空间内定义qHash函数可能会解决编译器错误,但将函数添加到std命名空间是未定义的行为。所以,这是不允许的。

解决方法是将std::string包装在帮助程序类[1]中:

class MyHashString : public std::string {};
QHash<MyHashString, QString> m_hash;
m_hash.insert("ABC", "DEF");
inline qHash(const MyHashString& key, uint seed = 0)
{
qHash(QByteArray::fromRawData(key.data(), key.length()), seed);
}

长答案

如此错误报告中所述,必须在std::string的命名空间内定义qHash函数:

这记录在C++标准中。它称为参数相关查找。它说搜索非限定的qHash(T(将在T的命名空间中找到它。

因此,所需qHash的正确定义是:

namespace std
{
inline qHash(const std::string& key, uint seed = 0)
{
qHash(QByteArray::fromRawData(key.data(), key.length()), seed);
}
}

Qt文档中也提到了这一点:

QHash的键类型除了是可分配的数据类型之外,还有其他要求:它必须提供operator==((,并且该类型的命名空间中还必须有一个qHash((函数,该函数返回键类型的参数的哈希值。

但是,std命名空间添加函数是未定义的行为。因此,人们坚持使用非理想的解决方法。

延伸阅读

  • https://en.wikipedia.org/wiki/Argument-dependent_name_lookup
  • https://en.cppreference.com/w/cpp/language/adl
  • 关于qHash重载的有趣文章:https://www.kdab.com/how-to-declare-a-qhash-overload/