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 <ogoffart@woboq.com>
This commit is contained in:
Stephen Kelly 2013-09-08 12:08:22 +02:00 committed by The Qt Project
parent 7fb3906d4e
commit a1898f4466
4 changed files with 113 additions and 113 deletions

View File

@ -112,3 +112,34 @@ id = qMetaTypeId<MyStruct>(); // compile error if MyStruct not declared
typedef QString CustomString;
qRegisterMetaType<CustomString>("CustomString");
//! [9]
//! [10]
#include <deque>
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::deque)
void someFunc()
{
std::deque<QFile*> container;
QVariant var = QVariant::fromValue(container);
// ...
}
//! [10]
//! [11]
#include <unordered_list>
Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::unordered_map)
void someFunc()
{
std::unordered_map<int, bool> container;
QVariant var = QVariant::fromValue(container);
// ...
}
//! [11]

View File

@ -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<T> 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<T, U> 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<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>

View File

@ -1331,33 +1331,12 @@ namespace QtPrivate
enum { Value = false };
};
#define QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(CONTAINER) \
template<typename T> \
struct IsSequentialContainer<CONTAINER<T> > \
{ \
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<typename T>
struct IsAssociativeContainer
{
enum { Value = false };
};
#define QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(CONTAINER) \
template<typename T, typename U> \
struct IsAssociativeContainer<CONTAINER<T, U> > \
{ \
enum { Value = true }; \
};
QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QHash)
QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QMap)
QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(std::map)
template<typename T, bool = QtPrivate::IsSequentialContainer<T>::Value>
struct SequentialContainerConverterHelper
{
@ -1763,6 +1742,13 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
return newId; \
} \
}; \
namespace QtPrivate { \
template<typename T> \
struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
{ \
enum { Value = true }; \
}; \
} \
QT_END_NAMESPACE
#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
@ -1851,7 +1837,7 @@ struct QMetaTypeId< SMART_POINTER<T> > \
};\
QT_END_NAMESPACE
#define Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER(TEMPLATENAME) \
#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
QT_BEGIN_NAMESPACE \
template <class T> 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_METATYPE_TEMPLATE_1ARG_ITER
#undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::vector)
Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::list)
#define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE Q_DECLARE_METATYPE_TEMPLATE_1ARG
#define Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector)
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list)
#define Q_FORWARD_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \
QT_BEGIN_NAMESPACE \
template <class T1, class T2> 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<typename T, typename U> \
struct IsAssociativeContainer<TEMPLATENAME<T, U> > \
{ \
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<T, true>::registerConverter(int id)
return true;
}
#ifndef Q_QDOC
template<typename T>
#endif
bool qRegisterSequentialConverter()
{
Q_STATIC_ASSERT_X(QMetaTypeId2<typename T::value_type>::Defined,
"The value_type of a sequential container must itself be a metatype.");
const int id = qMetaTypeId<T>();
const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>();
if (QMetaType::hasRegisteredConverterFunction(id, toId))
return true;
static const QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> o;
static const QtPrivate::ConverterFunctor<T,
QtMetaTypePrivate::QSequentialIterableImpl,
QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> > f(o);
return QMetaType::registerConverterFunction(&f, id, toId);
}
template<typename T>
bool qRegisterAssociativeConverter()
{
Q_STATIC_ASSERT_X(QMetaTypeId2<typename T::key_type>::Defined
&& QMetaTypeId2<typename T::mapped_type>::Defined,
"The key_type and mapped_type of an associative container must themselves be metatypes.");
const int id = qMetaTypeId<T>();
const int toId = qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>();
if (QMetaType::hasRegisteredConverterFunction(id, toId))
return true;
static const QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> o;
static const QtPrivate::ConverterFunctor<T,
QtMetaTypePrivate::QAssociativeIterableImpl,
QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> > f(o);
return QMetaType::registerConverterFunction(&f, id, toId);
}
QT_END_NAMESPACE
#endif // QMETATYPE_H

View File

@ -2278,23 +2278,26 @@ public:
template<typename T>
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<typename T, typename U>
struct AssociativeContainer
struct AssociativeContainer : public std::map<T, U>
{
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<int>)
void tst_QVariant::qvariant_cast_QObject_wrapper()
@ -2311,8 +2314,6 @@ void tst_QVariant::qvariant_cast_QObject_wrapper()
MyNS::SequentialContainer<int> sc;
sc.t = 47;
MyNS::AssociativeContainer<int, short> ac;
ac.t = 42;
ac.u = 5;
QVariant::fromValue(sc);
QVariant::fromValue(ac);
@ -3538,9 +3539,11 @@ struct ContainerAPI<Container, QString>
#ifdef TEST_FORWARD_LIST
#include <forward_list>
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::forward_list)
// Test that explicit declaration does not degrade features.
Q_DECLARE_METATYPE(std::forward_list<int>)
Q_DECLARE_METATYPE(std::forward_list<QVariant>)
Q_DECLARE_METATYPE(std::forward_list<QString>)
template<typename Value_Type>
struct ContainerAPI<std::forward_list<Value_Type> >
@ -3624,6 +3627,9 @@ struct KeyGetter<std::map<T, U> >
#ifdef TEST_UNORDERED_MAP
#include <unordered_map>
typedef std::unordered_map<int, bool> StdUnorderedMap_int_bool;
Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::unordered_map)
Q_DECLARE_METATYPE(StdUnorderedMap_int_bool)
template<typename T, typename U>
@ -3718,9 +3724,6 @@ void tst_QVariant::iterateContainerElements()
TEST_SEQUENTIAL_ITERATION(std::list, QString)
#ifdef TEST_FORWARD_LIST
qRegisterSequentialConverter<std::forward_list<int> >();
qRegisterSequentialConverter<std::forward_list<QVariant> >();
qRegisterSequentialConverter<std::forward_list<QString> >();
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<StdUnorderedMap_int_bool>();
TEST_ASSOCIATIVE_ITERATION(std::unordered_map, int, bool)
#endif
}