qt中QMap的key值为结构体时,正确重写<方式

自己在项目中遇到了qmap中key值需要用到结构体,对结构体里多个值进行匹配,全部成功输出才value值。

查阅大量资料,结果不尽人意,查询时总有些漏洞,不完全正确。

自己仔细研究qmap后发现,这个是一个顺序存储的容器。顾名思义,就是比较大小,小的排放在前,大的排放在后。插入与读取时,比较key值是按照2分查找法来进行的。不废话了。直接上图。 

 附带了一个qdbug输出的重写,请看官一起笑纳。

代码解析:我就不解析了,强调一点,QString类型用compare比较结果不是-1,0,1。只用比较0就行了。如果真的看不懂,就把注释打开,看看qdebug的输出,就明白qmap的存入和输出逻辑了。

测试代码也给你们安排上,自行领悟。 

struct comkey{
        QString comname;
        int comgnm;
        int zhanhao;
        int addr;
        bool operator<(const comkey&comdata2) const
        {
            if( this->comname.compare(comdata2.comname) <0 ||this->comname.compare(comdata2.comname) >0)
            {
//                qDebug()<
<think>我们正在处理一个关于Qt类型注册的问题,特别是如何注册包含自定义结构体QMap类型。在Qt中,为了能够在信号和槽之间传递自定义类型,或者用于QVariant等,我们需要注册这些类型。对于QMap<Key, T>,如果Key或T是自定义类型,我们也需要注册。 步骤: 1. 首先,自定义结构体需要满足一定的条件(如可默认构造、可拷贝构造等),并且需要使用Q_DECLARE_METATYPE宏声明。 2. 然后,在运行使用qRegisterMetaType()注册该结构体类型。 3. 对于QMap<Key, T>,同样需要使用qRegisterMetaType()注册,并且如果Key或T是自定义类型,需要确保它们已经注册。 但是,注意:对于模板类,如QMap<Key, T>,我们需要使用`qRegisterMetaType<QMap<Key, T>>("QMap<Key,T>")`来注册。 另外,如果要在信号和槽中使用,还需要使用`qRegisterMetaType<QMap<Key, T>>()`(不带参数)来注册,以确保跨线程使用正确性。 具体步骤: 假设我们有一个自定义结构体: ```cpp struct MyStruct { int id; QString name; }; ``` 首先,在结构体定义后使用Q_DECLARE_METATYPE: ```cpp Q_DECLARE_METATYPE(MyStruct) ``` 然后,在main函数中(或在使用前)注册结构体QMap类型: ```cpp qRegisterMetaType<MyStruct>("MyStruct"); qRegisterMetaType<QMap<QString, MyStruct>>("QMap<QString,MyStruct>"); ``` 注意:如果需要在信号和槽中使用,特别是跨线程使用,建议使用: ```cpp qRegisterMetaType<QMap<QString, MyStruct>>(); ``` 但是,对于QMap这样的模板类,有可能会遇到编译错误,提示没有合适的默认构造函数等。这,我们需要确保在注册之前,该类型已经被完全定义。 另外,从Qt5开始,对于非基于QObject的类型,我们通常使用Q_DECLARE_METATYPE和qRegisterMetaType来注册。 但是,请注意:QVariant默认支持一些常见的类型,对于自定义类型,必须注册。 示例代码: 1. 定义结构体并声明元类型: 在头文件中(例如mystruct.h): ```cpp #include <QMetaType> #include <QString> #include <QMap> struct MyStruct { int id; QString name; // 为了方便,可以添加构造函数 MyStruct() : id(0) {} MyStruct(int id, const QString& name) : id(id), name(name) {} }; Q_DECLARE_METATYPE(MyStruct) // 注意:QMap类型不能在此处使用Q_DECLARE_METATYPE,因为它是模板类,且Q_DECLARE_METATYPE通常用于具体类型。 // 但是,我们可以使用模板特化来声明,不过通常我们直接使用qRegisterMetaType注册即可。 ``` 2. 在main函数中(或初始化代码中)注册: ```cpp #include "mystruct.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); // 注册结构体 qRegisterMetaType<MyStruct>(); // 注册QMap类型 qRegisterMetaType<QMap<QString, MyStruct>>("QMap<QString,MyStruct>"); // 如果需要在信号和槽中使用,尤其是跨线程,使用无参版本 qRegisterMetaType<QMap<QString, MyStruct>>(); // ... 其他代码 } ``` 注意:如果自定义结构体需要用于QVariant,那么必须使用Q_DECLARE_METATYPE声明,并且通常还需要使用qRegisterMetaType()进行注册(尽管在有些情况下,Q_DECLARE_METATYPE已经足够,但为了跨线程安全,建议注册)。 另外,如果自定义结构体包含的成员也是自定义类型,那么这些成员类型也需要注册。 如果遇到问题,比如编译错误或者运行无法识别类型,请检查: - 是否在头文件中使用了Q_DECLARE_METATYPE(MyStruct)? - 是否在初始化调用了qRegisterMetaType<MyStruct>()? - 对于QMap,是否正确地注册了模板实例? 最后,注意在信号和槽中使用自定义类型,connect函数中需要使用`Q_DECLARE_METATYPE`和`qRegisterMetaType`注册的类型,并且在connect指定参数类型为`QMap<QString, MyStruct>`。 相关问题: 1. 如何在Qt中注册一个自定义类型? 2. 为什么需要在Qt中注册自定义类型? 3. 在Qt中使用自定义类型作为信号/槽参数需要注意什么? 4. Q_DECLARE_METATYPE和qRegisterMetaType有什么区别?</think>### 在 Qt 中注册包含自定义结构体QMap 类型 在 Qt 中注册自定义类型需要两个关键步骤:使用 `Q_DECLARE_METATYPE` 声明类型,并在运行用 `qRegisterMetaType()` 注册。对于 `QMap<Key, CustomStruct>` 类型,需确保键类型(Key)和类型(CustomStruct)均已正确注册。 #### 完整步骤: 1. **定义自定义结构体**(需包含默认构造函数和拷贝构造函数) ```cpp // mystruct.h #include <QMetaType> #include <QString> struct MyCustomStruct { int id; QString name; // 必须提供默认构造函数 MyCustomStruct() : id(0) {} MyCustomStruct(int i, const QString& s) : id(i), name(s) {} }; ``` 2. **声明元类型** ```cpp // 在头文件末尾添加 Q_DECLARE_METATYPE(MyCustomStruct) Q_DECLARE_METATYPE(QMap<QString, MyCustomStruct>) // 示例:Key=QString ``` 3. **运行注册类型** ```cpp // main.cpp 或初始化代码中 #include "mystruct.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); // 注册自定义结构体 qRegisterMetaType<MyCustomStruct>("MyCustomStruct"); // 注册QMap类型 qRegisterMetaType<QMap<QString, MyCustomStruct>>("QMap<QString,MyCustomStruct>"); // 如果用于跨线程信号槽,需额外注册 qRegisterMetaType<QMap<QString, MyCustomStruct>>(); } ``` #### 关键注意事项: 1. **类型要求**: - 自定义结构体必须可拷贝(提供拷贝构造函数) - 必须包含默认构造函数 - 成员变量需使用 Qt 支持的类型(如 `int`、`QString` 等) 2. **信号槽使用**: ```cpp // 声明信号 signals: void mapUpdated(const QMap<QString, MyCustomStruct>& data); // 连接信号槽 QObject::connect(sender, &SenderClass::mapUpdated, receiver, &ReceiverClass::handleMap); ``` 3. **QVariant 转换**: ```cpp // 存储到QVariant QMap<QString, MyCustomStruct> myMap; QVariant variant = QVariant::fromValue(myMap); // 从QVariant取出 auto retrievedMap = variant.value<QMap<QString, MyCustomStruct>>(); ``` #### 常见问题排查: - **编译错误** "Type is not registered...": 1. 确认 `Q_DECLARE_METATYPE` 在头文件末尾 2. 检查 `qRegisterMetaType()` 是否在 `QApplication` 实例化后调用 3. 确保所有使用该类型的代码都包含结构体头文件 - **运行崩溃**: - 检查自定义结构体是否包含指针成员(需自行管理内存) - 确认跨线程传递使用 `Qt::QueuedConnection` > 引用[1]提到 Qt 模板库为性能优化减少了安全检查,因此开发者需自行确保类型操作的合法性[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值