qHash implementation for scoped enum type



  • I want to have a QSet of scoped enum values within a namespace. I tried implementing a specialization of qHash function for my scoped enum type following instructions in the docs. I also checked the forum for an answer on a similar problem and the only difference is that my enum type is defined within a namespace. I'm getting an obscure compilation error I haven't been able to fully understand.

    If I define the enum in the global namespace I don't get the compilation errors, but I'd like to keep my enum defined under its namespace.

    Here's my testing program:

    #include <QCoreApplication>
    #include <QSet>
    
    namespace foo {
    namespace hash {
        enum class MyEnum
        {
            ZERO = 0
            , ONE
        };
    }
    }
    
    inline uint qHash(foo::hash::MyEnum key, uint seed)
    {
        return qHash(static_cast<uint>(key), seed);
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QSet<foo::hash::MyEnum> set;
        set.insert(foo::hash::MyEnum::ZERO);
        set.insert(foo::hash::MyEnum::ONE);
    
        return a.exec();
    }
    

    And the compilation errors:

    g++ -c -pipe -std=c++11 -g -Wall -W -D_REENTRANT -fPIC -DQT_CORE_LIB -I../hash -I. -I/opt/Qt/5.4/gcc_64/include -I/opt/Qt/5.4/gcc_64/include/QtCore -I. -I/opt/Qt/5.4/gcc_64/mkspecs/linux-g++ -o main.o ../hash/main.cpp
    In file included from /opt/Qt/5.4/gcc_64/include/QtCore/qglobal.h:70:0,
                     from /opt/Qt/5.4/gcc_64/include/QtCore/qcoreapplication.h:37,
                     from /opt/Qt/5.4/gcc_64/include/QtCore/QCoreApplication:1,
                     from ../hash/main.cpp:1:
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h: In instantiation of 'uint qHash(const T&, uint) [with T = foo::hash::MyEnum; uint = unsigned int]':
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:912:32:   required from 'QHash<Key, T>::Node** QHash<Key, T>::findNode(const Key&, uint*) const [with Key = foo::hash::MyEnum; T = QHashDummyValue; QHash<Key, T>::Node = QHashNode<foo::hash::MyEnum, QHashDummyValue>; uint = unsigned int]'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:768:36:   required from 'QHash<Key, T>::iterator QHash<Key, T>::insert(const Key&, const T&) [with Key = foo::hash::MyEnum; T = QHashDummyValue]'
    /opt/Qt/5.4/gcc_64/include/QtCore/qset.h:188:94:   required from 'QSet<T>::iterator QSet<T>::insert(const T&) [with T = foo::hash::MyEnum]'
    ../hash/main.cpp:24:39:   required from here
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:101:42: error: no matching function for call to 'qHash(const foo::hash::MyEnum&)'
         Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t)))
                                              ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qcompilerdetection.h:977:43: note: in definition of macro 'Q_DECL_NOEXCEPT_EXPR'
     # define Q_DECL_NOEXCEPT_EXPR(x) noexcept(x)
                                               ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:101:42: note: candidates are:
         Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t)))
                                              ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qcompilerdetection.h:977:43: note: in definition of macro 'Q_DECL_NOEXCEPT_EXPR'
     # define Q_DECL_NOEXCEPT_EXPR(x) noexcept(x)
                                               ^
    In file included from /opt/Qt/5.4/gcc_64/include/QtCore/qset.h:37:0,
                     from /opt/Qt/5.4/gcc_64/include/QtCore/QSet:1,
                     from ../hash/main.cpp:2:
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:63:52: note: constexpr uint qHash(char, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(char key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:63:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'char'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:64:52: note: constexpr uint qHash(uchar, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uchar key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:64:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'uchar {aka unsigned char}'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:65:52: note: constexpr uint qHash(signed char, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(signed char key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:65:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'signed char'
    In file included from /opt/Qt/5.4/gcc_64/include/QtCore/qset.h:37:0,
                     from /opt/Qt/5.4/gcc_64/include/QtCore/QSet:1,
                     from ../hash/main.cpp:2:
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:66:52: note: constexpr uint qHash(ushort, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ushort key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:66:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'ushort {aka short unsigned int}'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:67:52: note: constexpr uint qHash(short int, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(short key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:67:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'short int'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:68:52: note: constexpr uint qHash(uint, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(uint key, uint seed = 0) Q_DECL_NOTHROW { return key ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:68:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'uint {aka unsigned int}'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:69:52: note: constexpr uint qHash(int, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(int key, uint seed = 0) Q_DECL_NOTHROW { return uint(key) ^ seed; }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:69:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'int'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:70:52: note: constexpr uint qHash(ulong, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(ulong key, uint seed = 0) Q_DECL_NOTHROW
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:70:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'ulong {aka long unsigned int}'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:76:52: note: constexpr uint qHash(long int, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(long key, uint seed = 0) Q_DECL_NOTHROW { return qHash(ulong(key), seed); }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:76:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'long int'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:77:52: note: constexpr uint qHash(quint64, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(quint64 key, uint seed = 0) Q_DECL_NOTHROW
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:77:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'quint64 {aka long long unsigned int}'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:81:52: note: constexpr uint qHash(qint64, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(qint64 key, uint seed = 0) Q_DECL_NOTHROW { return qHash(quint64(key), seed); }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:81:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'qint64 {aka long long int}'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:82:42: note: uint qHash(float, uint)
     Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(float key, uint seed = 0) Q_DECL_NOTHROW;
                                              ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:82:42: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'float'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:83:42: note: uint qHash(double, uint)
     Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(double key, uint seed = 0) Q_DECL_NOTHROW;
                                              ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:83:42: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'double'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:85:42: note: uint qHash(long double, uint)
     Q_CORE_EXPORT Q_DECL_CONST_FUNCTION uint qHash(long double key, uint seed = 0) Q_DECL_NOTHROW;
                                              ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:85:42: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'long double'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:87:52: note: constexpr uint qHash(QChar, uint)
     Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qHash(const QChar key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.unicode(), seed); }
                                                        ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:87:52: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'QChar'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:88:41: note: uint qHash(const QByteArray&, uint)
     Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QByteArray &key, uint seed = 0) Q_DECL_NOTHROW;
                                             ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:88:41: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'const QByteArray&'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:89:41: note: uint qHash(const QString&, uint)
     Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QString &key, uint seed = 0) Q_DECL_NOTHROW;
                                             ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:89:41: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'const QString&'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:90:41: note: uint qHash(const QStringRef&, uint)
     Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QStringRef &key, uint seed = 0) Q_DECL_NOTHROW;
                                             ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:90:41: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'const QStringRef&'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:91:41: note: uint qHash(const QBitArray&, uint)
     Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QBitArray &key, uint seed = 0) Q_DECL_NOTHROW;
                                             ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:91:41: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'const QBitArray&'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:92:41: note: uint qHash(QLatin1String, uint)
     Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QLatin1String key, uint seed = 0) Q_DECL_NOTHROW;
                                             ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:92:41: note:   no known conversion for argument 1 from 'const foo::hash::MyEnum' to 'QLatin1String'
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:96:32: note: template<class T> uint qHash(const T*, uint)
     template <class T> inline uint qHash(const T *key, uint seed = 0) Q_DECL_NOTHROW
                                    ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:96:32: note:   template argument deduction/substitution failed:
    In file included from /opt/Qt/5.4/gcc_64/include/QtCore/qglobal.h:70:0,
                     from /opt/Qt/5.4/gcc_64/include/QtCore/qcoreapplication.h:37,
                     from /opt/Qt/5.4/gcc_64/include/QtCore/QCoreApplication:1,
                     from ../hash/main.cpp:1:
    /opt/Qt/5.4/gcc_64/include/QtCore/qhash.h:101:42: note:   mismatched types 'const T*' and 'foo::hash::MyEnum'
         Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t)))
                                              ^
    /opt/Qt/5.4/gcc_64/include/QtCore/qcompilerdetection.h:977:43: note: in definition of macro 'Q_DECL_NOEXCEPT_EXPR'
     # define Q_DECL_NOEXCEPT_EXPR(x) noexcept(x)
                                               ^
    


  • I found a way to get the code compiling. Defining the qHash function within the same scope as the enum type makes it work. But I fail to see why the definition in the global namespace with the fully qualified parameter type fails to compile.

    Here's the working code:

    #include <QCoreApplication>
    #include <QSet>
    
    namespace foo {
    namespace hash {
        enum class MyEnum
        {
            ZERO = 0
            , ONE
        };
    
        inline uint qHash(MyEnum key, uint seed)
        {
            return ::qHash(static_cast<uint>(key), seed);
        }
    }
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QSet<foo::hash::MyEnum> set;
        set.insert(foo::hash::MyEnum::ZERO);
        set.insert(foo::hash::MyEnum::ONE);
    
        return a.exec();
    }
    

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Good question, however the documentation about the qHash function states that the function must be in the namespace


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.