qHash implementation for scoped enum type
-
I want to have a
QSet
of scoped enum values within a namespace. I tried implementing a specialization ofqHash
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(); }
-
Hi and welcome to devnet,
Good question, however the documentation about the qHash function states that the function must be in the namespace