Applied Type Erasure in Qt 5 Stephen Kelly KDAB Stephen Kelly - - PowerPoint PPT Presentation

applied type erasure in qt 5 stephen kelly kdab
SMART_READER_LITE
LIVE PREVIEW

Applied Type Erasure in Qt 5 Stephen Kelly KDAB Stephen Kelly - - PowerPoint PPT Presentation

Applied Type Erasure in Qt 5 Stephen Kelly KDAB Stephen Kelly KDAB engineer Qt Maintainer (ItemViews, CMake) KDE Developer Many Qt contributions QVariant QMetaType Grantlee - domain specific language Boost


slide-1
SLIDE 1

Applied Type Erasure in Qt 5 Stephen Kelly KDAB

slide-2
SLIDE 2

Stephen Kelly

  • KDAB engineer
  • Qt Maintainer (ItemViews, CMake)
  • KDE Developer
  • Many Qt contributions

– QVariant – QMetaType

  • Grantlee - domain specific language
  • Boost developer
  • CMake developer
slide-3
SLIDE 3

Type Erasure

“Process of turning a wide variety of types with a common interface into one type with that same interface.”

slide-4
SLIDE 4

Type Erasure

  • Hold distinct, unrelated types
  • Convert between types
  • Store instances in containers
  • Copy instances
  • Assign instances
slide-5
SLIDE 5

Type Erasure

  • Interface abstraction

– QVariant QAbstractItemModel::data(); – QVariant QVariantAnimation::valueChanged()

  • Domain Specific Language

– QML – Grantlee

  • Language binding

– PyQt/PySide – RubyQt

  • Interface abstraction

– QVariant QAbstractItemModel::data(); – QVariant QVariantAnimation::valueChanged()

  • Domain Specific Language

– QML – Grantlee

  • Language binding

– PyQt/PySide – RubyQt

slide-6
SLIDE 6

Domain Specific Language

import QtQuick 2.0 Rectangle { color : “lightsteelblue” width : 42 height : 47 }

slide-7
SLIDE 7

Domain Specific Language

Rectangle { color : “red” color : Qt.rgb(255, 0, 0) color : Qt.red }

slide-8
SLIDE 8

Text Template System

<html> <p>Welcome back {{ user.name }}! <p>You have {{ user.messages.length }} messages {% for message in user.messages %} <li>From: {{ message.sender }} : {{ message.content }} {% if message.urgent %} <img src=”urgent.png”/> {% endif %} {% endfor %} </html>

slide-9
SLIDE 9

Text Template System

<html> <p>Welcome back {{ user.name }}! <p>You have {{ user.messages.length }} messages {% for message in user.messages %} <li>From: {{ message.sender }} : {{ message.content }} {% if message.urgent %} <img src=”urgent.png”/> {% endif %} {% endfor %} </html>

slide-10
SLIDE 10

Requirements

  • Type conversion

– String, numbers – Equivalent colors – {% if message.urgent %}

  • Properties

– {{ user.name }} – {{ messages.length }}

  • Containers

– Sequences – Mappings – {% for item in container %}...{% endfor %}

slide-11
SLIDE 11

QVariant

slide-12
SLIDE 12

QVariant

slide-13
SLIDE 13

Conversion I

  • QString QVariant::toString()

– QVariant(42).toString() – QVariant(3.15).toString() – QVariant(“Hello, world!”).toString()

  • bool QVariant::toBool()

– QVariant(42).toBool() – QVariant(true).toBool()

slide-14
SLIDE 14

Properties

class User : public QObject { Q_PROPERTY(QString name ...) Q_PROPERTY(int numMessages ...) Q_OBJECT // ... }; QObject* obj = new User(this);

  • bj->property(“name”).toString();
  • bj->property(“numMessages”).toInt();
slide-15
SLIDE 15

Text Template System

<html> <p>Welcome back {{ user.name }}! <p>You have {{ user.messages.length }} messages {% for message in user.messages %} <li>From: {{ message.sender }} : {{ message.content }} {% if message.urgent %} <img src=”urgent.png”/> {% endif %} {% endfor %} </html>

slide-16
SLIDE 16

Conversion II

  • QObject* QVariant::value<QObject*>()

– QVariant::fromValue(new QObject) – QVariant::fromValue(new QFile) – QVariant::fromValue(new User) – QVariant::fromValue(QPointer<User>) – QVariant::fromValue(QSharedPointer<User>) – QVariant::fromValue(QWeakPointer<User>)

slide-17
SLIDE 17

Conversion II

class User : public QObject {

Q_OBJECT // ...

}; auto sp = QSharedPointer<User>::Create(); QVariant var = QVariant::fromValue(sp); // Later: QObject *obj = var.value<QObject*>() QString propValue =

