From a1898f4466518bf3e1b6e9154eec05ecf9d909e3 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sun, 8 Sep 2013 12:08:22 +0200 Subject: Metatype: Remove the need for runtime-registration of 3rd party containers. Replace that need with a macro so that registration of the container helper conversions is done at the time of registration of the container (usually when it is put into a QVariant). Change-Id: I823fb3fdbce306ebc9f146675ac43724cec678d5 Reviewed-by: Olivier Goffart --- .../snippets/code/src_corelib_kernel_qmetatype.cpp | 31 +++++++ src/corelib/kernel/qmetatype.cpp | 65 ++++++------- src/corelib/kernel/qmetatype.h | 102 +++++++-------------- .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 28 +++--- 4 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp index 4437313f0a..cb1346f74c 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp @@ -112,3 +112,34 @@ id = qMetaTypeId(); // compile error if MyStruct not declared typedef QString CustomString; qRegisterMetaType("CustomString"); //! [9] + +//! [10] + +#include + +Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::deque) + +void someFunc() +{ + std::deque container; + QVariant var = QVariant::fromValue(container); + // ... +} + +//! [10] + +//! [11] + +#include + +Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::unordered_map) + +void someFunc() +{ + std::unordered_map container; + QVariant var = QVariant::fromValue(container); + // ... +} + +//! [11] + diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 17fbbda720..2ab6681bb9 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -140,6 +140,40 @@ struct DefinedTypesFilter { \sa qRegisterMetaType() */ +/*! + \macro Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(Container) + \relates QMetaType + + This macro makes the container \a Container known to QMetaType as a sequential + container. This makes it possible to put an instance of Container into + a QVariant, if T itself is known to QMetaType. + + Note that all of the Qt sequential containers already have built-in + support, and it is not necessary to use this macro with them. The + std::vector and std::list containers also have built-in support. + + This example shows a typical use of Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(): + + \snippet code/src_corelib_kernel_qmetatype.cpp 10 +*/ + +/*! + \macro Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(Container) + \relates QMetaType + + This macro makes the container \a Container known to QMetaType as an associative + container. This makes it possible to put an instance of Container into + a QVariant, if T and U are themselves known to QMetaType. + + Note that all of the Qt associative containers already have built-in + support, and it is not necessary to use this macro with them. The + std::map container also has built-in support. + + This example shows a typical use of Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(): + + \snippet code/src_corelib_kernel_qmetatype.cpp 11 +*/ + /*! \enum QMetaType::Type @@ -2085,37 +2119,6 @@ const QMetaObject *QMetaType::metaObjectForType(int type) \sa Q_DECLARE_METATYPE(), QMetaType::type() */ -/*! - \fn bool qRegisterSequentialConverter() - \relates QMetaType - \since 5.2 - - Registers a sequential container so that it can be converted to - a QVariantList. If compilation fails, then you probably forgot to - Q_DECLARE_METATYPE the value type. - - Note that it is not necessary to call this method for Qt containers (QList, - QVector etc) or for std::vector or std::list. Such containers are automatically - registered by Qt. - - \sa QVariant::canConvert() -*/ - -/*! - \fn bool qRegisterAssociativeConverter() - \relates QMetaType - \since 5.2 - - Registers an associative container so that it can be converted to - a QVariantHash or QVariantMap. If the key_type and mapped_type of the container - was not declared with Q_DECLARE_METATYPE(), compilation will fail. - - Note that it is not necessary to call this method for Qt containers (QHash, - QMap etc) or for std::map. Such containers are automatically registered by Qt. - - \sa QVariant::canConvert() -*/ - namespace { class TypeInfo { template::IsAccepted> diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 6b1a988fce..bd4963e4f1 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1331,33 +1331,12 @@ namespace QtPrivate enum { Value = false }; }; -#define QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(CONTAINER) \ - template \ - struct IsSequentialContainer > \ - { \ - enum { Value = true }; \ - }; - QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE) - QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(std::vector) - QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(std::list) - template struct IsAssociativeContainer { enum { Value = false }; }; -#define QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(CONTAINER) \ - template \ - struct IsAssociativeContainer > \ - { \ - enum { Value = true }; \ - }; - QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QHash) - QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QMap) - QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(std::map) - - template::Value> struct SequentialContainerConverterHelper { @@ -1763,6 +1742,13 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE > \ return newId; \ } \ }; \ +namespace QtPrivate { \ +template \ +struct IsSequentialContainer > \ +{ \ + enum { Value = true }; \ +}; \ +} \ QT_END_NAMESPACE #define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \ @@ -1851,7 +1837,7 @@ struct QMetaTypeId< SMART_POINTER > \ };\ QT_END_NAMESPACE -#define Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER(TEMPLATENAME) \ +#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \ QT_BEGIN_NAMESPACE \ template class TEMPLATENAME; \ QT_END_NAMESPACE \ @@ -1859,25 +1845,42 @@ QT_END_NAMESPACE QT_END_NAMESPACE -QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER) +QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER) + +#undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER -#undef Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER +#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE Q_DECLARE_METATYPE_TEMPLATE_1ARG -Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::vector) -Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::list) +Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector) +Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list) -#define Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \ +#define Q_FORWARD_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \ QT_BEGIN_NAMESPACE \ template CPPTYPE TEMPLATENAME; \ QT_END_NAMESPACE \ - Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME) -QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER) +QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(Q_FORWARD_DECLARE_METATYPE_TEMPLATE_2ARG_ITER) #undef Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER +#define Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(TEMPLATENAME) \ + QT_BEGIN_NAMESPACE \ + namespace QtPrivate { \ + template \ + struct IsAssociativeContainer > \ + { \ + enum { Value = true }; \ + }; \ + } \ + QT_END_NAMESPACE \ + Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME) + +Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QHash) +Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QMap) +Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::map) + +Q_DECLARE_METATYPE_TEMPLATE_2ARG(QPair) Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair) -Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::map) #define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \ Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME) @@ -2009,45 +2012,6 @@ inline bool QtPrivate::IsMetaTypePair::registerConverter(int id) return true; } - -#ifndef Q_QDOC -template -#endif -bool qRegisterSequentialConverter() -{ - Q_STATIC_ASSERT_X(QMetaTypeId2::Defined, - "The value_type of a sequential container must itself be a metatype."); - const int id = qMetaTypeId(); - const int toId = qMetaTypeId(); - if (QMetaType::hasRegisteredConverterFunction(id, toId)) - return true; - - static const QtMetaTypePrivate::QSequentialIterableConvertFunctor o; - static const QtPrivate::ConverterFunctor > f(o); - return QMetaType::registerConverterFunction(&f, id, toId); -} - -template -bool qRegisterAssociativeConverter() -{ - Q_STATIC_ASSERT_X(QMetaTypeId2::Defined - && QMetaTypeId2::Defined, - "The key_type and mapped_type of an associative container must themselves be metatypes."); - - const int id = qMetaTypeId(); - const int toId = qMetaTypeId(); - if (QMetaType::hasRegisteredConverterFunction(id, toId)) - return true; - static const QtMetaTypePrivate::QAssociativeIterableConvertFunctor o; - static const QtPrivate::ConverterFunctor > f(o); - - return QMetaType::registerConverterFunction(&f, id, toId); -} - QT_END_NAMESPACE #endif // QMETATYPE_H diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index eab2ba4f36..a532407ad4 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -2278,23 +2278,26 @@ public: template struct SequentialContainer { + typedef T value_type; + typedef const T* const_iterator; T t; + const_iterator begin() const { return &t; } + const_iterator end() const { return &t + 1; } }; template -struct AssociativeContainer +struct AssociativeContainer : public std::map { - T t; - U u; }; } Q_DECLARE_SMART_POINTER_METATYPE(MyNS::SmartPointer) -Q_DECLARE_METATYPE_TEMPLATE_1ARG(MyNS::SequentialContainer) -Q_DECLARE_METATYPE_TEMPLATE_2ARG(MyNS::AssociativeContainer) +Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(MyNS::SequentialContainer) +Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(MyNS::AssociativeContainer) +// Test that explicit declaration does not degrade features. Q_DECLARE_METATYPE(MyNS::SmartPointer) void tst_QVariant::qvariant_cast_QObject_wrapper() @@ -2311,8 +2314,6 @@ void tst_QVariant::qvariant_cast_QObject_wrapper() MyNS::SequentialContainer sc; sc.t = 47; MyNS::AssociativeContainer ac; - ac.t = 42; - ac.u = 5; QVariant::fromValue(sc); QVariant::fromValue(ac); @@ -3538,9 +3539,11 @@ struct ContainerAPI #ifdef TEST_FORWARD_LIST #include + +Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::forward_list) + +// Test that explicit declaration does not degrade features. Q_DECLARE_METATYPE(std::forward_list) -Q_DECLARE_METATYPE(std::forward_list) -Q_DECLARE_METATYPE(std::forward_list) template struct ContainerAPI > @@ -3624,6 +3627,9 @@ struct KeyGetter > #ifdef TEST_UNORDERED_MAP #include typedef std::unordered_map StdUnorderedMap_int_bool; + +Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::unordered_map) + Q_DECLARE_METATYPE(StdUnorderedMap_int_bool) template @@ -3718,9 +3724,6 @@ void tst_QVariant::iterateContainerElements() TEST_SEQUENTIAL_ITERATION(std::list, QString) #ifdef TEST_FORWARD_LIST - qRegisterSequentialConverter >(); - qRegisterSequentialConverter >(); - qRegisterSequentialConverter >(); TEST_SEQUENTIAL_ITERATION(std::forward_list, int) TEST_SEQUENTIAL_ITERATION(std::forward_list, QVariant) TEST_SEQUENTIAL_ITERATION(std::forward_list, QString) @@ -3758,7 +3761,6 @@ void tst_QVariant::iterateContainerElements() TEST_ASSOCIATIVE_ITERATION(QMap, int, bool) TEST_ASSOCIATIVE_ITERATION(std::map, int, bool) #ifdef TEST_UNORDERED_MAP - qRegisterAssociativeConverter(); TEST_ASSOCIATIVE_ITERATION(std::unordered_map, int, bool) #endif } -- cgit v1.2.3