Add automatic container access registration for built-in containers.

Change-Id: I4d590c23e072994930922ff73367600f848fbcf0
Reviewed-by: Stephen Kelly <stephen.kelly@kdab.com>
This commit is contained in:
Stephen Kelly 2013-04-05 13:24:54 +02:00 committed by The Qt Project
parent c5a6b894e7
commit 508ee5616b
5 changed files with 75 additions and 29 deletions

View File

@ -137,8 +137,6 @@ QVariant data = QVariant::fromValue(object);
//! [9]
qRegisterSequentialConverter<QList<int> >();
QList<int> intList;
intList.push_back(7);
intList.push_back(11);

View File

@ -1971,6 +1971,10 @@ const QMetaObject *QMetaType::metaObjectForType(int type)
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()
*/

View File

@ -307,6 +307,9 @@ struct ConverterFunctor : public AbstractConverterFunction
UnaryFunction m_function;
};
template<typename T, bool>
struct ValueTypeIsMetaType;
}
class Q_CORE_EXPORT QMetaType {
@ -538,6 +541,7 @@ private:
#ifndef Q_QDOC
template<typename T>
friend bool qRegisterSequentialConverter();
template<typename, bool> friend struct QtPrivate::ValueTypeIsMetaType;
#endif
#else
public:
@ -946,6 +950,63 @@ namespace QtPrivate
enum { Value = true };
};
template<typename T>
struct IsSequentialContainer
{
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, bool = QtPrivate::IsSequentialContainer<T>::Value>
struct SequentialContainerConverterHelper
{
static bool registerConverter(int)
{
return false;
}
};
template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined>
struct ValueTypeIsMetaType
{
static bool registerConverter(int)
{
return false;
}
};
template<typename T>
struct ValueTypeIsMetaType<T, true>
{
static bool registerConverter(int id)
{
const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> f;
return QMetaType::registerConverterFunction(
new QtPrivate::ConverterFunctor<T,
QtMetaTypePrivate::QSequentialIterableImpl,
QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> >(f),
id, toId);
}
return true;
}
};
template<typename T>
struct SequentialContainerConverterHelper<T, true> : ValueTypeIsMetaType<T>
{
};
Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type);
} // namespace QtPrivate
@ -1035,7 +1096,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
if (defined)
flags |= QMetaType::WasDeclaredAsMetaType;
return QMetaType::registerNormalizedType(normalizedTypeName,
const int id = QMetaType::registerNormalizedType(normalizedTypeName,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Delete,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Create,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct,
@ -1043,6 +1104,12 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
sizeof(T),
flags,
QtPrivate::MetaObjectForType<T>::value());
if (id > 0) {
QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id);
}
return id;
}
template <typename T>

View File

@ -2753,11 +2753,9 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
\snippet code/src_corelib_kernel_qvariant.cpp 9
This requires that the value_type of the container is itself a metatype. To make it
possible to convert or iterate over a sequential container, the qRegisterSequentialConverter
method must first be called for the container.
This requires that the value_type of the container is itself a metatype.
\sa convert(), QSequentialIterable
\sa convert(), QSequentialIterable, qRegisterSequentialConverter()
*/
bool QVariant::canConvert(int targetTypeId) const
{
@ -3090,9 +3088,7 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\snippet code/src_corelib_kernel_qvariant.cpp 9
The qRegisterSequentialConverter method must first be called for the container.
\sa setValue(), fromValue(), canConvert()
\sa setValue(), fromValue(), canConvert(), qRegisterSequentialConverter()
*/
/*! \fn bool QVariant::canConvert() const

View File

@ -3518,25 +3518,6 @@ void tst_QVariant::iterateContainerElements()
TEST_RANGE_FOR(CONTAINER, VALUE_TYPE) \
}
qRegisterSequentialConverter<QVector<int> >();
qRegisterSequentialConverter<QVector<QVariant> >();
qRegisterSequentialConverter<QVector<QString> >();
qRegisterSequentialConverter<QQueue<int> >();
qRegisterSequentialConverter<QQueue<QVariant> >();
qRegisterSequentialConverter<QQueue<QString> >();
qRegisterSequentialConverter<QList<int> >();
qRegisterSequentialConverter<QList<QVariant> >();
qRegisterSequentialConverter<QList<QString> >();
qRegisterSequentialConverter<QStack<int> >();
qRegisterSequentialConverter<QStack<QVariant> >();
qRegisterSequentialConverter<QStack<QString> >();
qRegisterSequentialConverter<std::vector<int> >();
qRegisterSequentialConverter<std::vector<QVariant> >();
qRegisterSequentialConverter<std::vector<QString> >();
qRegisterSequentialConverter<std::list<int> >();
qRegisterSequentialConverter<std::list<QVariant> >();
qRegisterSequentialConverter<std::list<QString> >();
TEST_SEQUENTIAL_ITERATION(QVector, int)
TEST_SEQUENTIAL_ITERATION(QVector, QVariant)
TEST_SEQUENTIAL_ITERATION(QVector, QString)