  • bj->property(“some_prop”).toString();
slide-18
SLIDE 18

Text Template System

<html> <p>Welcome back {{ user.name }}! <p>You have {{ user.messages.length }} messages {% for message in user.messages %} <li>From: {{ message.sender }} : {{ message.content }} {% if message.urgent %} <img src=”urgent.png”/> {% endif %} {% endfor %} </html>

slide-19
SLIDE 19

Sequential Containers

class Message : public QObject { Q_OBJECT QPROPERTY(QString content ...) QPROPERTY(QString sender ...) }; class User : public QObject { Q_OBJECT Q_PROPERTY(QList<Message*> messages ...) };

slide-20
SLIDE 20

Sequential Containers

QObject *userObject = ...; QVariant var = userObject->property(“messages”); // Can't do this: QList<Message*> list = var.value<QList<Message*> >(); // Can't do this: QList<QObject*> list = var.value<QList<QObject*> >(); // Can do this (Qt 5.2)! QVariantList list = var.value<QVariantList>();

slide-21
SLIDE 21

Sequential Containers

if (var.canConvert<QVariantList>()) { auto iter = var.value<QSequentialIterable>(); foreach(const QVariant &item, iter) { // item.toString(); // item.value<QObject*>(); } }

slide-22
SLIDE 22

Sequential Containers

if (var.canConvert<QVariantList>()) { auto iter = var.value<QSequentialIterable>(); for (auto it = iter.begin(); it != iter.end(); ++it) { // it->toString(); // it->value<QObject*>(); } }

slide-23
SLIDE 23

Sequential Containers

if (var.canConvert<QVariantList>()) { auto iter = var.value<QSequentialIterable>(); for (QVariant item : iter) { // item.toString(); // item.value<QObject*>(); } }

slide-24
SLIDE 24

Sequential Containers

  • Built-in support for:

– QList – QVector – QStack – QQueue – QSet – QLinkedList – std::vector – std::list

slide-25
SLIDE 25

Associative Containers

QObject *userObject = ...; QVariant var = userObject->property(“some_mapping”); // Can't do this: QHash<QString, Message*> mapping = var.value<QHash<QString, Message*> >(); // Can't do this: QHash<QString, QObject*> mapping = var.value<QHash<QString, QObject*> >(); // Can do this (Qt 5.2)! QVariantHash mapping = var.value<QVariantHash>();

slide-26
SLIDE 26

Associative Containers

if (var.canConvert<QVariantHash>()) { auto iter = var.value<QAssociativeIterable>(); for (auto it = iter.begin(); it != iter.end(); ++it) { // it.key().toString(); // it.value().toString(); } }

slide-27
SLIDE 27

Associative Containers

  • Built-in support for:

– QHash – QMap – std::map

slide-28
SLIDE 28

Associative Containers

if (var.canConvert<QVariantPair>()) { auto pair = var.value<QVariantPair>(); // pair.first().toString(); // pair.second().toString(); }

  • Built-in support for:

– QPair<T, U> – std::pair<T, U>

slide-29
SLIDE 29

Text Template System

<html> <p>Welcome back {{ user.name }}! <p>You have {{ user.messages.length }} messages {% for message in user.messages %} <li>From: {{ message.sender }} : {{ message.content }} {% if message.urgent %} <img src=”urgent.png”/> {% endif %} {% endfor %} </html>

slide-30
SLIDE 30

Conversion III

Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr) Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE( std::deque) Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE( std::unordered_map)

slide-31
SLIDE 31

Conversion IV

struct Roles { QString toString() const; }; QMetaType::registerConverter(&Roles::toString); QMetaType::registerConverter(converterFunction); QMetaType::registerConverter(converterFunctor);

slide-32
SLIDE 32

Conversion IV

#include <QDebug> struct Roles { bool canDelete() const; bool canCreate() const; bool canAccess() const; QString toString() const { return “Roles”; } }; Q_DECLARE_METATYPE(Roles) int main(int argc, char **argv) { Roles r; QMetaType::registerConverter(&Roles::toString); QVariant v = QVariant::fromValue(r); qDebug() << v.toString(); }

slide-33
SLIDE 33

Summary

  • Type erasure based on QVariant
  • Qt 5.2 new capabilities

– Generic QObject* handling – Generic smart pointer handling – Generic container iteration – User extensible – User-defined conversions

slide-34
SLIDE 34

Q & A

stephen.kelly@kdab.com