Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Initialize a QHash



  • Hi,
    this might be a noob question and I am not sure if it's rather about how QHash's initializer lists work / don't work or perhaps just about the basic c++ means of list initialization.

        Note test0 = Note("f","#",4);
    
        QHash<QVector<int>, QVector<int>> test1{ {QVector<int>{1,2,3}, QVector<int>{1,2,3} } };
    
        QHash<Note, QVector<int>> test3;
    
        QHash<Note, QVector<int>> test4{ {Note("f","#",4), QVector<int>{1,2,3} } };
    

    The first three variables are initialized without problems. But "test4" gives a mess of build errors, the most sensible being:

    C:/Qt/5.15.0/mingw81_64/include/QtCore/qhashfunctions.h:118:28: error: no matching function for call to 'qHash(const Note&)'
         noexcept(noexcept(qHash(t)))
    

    I don't understand this error message.
    The non-default constructor of the class Note is

    Note::Note(QString name, QString accidental, int midiOctave, Note::Duration duration, bool dotted)
    {
        m_name = name;
        m_accidental = accidental;
        m_midiOctave = midiOctave;
        m_duration = duration;
        m_dotted = dotted;
    }
    

    Is what I try to achieve possible? Can I change the Constructor or write an additional one for this purpose?


  • Lifetime Qt Champion

    @SeDi said in Initialize a QHash:

    no matching function for call to 'qHash(const Note&)'

    Isn't this obvious enough? It's also in the docs: The key type of a QHash must provide operator==() and a global hash function called qHash().



  • Ouch. Thank you. I have missed that. Sorry. Thank you very much!



  • Unfortunately I still can't get it to work. I have defined an:

    inline bool operator==(const Note &n2) const { return n2.midiNumber() == this->midiNumber(); }
    

    This compiles well, at least as long as I comment out:

    //QHash<Note, QVector<int>> test4{ {Note("f","#",4), QVector<int>{1,2,3} } };
    

    I have tried dozens of versions and places for my:

    uint qHash(const Note& key, uint seed = 0) {
        Q_UNUSED(seed)
        return uint(key.midiNumber());
    }
    

    It is now located in Note.h right after the end of the class definition. Shortened declaration:

    #ifndef NOTE_H
    #define NOTE_H
    #include <QHash>
    class Note
    {
    public:
        explicit Note();
        Note(QString name, QString accidental, int midiOctave, Note::Duration duration = Note::Duration::WHOLE, bool dotted = false);
        int midiNumber() const;
        inline bool operator==(const Note &n2) const { return n2.midiNumber() == this->midiNumber(); }
    private:
        QString m_name = "c";
        QString m_accidental = "";
        int m_midiOctave = 5;
    };
    /// after class definition has ended:
    uint qHash(const Note& key, uint seed = 0) {
        Q_UNUSED(seed)
        return uint(key.midiNumber());
    }
    #endif // NOTE_H
    

    I get this build error log (test4 still commented out):

    debug/main.o: In function `qHash(Note const&, unsigned int)':
    C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: multiple definition of `qHash(Note const&, unsigned int)'
    debug/controller.o:C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: first defined here
    debug/note.o: In function `std::operator&(std::memory_order, std::__memory_order_modifier)':
    C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: multiple definition of `qHash(Note const&, unsigned int)'
    debug/controller.o:C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: first defined here
    debug/task.o: In function `operator new(unsigned long long, void*)':
    C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: multiple definition of `qHash(Note const&, unsigned int)'
    debug/controller.o:C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: first defined here
    debug/moc_controller.o: In function `QHash<int, QHashDummyValue>::concrete(QHashData::Node*)':
    C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/debug/../../BrassTutor/note.h:71: multiple definition of `qHash(Note const&, unsigned int)'
    debug/controller.o:C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: first defined here
    debug/moc_task.o: In function `QMetaObject const* QMetaObject::staticMetaObject<QObject::staticMetaObject>()':
    C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/debug/../../BrassTutor/note.h:71: multiple definition of `qHash(Note const&, unsigned int)'
    debug/controller.o:C:\Users\SeDi\cpp\build-BrassTutor-Desktop_Qt_5_15_0_MinGW_64_bit-Debug/../BrassTutor/note.h:71: first defined here
    collect2.exe: error: ld returned 1 exit status
    mingw32-make[1]: *** [Makefile.Debug:90: debug/BrassTutor.exe] Error 1
    mingw32-make: *** [Makefile:45: debug] Error 2
    

    I don't understand how this can be possible. I am 100% sure that I don't have a second definition of qHash() anywhere in my code and the header file is guarded with #ifndef against multiple includes.
    There is probably a very basic thing that I totally don't see or understand.



  • After days of searching I've found it myself right after posting this. Sorry.
    Following this article I re-applied "inline" and now it works.
    Thanks!
    For posterity:

    #ifndef NOTE_H
    #define NOTE_H
    #include <QHash>
    class Note
    {
        ///...
        inline bool operator==(const Note &n2) const { return n2.midiNumber() == this->midiNumber(); }
        ///...
    };
    /// after class definition has ended:
    inline uint qHash(const Note& key, uint seed = 0) {
        Q_UNUSED(seed)
        return uint(key.midiNumber());
    }
    #endif // NOTE_H
    

Log in to reply