[Development] C++11 decltype magic with a container?
Stephen Kelly
stephen.kelly at kdab.com
Wed May 22 11:07:44 CEST 2013
On Tuesday, May 21, 2013 11:38:41 Thiago Macieira wrote:
> On terça-feira, 21 de maio de 2013 20.27.41, Stephen Kelly wrote:
> > For a Qt patch, I need to know at compile-time whether std::find can be
> > used with it, ie, whether the value_type of the container can be
> > equality-compared.
> >
> > https://codereview.qt-project.org/#change,55735
> >
> > I used a decltype, which works for the type itself, but not for the
> > container. I also tried an enable_if, but that doesn't solve the problem
> > either.
>
> Let's go back a step.
>
> What are you trying to do?
It is now possible to iterate over the elements of a sequential iterator via
the QVariant API, without knowing exactly what type of container it is:
QVector<int> vec;
vec.push_back(1);
vec.push_back(7);
vec.push_back(0);
vec.push_back(1);
QVariant var = QVariant::fromValue(vec);
// ...
if (var.canConvert<QVariantList>()) {
QSequentialIterable iter = var.value<QSequentialIterable>();
QSequentialIterable::const_iterator it = iter.begin();
const QSequentialIterable::const_iterator end = iter.end();
for ( ; it != end; ++it) {
qDebug() << *it;
}
}
The problem is that QSequentialIterable::const_iterator::operator*() returns a
'QVariant', not a 'const QVariant &', so it's not stl compatible and can't be
used with standard algorithms such as find.
So, in order to test if a container contains a particular value without first
iterating over it and creating a QVariantList and testing *that*, I wanted to
make it possible to do this:
QSequentialIterable::const_iterator it = iter.find(2);
if (it != iter.end()) ...
That requires that the Container::value_type is equality comparable. So, the
patch that I linked to uses decltype to try to check if that is possible.
struct A {};
std::vector<A> v;
A a;
v.push_back(a);
std::find(v.begin(), v.end(), a); // Doesn't compile.
QList<A> l;
l.push_back(a);
l.indexOf(a); // Doesn't compile.
While my patch works for one step, of introspection, as soon as nested
containers are used it no longer gives correct results, with the result that
my patch does not actually compile:
/home/stephen/dev/src/qtbase/src/platformsupport/linuxaccessibility/struct_marshallers_p.h:168:1:
required from here
../../include/QtCore/../../../../../src/qtbase/src/corelib/tools/qlist.h:752:9:
error: no match for ‘operator==’ in ‘i-
>QList<T>::Node::t<QSpiObjectReference>() == li-
>QList<T>::Node::t<QSpiObjectReference>()’
struct QSpiObjectReference {}; // Not equality-comparable
typedef QPair < unsigned int,
QList < QSpiObjectReference > > QSpiRelationArrayEntry;
typedef QList< QSpiRelationArrayEntry > QSpiRelationArray;
Q_DECLARE_METATYPE(QSpiRelationArray) // line 168
QSpiRelationArray::value_type is QSpiRelationArrayEntry which, being a QPair,
does have a operator==(), so the decltype gives the result that the std::find
should work.
> And what types of a container aren't comparable? All containers require
> comparison in order to implement find() and constFind();
I hope the above answers your question.
Thanks,
--
Stephen Kelly <stephen.kelly at kdab.com> | Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
www.kdab.com || Germany +49-30-521325470 || Sweden (HQ) +46-563-540090
KDAB - Qt Experts - Platform-Independent Software Solutions
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.qt-project.org/pipermail/development/attachments/20130522/8d833180/attachment.sig>
More information about the Development
mailing list