m7913d
m7913d

Reputation: 11072

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

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?

Upvotes: 0

Views: 1439

Answers (1)

m7913d
m7913d

Reputation: 11072

Qt 6.1 and newer

Using std::string as a key is supported out of the box, as Qt now uses std::hash as a fallback for qHash.

Pre Qt 6.1

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

Upvotes: 2

Related Questions