I want to use a std::string
as the key of a QHash
:
QHash<std::string, QString> m_hash;
m_hash.insert("ABC", "DEF");
I implemented the required qHash:
inline qHash(const std::string& key, uint seed = 0)
{
qHash(QByteArray::fromRawData(key.data(), key.length()), seed);
}
Everything compiles correctly using MSVC, but gcc generates the following error:
error: no matching function for call to
qHash(const std::__cxx11::basic_string<char>&)
How should I resolve this isse?
Using std::string
as a key is supported out of the box, as Qt now uses std::hash
as a fallback for qHash
.
Short answer
Defining the qHash
function inside the std
namespace may resolve the compiler error, but adding a function to the std
namespace is undefined behaviour. So, it is not allowed.
A workaround is to wrap std::string
inside a helper class[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);
}
Long Answer
As stated in this bug report, one has to define the qHash
function inside the namespace of std::string
:
This is documented in the C++ standard. It's called Argument-Dependent Lookup. It says that searching for an unqualified qHash(T) will find it in T's namespace.
So, the correct definition of the required qHash
would be:
namespace std
{
inline qHash(const std::string& key, uint seed = 0)
{
qHash(QByteArray::fromRawData(key.data(), key.length()), seed);
}
}
It is also mentioned in the Qt docs:
A QHash's key type has additional requirements other than being an assignable data type: it must provide operator==(), and there must also be a qHash() function in the type's namespace that returns a hash value for an argument of the key's type.
However, adding a function to the std
namespace is undefined behaviour. So, one is stuck using a non-ideal workaround.
Further reading
qHash
overloading: https://www.kdab.com/how-to-declare-a-qhash-overload/