Название: [РЕШЕНО] перегрузка функции qHash
Отправлено: Yegor от Сентябрь 09, 2016, 16:05
Всем здравствуйте! Делаю хранилище в виде QHash. И ключ для него - свои пользовательские данные ( структура). Чтобы QHash работал с такими ключами, нужно перегрузить функцию qHash, в качестве аргумента которой кидается моя структура (ключ). Помогите, пожалуйста, мне с этим разобраться. А то сыпятся куча ошибок. Выкладываю минимальный компилированный проект. Функция mainC++ (Qt) #include <QtCore/QCoreApplication> #include <QtCore/QHash> #include <QtCore/QLatin1String> #include "Types.h" int main(int argc, char** argv) { QCoreApplication a(argc,argv); // QHash with custom type of key - 'SensorCode'. // Reimplement of the function 'qHash(SensorCode)' - in 'Types.h'. QHash<SensorCode,QLatin1String> storage; // !!! Instantiating by my custom kye type - 'SensorCode'. // Work with storage. SensorCode code(); storage[code] = QLatin1String("My sensor 1"); return a.exec(); } Заголовочный файл с пользовательскими типамиC++ (Qt) #ifndef TYPES_H #define TYPES_H #include <QtCore/QHash> // Sensor code - bytes 'CD', 'B1B0' in formular - sensor code relatevly the controller. struct SensorCode { quint8 cd; quint16 b1b0; // Null val. SensorCode() { this->cd=0; this->b1b0=0; } // Override of '=' operator. void operator= ( const SensorCode& other ) { this->cd = other.cd; this->b1b0 = other.b1b0; } }; // Override of 'operator=='. inline bool operator== (const SensorCode& code1, const SensorCode& code2); // Override of 'operator!='. inline bool operator!= (const SensorCode& code1, const SensorCode& code2); // Override of 'SensorCode' hashing. inline uint qHash (const SensorCode &code, uint seed = 0); #endif Файл реализации пользовательских типовC++ (Qt) #include "Types.h" // Override of 'operator=='. bool operator== (const SensorCode& code1, const SensorCode& code2) { if ( code1.cd != code2.cd ) return false; if ( code1.b1b0 != code2.b1b0 ) return false; return true; } // Override of 'operator!='. bool operator!= (const SensorCode& code1, const SensorCode& code2) { return ! ( code1 == code2 ); } // Override of 'SensorCode' hashing. inline uint qHash (const SensorCode &code, uint seed) { uint key = 0x00; key = ((uint)(code.cd))*0x10000; key += (uint)(code.b1b0); return qHash ( key, seed ); }
Ошибка высвечивается в файле main.cc на строке: QHash<SensorCode,QLatin1String> storage; // !!! Instantiating by my custom kye type - 'SensorCode'. И еще очень много предупреждений. Вот весь их список: 16:04:28: Выполняются этапы для проекта QHash... 16:04:28: Настройки не изменились, этап qmake пропускается. 16:04:28: Запускается: «C:\DevTools\Qt_4.8.6\MinGW-4.8.2-i686-posix-dwarf-rev3\mingw32\bin\mingw32-make.exe» C:/DevTools/Qt_4.8.6/MinGW-4.8.2-i686-posix-dwarf-rev3/mingw32/bin/mingw32-make -f Makefile.Release mingw32-make[1]: Entering directory 'D:/Projects/QtProjects/build-QHash-Qt_5_6-Release' g++ -c -pipe -fno-keep-inline-dllexport -O2 -std=gnu++0x -frtti -Wall -Wextra -fexceptions -mthreads -DUNICODE -DQT_NO_DEBUG -DQT_CORE_LIB -I..\QHash -I. -IC:\DevTools\Qt\5.6\mingw49_32\include -IC:\DevTools\Qt\5.6\mingw49_32\include\QtCore -Ibuild -IC:\DevTools\Qt\5.6\mingw49_32\mkspecs\win32-g++ -o build\main.o ..\QHash\main.cc ..\QHash\main.cc: In function 'int main(int, char**)': ..\QHash\main.cc:17:12: error: no match for 'operator[]' (operand types are 'QHash<SensorCode, QLatin1String>' and 'SensorCode()') storage[code] = QLatin1String("My sensor 1"); ^ ..\QHash\main.cc:17:12: note: candidates are: In file included from C:\DevTools\Qt\5.6\mingw49_32\include/QtCore/QHash:1:0, from ..\QHash\main.cc:2: C:\DevTools\Qt\5.6\mingw49_32\include/QtCore/qhash.h:721:22: note: T& QHash<Key, T>::operator[](const Key&) [with Key = SensorCode; T = QLatin1String] Q_INLINE_TEMPLATE T &QHash<Key, T>::operator[](const Key &akey) ^ C:\DevTools\Qt\5.6\mingw49_32\include/QtCore/qhash.h:721:22: note: no known conversion for argument 1 from 'SensorCode()' to 'const SensorCode&' C:\DevTools\Qt\5.6\mingw49_32\include/QtCore/qhash.h:715:27: note: const T QHash<Key, T>::operator[](const Key&) const [with Key = SensorCode; T = QLatin1String] Q_INLINE_TEMPLATE const T QHash<Key, T>::operator[](const Key &akey) const ^ C:\DevTools\Qt\5.6\mingw49_32\include/QtCore/qhash.h:715:27: note: no known conversion for argument 1 from 'SensorCode()' to 'const SensorCode&' Makefile.Release:220: recipe for target 'build/main.o' failed mingw32-make[1]: *** [build/main.o] Error 1 mingw32-make[1]: Leaving directory 'D:/Projects/QtProjects/build-QHash-Qt_5_6-Release' Makefile:34: recipe for target 'release' failed mingw32-make: *** [release] Error 2 16:04:30: Процесс «C:\DevTools\Qt_4.8.6\MinGW-4.8.2-i686-posix-dwarf-rev3\mingw32\bin\mingw32-make.exe» завершился с кодом 2. Ошибка при сборке/установке проекта QHash (комплект: Qt 5.6) Во время выполнения этапа «Сборка» 16:04:30: Прошло времени: 00:01.
Спасибо! [/code][/code]
Название: Re: перегрузка функции qHash
Отправлено: kambala от Сентябрь 09, 2016, 16:13
SensorAttributes::SensorCode code; // скобки не нужны
Название: Re: перегрузка функции qHash
Отправлено: Yegor от Сентябрь 09, 2016, 16:34
SensorAttributes::SensorCode code; // скобки не нужны Там скобки - сделать структуру по умолчанию (обнулить поля структуры), это реализовано в Types.ссЕсли убрать скобки, то при компилировании ошибки: ругается, что не может найти `qHash(SensorCode const&, unsigned int)'Вот полный перечень ошибок: D:\Projects\QtProjects\QHash\main.cc:-1: ошибка: undefined reference to `qHash(SensorCode const&, unsigned int)' D:\Projects\QtProjects\QHash\main.cc:-1: ошибка: undefined reference to `qHash(SensorCode const&, unsigned int)' :-1: ошибка: build/main.o: bad reloc address 0x120 in section `.text$_ZN5QHashI10SensorCode13QLatin1StringEixERKS0_[__ZN5QHashI10SensorCode13QLatin1StringEixERKS0_]' collect2.exe:-1: ошибка: error: ld returned 1 exit status Думаю, это распространенная задача, перегрузка qHash. Кто с этим сталкивался, помогите, пожалуйста.
Название: Re: перегрузка функции qHash
Отправлено: Yegor от Сентябрь 09, 2016, 16:44
Сейчас поубирал в коде везде ключевые слова ' inline'. И теперь нормально компилируется. Вывожу еще раз исходники, теперь уже нормальные. main.cc C++ (Qt) #include <QtCore/QCoreApplication> #include <QtCore/QHash> #include <QtCore/QLatin1String> #include "Types.h" int main(int argc, char** argv) { QCoreApplication a(argc,argv); QHash<SensorCode,QLatin1String> storage; SensorCode code; code.cd = 0; code.b1b0 = 0; storage[code] = QLatin1String("My sensor 1"); return a.exec(); } Types.hC++ (Qt) #ifndef TYPES_H #define TYPES_H #include <QtCore/QHash> //namespace SensorAttributes //{ // Sensor code - bytes 'CD', 'B1B0' in formular - sensor code relatevly the controller. struct SensorCode { quint8 cd; quint16 b1b0; // Null val. SensorCode() { this->cd=0; this->b1b0=0; } // Override of '=' operator. void operator= ( const SensorCode& other ) { this->cd = other.cd; this->b1b0 = other.b1b0; } }; //} // namespace SensorAttributes // Override of 'operator=='. bool operator== (const SensorCode& code1, const SensorCode& code2); // Override of 'operator!='. bool operator!= (const SensorCode& code1, const SensorCode& code2); // Override of 'SensorCode' hashing. uint qHash (const SensorCode &code, uint seed = 0); #endif Types.ccC++ (Qt) #include "Types.h" // Override of 'operator=='. bool operator== (const SensorCode& code1, const SensorCode& code2) { if ( code1.cd != code2.cd ) return false; if ( code1.b1b0 != code2.b1b0 ) return false; return true; } // Override of 'operator!='. bool operator!= (const SensorCode& code1, const SensorCode& code2) { return ! ( code1 == code2 ); } // Override of 'SensorCode' hashing. uint qHash (const SensorCode &code, uint seed) { uint key = 0x00; key = ((uint)(code.cd))*0x10000; key += (uint)(code.b1b0); return qHash ( key, seed ); }
Странно, в qt assistant там использовались эти функции с ' inline' и было нормально.[/code]
Название: Re: [РЕШЕНО] перегрузка функции qHash
Отправлено: Alex Custov от Сентябрь 09, 2016, 17:59
inline функции должны быть реализованы в том же заголовке, где они объявлены. Нельзя объявлять inline функцию в заголовке, и реализовывать её в cpp (TU). Вторая проблема, что SensorCode code(); - это объявление (declaration) функции с именем code, которая возвращает объект типа SensorCode. А вовсе не объект code созданный конструктором по-умолчанию.
Все проблемы - чистые проблемы с С++, может рановато за Qt браться?
Название: Re: перегрузка функции qHash
Отправлено: Yegor от Сентябрь 09, 2016, 18:33
А теперь, если переделать проект так, чтобы тип ключа засунуть в пространство имен namespace SensorAttributes { ... struct SensorCode { ... } ... } И использовать его в QHash. То при таком инстанцировании: QHash<SensorAttributes::SensorCode,QLatin1String> storage; При компиляции возникает ошибка: no matching function for call to 'qHash(const SensorAttributes::SensorCode&)' Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t))) ^ Хочется все же тип ключа засунуть в пространство имен, а иначе коряво тогда. Alex Custov, помогите, пожалуйста. Может тут тоже дело в чистом C++ :-X. Привожу листинг проекта, где добавлено пространство имен. main.ccC++ (Qt) #include <QtCore/QCoreApplication> #include <QtCore/QHash> #include <QtCore/QLatin1String> #include <QtDebug> #include "Types.h" int main(int argc, char** argv) { QCoreApplication a(argc,argv); // QHash с особым типом ключа - 'SensorCode'. // Перегрузка qHash(SensorCode) - в 'Types.h'. QHash<SensorAttributes::SensorCode,QLatin1String> storage; // Работа с хранилищем. SensorAttributes::SensorCode code1(0xaa,0xbbcc), code2(0x01,0x0203); storage[code1] = QLatin1String("My sensor 1"); storage[code2] = QLatin1String("My sensor 2"); qInfo() << "Key1:" << storage.value(code1,QLatin1String("none")); qInfo() << "Key2:" << storage.value(code2,QLatin1String("none")); QMetaObject::invokeMethod(&a,"quit",Qt::QueuedConnection); return a.exec(); } Types.hC++ (Qt) #ifndef TYPES_H #define TYPES_H #include <QtCore/QHash> namespace SensorAttributes { // Sensor code - bytes 'CD', 'B1B0' in formular - sensor code relatevly the controller. struct SensorCode { quint8 cd; quint16 b1b0; // Null val. SensorCode() { this->cd=0; this->b1b0=0; } SensorCode(quint8 arg1, quint16 arg2) { this->cd=arg1; this->b1b0=arg2; } // Override of '=' operator. void operator= ( const SensorCode& other ) { this->cd = other.cd; this->b1b0 = other.b1b0; } }; } // namespace SensorAttributes // Override of 'operator=='. bool operator== (const SensorAttributes::SensorCode& code1, const SensorAttributes::SensorCode& code2); // Override of 'operator!='. bool operator!= (const SensorAttributes::SensorCode& code1, const SensorAttributes::SensorCode& code2); // Override of 'SensorCode' hashing. uint qHash (const SensorAttributes::SensorCode &code, uint seed = 0); #endif Types.ccC++ (Qt) #include "Types.h" // Override of 'operator=='. bool operator== (const SensorAttributes::SensorCode& code1, const SensorAttributes::SensorCode& code2) { if ( code1.cd != code2.cd ) return false; if ( code1.b1b0 != code2.b1b0 ) return false; return true; } // Override of 'operator!='. bool operator!= (const SensorAttributes::SensorCode& code1, const SensorAttributes::SensorCode& code2) { return ! ( code1 == code2 ); } // Override of 'SensorCode' hashing. uint qHash (const SensorAttributes::SensorCode &code, uint seed) { uint key = 0x00; key = ((uint)(code.cd))*0x10000; key += (uint)(code.b1b0); return qHash ( key, seed ) ^ seed; }
Где ошибка?
Название: Re: перегрузка функции qHash
Отправлено: Igors от Сентябрь 10, 2016, 08:18
The qHash() hashing function
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.
Название: Re: перегрузка функции qHash
Отправлено: Yegor от Сентябрь 10, 2016, 10:24
Значит функция qHash должна располагаться в том же пространстве имен, где объявлен тип ключа. Переделал таким способом, и проект компилируется. Вот его исходники: main.ccC++ (Qt) #include <QtCore/QCoreApplication> #include <QtCore/QHash> #include <QtCore/QLatin1String> #include <QtDebug> #include "Types.h" int main(int argc, char** argv) { QCoreApplication a(argc,argv); // QHash с особым типом ключа - 'SensorCode'. // Перегрузка qHash(SensorCode) - в 'Types.h'. QHash<SensorAttributes::SensorCode,QLatin1String> storage; // Работа с хранилищем. SensorAttributes::SensorCode code1(0xaa,0xbbcc), code2(0x01,0x0203); storage[code1] = QLatin1String("My sensor 1"); storage[code2] = QLatin1String("My sensor 2"); qInfo() << "Key1:" << storage.value(code1,QLatin1String("none")); qInfo() << "Key2:" << storage.value(code2,QLatin1String("none")); QMetaObject::invokeMethod(&a,"quit",Qt::QueuedConnection); return a.exec(); } Types.hC++ (Qt) #ifndef TYPES_H #define TYPES_H #include <QtCore/QHash> namespace SensorAttributes { // Sensor code - bytes 'CD', 'B1B0' in formular - sensor code relatevly the controller. struct SensorCode { quint8 cd; quint16 b1b0; // Null val. SensorCode() { this->cd=0; this->b1b0=0; } SensorCode(quint8 arg1, quint16 arg2) { this->cd=arg1; this->b1b0=arg2; } // Override of '=' operator. void operator= ( const SensorCode& other ) { this->cd = other.cd; this->b1b0 = other.b1b0; } // Overrride of 'operator=='. bool operator== ( const SensorCode& code ) const { if ( this->cd != code.cd ) return false; if ( this->b1b0 != code.b1b0 ) return false; return true; } }; // Override of 'SensorCode' hashing. inline uint qHash ( const SensorCode &code, uint seed = 0 ) { uint key = 0x00; key = ((uint)(code.cd))*0x10000; key += (uint)(code.b1b0); return ::qHash ( key, seed ); } } // namespace SensorAttributes #endif
Спасибо большое, Igors. Задача решена.
|