PDA

View Full Version : QHash add comparison function, how?



holst
30th March 2010, 08:09
Hi,

In std::map (stl) you can define the key and value types, but also the comparison function for the keys.
I want to do the same for a QHash, but I reading QtAssistant and googling and the only things I can define are key and value type.

Can I set the comparison function for a QHash? If yes, how?

Thanks.

spud
30th March 2010, 08:21
You not only can, but you have to define the function:


quint32 qHash(const Key &key);

unless you're working with some standard type, for which the function already has been provided.

holst
30th March 2010, 09:03
I'm using a QPair as a key, and I want to use another comparison function and not the given one.
I tried to derived QPair an use it as a key:


template <class T1, class T2>
struct stEvPairKey : QPair<T1, T2>
{
stEvPairKey() : QPair<T1, T2>() {}
stEvPairKey(const T1 &t1, const T2 &t2) : QPair<T1, T2>(t1, t2) {}
};
template <class T1, class T2>
bool operator==(const stEvPairKey<T1, T2> &p1, const stEvPairKey<T1, T2> &p2)
{
return (p1.first == p2.first) && (p1.second & p2.second);
}


and use this struct as a key:


QHash<stEvPairKey<int, unsigned long>, CMyClass*> m_hash;


But never goes into my "operator==".
The function you give:


quint32 qHash(const Key &key);

is to compute the hash value for the key, but not to compare 2 keys.

What is wrong?

Thank you.

wysota
30th March 2010, 09:07
Doesn't QPair have the operator already defined the way you defined it?

spud
30th March 2010, 10:14
As you will see in the following program, both the equality operator and the hash function get called.

#include <QHash>
#include <QDebug>

template <class T1, class T2>
struct stEvPairKey : QPair<T1, T2>
{
stEvPairKey() : QPair<T1, T2>() {}
stEvPairKey(const T1 &t1, const T2 &t2) : QPair<T1, T2>(t1, t2) {}
};
template <class T1, class T2>
bool operator==(const stEvPairKey<T1, T2> &p1, const stEvPairKey<T1, T2> &p2)
{
qDebug()<<"comparison";
return (p1.first == p2.first) && (p1.second & p2.second);
}
template <class T1, class T2>
quint32 qHash(const stEvPairKey<T1,T2>&key)
{
qDebug()<<"hash";
return qHash((QPair<T1,T2>)key);
}
void main()
{

QHash<stEvPairKey<int, unsigned long>, bool> m_hash;
m_hash.insert(stEvPairKey<int, unsigned long>(1, 2), true);
if(m_hash.contains(stEvPairKey<int, unsigned long>(1, 2)))
qDebug()<<"true";
}
Although, as Wysota pointed out, both functions are unnecessary because QPair provides those functions.

wysota
30th March 2010, 10:44
By the way... qHash() is for comparing two keys.

holst
30th March 2010, 11:29
ok, at last I understand what is happening.
The second part of the key T2 are some flags. For example this code


#include <QtCore/QCoreApplication>

#include <QMultiHash>
#include <QDebug>
#include <QString>

template <class T1, class T2>
struct stEvPairKey : QPair<T1, T2>
{
stEvPairKey() : QPair<T1, T2>() {}
stEvPairKey(const T1 &t1, const T2 &t2) : QPair<T1, T2>(t1, t2) {}
};
template <class T1, class T2>
bool operator==(const stEvPairKey<T1, T2> &p1, const stEvPairKey<T1, T2> &p2)
{
qDebug()<<"comparison";
return (p1.first == p2.first) && (p1.second & p2.second);
}
template <class T1, class T2>
quint32 qHash(const stEvPairKey<T1,T2>&key)
{
qDebug()<<"hash: " << qHash((QPair<T1,T2>)key);
return qHash((QPair<T1,T2>)key);
}

enum EFlags
{
NONE_FLAGS = 0,

FLAG1 = 1,
FLAG2 = 2,
FLAG3 = 4,
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QHash<stEvPairKey<int, unsigned long>, bool> m_hash;
m_hash.insert(stEvPairKey<int, unsigned long>(1, FLAG1 | FLAG3), true);
if(m_hash.contains(stEvPairKey<int, unsigned long>(1, FLAG1)))
qDebug()<<"FLAG1: true";
if(m_hash.contains(stEvPairKey<int, unsigned long>(1, FLAG1 | FLAG3)))
qDebug()<<"FLAG1 | FLAG3: true";

return a.exec();
}


The output is:


hash: 65541
hash: 65541
hash: 65537
hash: 65541
comparison
FLAG1 | FLAG3: true


My idea was to implement the operator== for stEvPairKey so the 1st "if()" be also true. But as is shown in the output the hash value is different for "FLAG1" and for "FLAG1 | FLAG3".
I was confused, the flags can't be part of the hash key.

Thank you very much :)

wysota
30th March 2010, 13:51
Maybe they should be a part of value and not the key then?

holst
30th March 2010, 15:38
Yes, that's right.
I made the change and works. I was confused, I was only thinking in the comparison function, when "contains()" is called, and no the "qHash()".

Thank you again.

wysota
30th March 2010, 19:49
QHash::contains() will call qHash() for the key.