Russian Qt Forum
Ноябрь 24, 2024, 15:38 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО] перегрузка функции qHash  (Прочитано 7576 раз)
Yegor
Гость
« : Сентябрь 09, 2016, 16:05 »

Всем здравствуйте!

Делаю хранилище в виде QHash. И ключ для него - свои пользовательские данные (структура). Чтобы QHash работал с такими ключами, нужно перегрузить функцию qHash, в качестве аргумента которой  кидается моя структура (ключ).

Помогите, пожалуйста, мне с этим разобраться. А то сыпятся куча ошибок. Выкладываю минимальный компилированный проект.

Функция main
Код
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 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]
« Последнее редактирование: Сентябрь 10, 2016, 10:24 от Yegor » Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #1 : Сентябрь 09, 2016, 16:13 »

SensorAttributes::SensorCode code; // скобки не нужны
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Yegor
Гость
« Ответ #2 : Сентябрь 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. Кто с этим сталкивался, помогите, пожалуйста.
Записан
Yegor
Гость
« Ответ #3 : Сентябрь 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.h
Код
C++ (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.cc
Код
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.
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]
« Последнее редактирование: Сентябрь 09, 2016, 18:21 от Yegor » Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #4 : Сентябрь 09, 2016, 17:59 »

inline функции должны быть реализованы в том же заголовке, где они объявлены. Нельзя объявлять inline функцию в заголовке, и реализовывать её в cpp (TU). Вторая проблема, что SensorCode code(); - это объявление (declaration) функции с именем code, которая возвращает объект типа SensorCode. А вовсе не объект code созданный конструктором по-умолчанию.

Все проблемы - чистые проблемы с С++, может рановато за Qt браться?
« Последнее редактирование: Сентябрь 09, 2016, 18:01 от Alex Custov » Записан
Yegor
Гость
« Ответ #5 : Сентябрь 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++  Рот на замке.

Привожу листинг проекта, где добавлено пространство имен.

main.cc
Код
C++ (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 &#1089; &#1086;&#1089;&#1086;&#1073;&#1099;&#1084; &#1090;&#1080;&#1087;&#1086;&#1084; &#1082;&#1083;&#1102;&#1095;&#1072; - 'SensorCode'.
   // &#1055;&#1077;&#1088;&#1077;&#1075;&#1088;&#1091;&#1079;&#1082;&#1072; qHash(SensorCode) - &#1074; 'Types.h'.
   QHash<SensorAttributes::SensorCode,QLatin1String> storage;
 
   // &#1056;&#1072;&#1073;&#1086;&#1090;&#1072; &#1089; &#1093;&#1088;&#1072;&#1085;&#1080;&#1083;&#1080;&#1097;&#1077;&#1084;.
   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.h
Код
C++ (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.cc

Код
C++ (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;
}
 

Где ошибка?
« Последнее редактирование: Сентябрь 09, 2016, 19:44 от Yegor » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Сентябрь 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.
Записан
Yegor
Гость
« Ответ #7 : Сентябрь 10, 2016, 10:24 »

Значит функция qHash должна располагаться в том же пространстве имен, где объявлен тип ключа.
Переделал таким способом, и проект компилируется.

Вот его исходники:

main.cc
Код
C++ (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.h
Код
C++ (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.

Задача решена.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.34 секунд. Запросов: 23.