如何使用 std::string 作为 QHash 的键?
Posted
技术标签:
【中文标题】如何使用 std::string 作为 QHash 的键?【英文标题】:How to use std::string as key of QHash? 【发布时间】:2020-01-25 14:51:02 【问题描述】:我想使用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>&)
我应该如何解决这个问题?
【问题讨论】:
【参考方案1】:简答
Qt 6.1 及更新版本开箱即用支持使用std::string
作为键,因为Qt 现在使用std::hash
as a fallback 作为qHash
。
在std
命名空间内定义qHash
函数可能会解决编译器错误,但是adding a function to the std
namespace is undefined behaviour。所以,这是不允许的。
一种解决方法是将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);
长答案
正如bug report 中所述,必须在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() 函数在类型的命名空间返回键类型参数的哈希值。
但是,adding a function to the std
namespace is undefined behaviour。因此,使用不理想的解决方法会卡住。
进一步阅读
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/
【讨论】:
以上是关于如何使用 std::string 作为 QHash 的键?的主要内容,如果未能解决你的问题,请参考以下文章
我可以在所有 MSVC >= 2013 上安全地使用哪些 SFINAE 技巧?
使用 std::string 作为通用 uint8_t 缓冲区