QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH: use unqualified qHash() lookup

... instead of QT_PREPEND_NAMESPACE(qHash), which is qualified (prepends at least '::'), and therefore disables ADL.

This is not a problem as long as we wrote our qHash() overloads as free functions (incl. non-hidden friends), but it should™ fail for hidden friends, so use the old using-std::swap() trick to bring QT_PREPEND_NAMESPACE(qHash) into scope, proceeding with an unqualified lookup.

Pick-to: 6.2
Change-Id: I00860b2313699849f86bfe3dd9f41db4ce993cd3
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Marc Mutz 2021-11-26 16:31:59 +01:00
parent 95ccdfa432
commit ccaeffe565
2 changed files with 33 additions and 4 deletions

View File

@ -251,6 +251,9 @@ struct QNothrowHashable : std::false_type {};
template <typename T>
struct QNothrowHashable<T, std::enable_if_t<QNothrowHashableHelper_v<T>>> : std::true_type {};
template <typename T>
constexpr inline bool QNothrowHashable_v = QNothrowHashable<T>::value;
} // namespace QtPrivate
template <typename... T>
@ -317,15 +320,15 @@ template <typename T1, typename T2> inline size_t qHash(const std::pair<T1, T2>
using argument_type = QT_PREPEND_NAMESPACE(Class); \
using result_type = size_t; \
size_t operator()(Arguments s) const \
noexcept(noexcept(QT_PREPEND_NAMESPACE(qHash)(s))) \
noexcept(QT_PREPEND_NAMESPACE( \
QtPrivate::QNothrowHashable_v)<argument_type>) \
{ \
/* this seeds qHash with the result of */ \
/* std::hash applied to an int, to reap */ \
/* any protection against predictable hash */ \
/* values the std implementation may provide */ \
return QT_PREPEND_NAMESPACE(qHash)(s, \
QT_PREPEND_NAMESPACE(qHash)( \
std::hash<int>{}(0))); \
using QT_PREPEND_NAMESPACE(qHash); \
return qHash(s, qHash(std::hash<int>{}(0))); \
} \
}; \
} \

View File

@ -303,8 +303,34 @@ void tst_QHashFunctions::rangeCommutative()
}
}
// QVarLengthArray these days has a qHash() as a hidden friend.
// This checks that QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH can deal with that:
QT_BEGIN_NAMESPACE
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QVarLengthArray<QVector<int>>)
QT_END_NAMESPACE
void tst_QHashFunctions::stdHash()
{
{
std::unordered_set<QVarLengthArray<QVector<int>>> s = {
{
{0, 1, 2},
{42, 43, 44},
{},
}, {
{11, 12, 13},
{},
},
};
QCOMPARE(s.size(), 2UL);
s.insert({
{11, 12, 13},
{},
});
QCOMPARE(s.size(), 2UL);
}
{
std::unordered_set<QString> s = {QStringLiteral("Hello"), QStringLiteral("World")};
QCOMPARE(s.size(), 2UL);