QSet<myEnumClass> --> no matching function for call to 'qHash(myEnumClass&)'
-
Hi and thanks for reading,
I have an enum class Operator::OperatorType that I want o use a QSet of. It's defined in the QObject-derived class Operator:#include "expression.h" class Operator: public Expression { Q_OBJECT public: enum class OperatorType { UNDEFINED, ADD, // add first to second SUB, // substract second from first MUL, // multiply first by second DIV, // divide first by second SQT, // secondth root of first SQU // first to the power of second }; Q_ENUM(OperatorType) //QHASH_FOR_CLASS_ENUM(OperatorType) // Ok Operator(OperatorType type, QSharedPointer<Expression> first, QSharedPointer<Expression> second);
At another point in my code I try to build a QSet of this type:
QSet<Operator::OperatorType> testTypes; Operator::OperatorType t = Operator::OperatorType::ADD; testTypes.insert(t); // <--- Error points to this line
This results in the following build error:
C:\Qt\5.11.2\mingw53_32\include\QtCore\qhashfunctions.h:112: error: no matching function for call to 'qHash(const Operator::OperatorType&)' Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(t))) // error points to (t)
As you can see (commented out in the above code), I have tried this idea:
#define QHASH_FRIEND_FOR_CLASS_ENUM(T) \ friend uint qHash(const T&, uint seed); #define QHASH_FOR_CLASS_ENUM(T) \ inline uint qHash(const T &t, uint seed) { \ return ::qHash(static_cast<typename std::underlying_type<T>::type>(t), seed); \ }
Unfortuntely the problem remained. Am I doing something stupid? I'd not have thought it to be problematic, having a set of enums….
What else would be recommendable? I'd rather not wrap the enum in a QVariant or attach it to a dummy object...
-
@SeDi
move the definition of qHash() outside the class.As the error says, it is looking for
qHash(const Operator::OperatorType&)
, notOperator::qHash(const OperatorType&)
-
To add to @raven-worx, here is the documentation on how to implement custom qHash.
-
Thank you for the idea @VRonin - I have looked into QFlags and I'd actually prefer that. But, at some point, I have to iterate over the enums stored inside - I haven't yet found a way to iterate over QFlags.
What I actually try to achieve with the iteration (and it does work with QSet now) is to randomly select one of those enums.
I don't want to rely on the QSet as being un-sorted in a random manner, so I pick a number by random and iterate to it:
int number = qrand() % types.count(); QSetIterator<Operator::OperatorType> iter(types); int i = 0; while (iter.hasNext()) { if (i == number) { return(iter.peekNext()); } i++; iter.next(); } return Operator::OperatorType::UNDEFINED;
With QFlags I'd probably have to resort to some even uglier bitwise operators, I'd presume (without having given it too much thought).
-
enum OperatorType { UNDEFINED = 0, ADD = 0x1, // add first to second SUB = 0x2, // substract second from first MUL= 0x4, // multiply first by second DIV= 0x8, // divide first by second SQT= 0x10, // secondth root of first SQU =0x20 // first to the power of second }; Q_FLAG(OperatorType)
But, at some point, I have to iterate over the enums stored inside
const auto flagMeta = QMetaEnum::fromType<Operator::OperatorType>(); for(int i=0;i<flagMeta.keyCount();++i){ qDebug() << flagMeta.key(i) << ": " << flagMeta.value(i); }
even uglier bitwise operators
const auto flagMeta = QMetaEnum::fromType<Operator::OperatorType>(); const auto randomOperator = static_cast<Operator::OperatorType>(1 << (qrand() % (flagMeta.keyCount()-1)));