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:
parent
7fb3906d4e
commit
a1898f4466
@ -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]
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user