C++ 如何散列QVariant?

C++ 如何散列QVariant?,c++,qt,qvariant,stdhash,C++,Qt,Qvariant,Stdhash,我需要使用QList作为std::unordered_map的键。这样做的目的是通过在唯一键列上建立索引来优化对数据表的搜索 所以我做了这个代码。它不完整,但列出了表键列中出现的一些基本数据类型: #include <unordered_map> #include <string> //std::hash #include <functional> //std::size_t #include <cstddef> // Hashing method

我需要使用
QList
作为
std::unordered_map
的键。这样做的目的是通过在唯一键列上建立索引来优化对数据表的搜索

所以我做了这个代码。它不完整,但列出了表键列中出现的一些基本数据类型:

#include <unordered_map>
#include <string>
//std::hash
#include <functional>
//std::size_t
#include <cstddef>
// Hashing method for QVariantList
namespace std {
    template <>
    struct hash<QList<QVariant>>
    {
        std::size_t operator()(const QList<QVariant>& k) const
        {
            using std::size_t;
            using std::hash;
            using std::string;
            size_t hash_num = 0;
            Q_FOREACH(var, k) {
                // Make hash of the primitive value of the QVariant
                switch(var.type()) {
                    case QVariant::String : {
                        hash_num = hash_num^hash<string>(var.toString().toStdString());
                        break;
                    }
                    case QVariant::Char :
                    case QVariant::ULongLong :
                    case QVariant::UInt :
                    case QVariant::LongLong :
                    case QVariant::Int : {
                        hash_num = hash_num^hash<long long>(var.toLongLong());
                        break;
                    }
                    case QVariant::Double : {
                        hash_num = hash_num^hash<double>(var.toDouble());
                        break;
                    }
                }
            }
            return hash_num;
        }
    };
}
#包括
#包括
//散列
#包括
//标准:尺寸
#包括
//QVariantList的哈希方法
名称空间标准{
模板
结构散列
{
std::size\u t运算符()(常量QList&k)常量
{
使用std::size\u t;
使用std::hash;
使用std::string;
大小\u t哈希\u num=0;
Q_FOREACH(var,k){
//对QVariant的原语值进行哈希
开关(变量类型()){
大小写QVariant::字符串:{
hash_num=hash_num^hash(变量toString().tostString());
打破
}
案例QVariant::Char:
案例QVariant::ULongLong:
案例QVariant::UInt:
案例QVariant::LongLong:
案例QVariant::Int:{
hash_num=hash_num^hash(变量toLongLong());
打破
}
案例QVariant::Double:{
hash_num=hash_num^hash(变量toDouble());
打破
}
}
}
返回hash_num;
}
};
}
显然,我不喜欢整个
开关
的事情。它是相当长和丑陋的代码,只考虑基本类型。我宁愿对分配给
QVariant
的内部数据的内存数据进行散列。或者,更好的方法是使用一些Qt的散列方法

有没有一种半可靠的*方式来散列任何QVariant而不将其转换为基元类型


*我知道复杂的对象可能隐藏在QVariant后面,但这会导致冲突的情况非常罕见,所以我不必在意。

给自己找一个
QByteArray
+
QBuffer
+
QDataStream
基本上将
QVariant
序列化到
QByteArray

然后简单地散列字节数组中的原始字节。Qt已经为
QByteArray
实现了一个
qHash
函数,所以您已经准备好了

通过使用足够的预分配字节重用相同的
QByteArray
,可以最大限度地提高效率,以避免重新分配。您可以将整个内容包装在一个
VariantHasher
类中,在每次新哈希之前,只需对缓冲区进行
seek(0)
,只对
pos()
字节数进行哈希,而不是对整个内容进行哈希

class QVariantHasher {
  public:
    QVariantHasher() : buff(&bb), ds(&buff) {
      bb.reserve(1000);
      buff.open(QIODevice::WriteOnly);
    }
    uint hash(const QVariant & v) {
      buff.seek(0);
      ds << v;
      return qHashBits(bb.constData(), buff.pos());
    }
  private:
    QByteArray bb;
    QBuffer buff;
    QDataStream ds;
};
QVariantHasher类{
公众:
QVariantHasher():buff(&bb)、ds(&buff){
bb.储备(1000);
buff.open(QIODevice::WriteOnly);
}
uint散列(常量QVariant&v){
buff.seek(0);

ds您是否已经尝试过Qt的方法,如
QVariant::toHash()
?@Jean-Emmanuel将变量转换为
QHash
,并且不散列基础值。@Jean-Emmanuel
toHash
尝试将
QVariant
转换为
QHash
,这是一个散列映射,而不是散列。我的意思是,我对文档执行了Ctrl+F操作,此外,我还阅读了它的内容。如果您不担心的话关于性能:使用
QDataStream
QVariant
写入
QByteArray
并使用
qHash(const-QByteArray&)
函数。我还没有发现一种简单的方法可以获得
QVariant
的“原始”表示。您可以使用类似的访问者,然后将返回值传递给
qHash()
。在这种特殊情况下,我非常关心性能。你认为你的建议会比我制作的
开关慢吗?好吧,除非你将它们并排比较,否则无法判断。你需要它有多快?在我的系统上,它在15213纳秒内散列4个整数4个实数4个字符串和4个QRECT。还有一个修道院考虑到效率因素,您不必实现一个巨大的开关,它适用于所有支持序列化的类型。@TomášZato首先,如果您要使用
qHash
函数,您可以使
qHash
开关更友好。例如
var.toString().toststring()
可能比
qHash(var.toString())慢
因为您在堆中创建了一个带有分配的临时对象。第二步:试着比较一下。没有人知道
QDataStream
如何序列化
QVariant
。至少额外的
QByteArray
可以有一个很长的分配/解除分配时间。@TomášZato您可以专门处理我们最常见的类型对问题中的代码进行重新编译,然后返回到这个答案的方法,作为对您不想专门处理的类型的回退和未来验证。