Когда-то для удобства (было куча списков, которые нужно было (де)сериализовать), накидал себе макрос ниже. Используется так (Car — любой класс, который нужно хранить в списке)
class MyClass : public QObject
{
    Q_OBJECT
    QML_LIST_PROPERTY(MyClass, Car, car);
 
public:
    void foo() {
        append_car(new Car());
        qDebug() << carsCount();
        auto car_at_0 = car(0);
        auto allCars = get_cars();
        clear_cars();
        qDebug() << carsCount();
    }
};


Немного бардак из-за смеси camel case/snake case, можно в принципе всё snake case-ом сделать. Исходники с ещё парой очень пригодившихся мне вещей можно взять тут.
Остальные методы требуются для взаимодействия с QML. Тут документация, собственно, на QQmlListProperty.
Макрос:
#define QML_LIST_PROPERTY(classname, type, name) \
        protected: \
        Q_PROPERTY(QQmlListProperty< type > name ## s \
                           READ name ## s \
                           NOTIFY name ## sChanged) \
        public: \
                QQmlListProperty< type > name ## s() { \
                        return QQmlListProperty< type >(this, this, \
                                         & classname :: append_ ## name, \
                                         & classname :: name ## sCount, \
                                         & classname :: name, \
                                         & classname :: clear_ ## name ## s); \
                } \
                void append_ ## name ( type * item) { \
                        m_ ## name ## s . append( item ); \
                        emit name ## sChanged(); \
                } \
                int name ## sCount() const { return m_ ## name ## s . count(); } \
                type * name(int index) const { return m_ ## name ## s . at( index ); } \
                void clear_ ## name ## s () { \
                        while( ! m_ ## name ## s . isEmpty()) { \
                                auto tmp = m_ ## name ## s . takeLast(); \
                                if(tmp->parent() == this) \
                                        delete tmp; \
                        } \
                        emit name ## sChanged(); \
                } \
                inline QList< type *>& get_ ## name ## s() { \
                        return m_ ## name ## s; \
                } \
        Q_SIGNALS: \
                void name ## sChanged(); \
        protected: \
                static void append_ ## name(QQmlListProperty< type >* list, type* item) { \
                        reinterpret_cast< classname* >(list->data)->append_ ## name (item); \
                } \
                static int name ## sCount(QQmlListProperty<type>* list) { \
                        return reinterpret_cast< classname * >(list->data)->name ## sCount(); \
                } \
                static type * name(QQmlListProperty<type>* list, int index) { \
                        return reinterpret_cast< classname * >(list->data)-> name (index); \
                } \
                static void clear_ ## name ## s(QQmlListProperty<type>* list) { \
                        reinterpret_cast< classname* >(list->data)->clear_ ## name ## s(); \
                } \
                \
                QList< type *> m_ ## name ## s
Все хорошо, но! QQmlListProperty немного не для этого задумывался, он скорее для обратной задачи: когда нужно иметь возможность добавлять в c++ модель элементы из кода в QML. Как нетрудно заметить в вашем коде, у вас на любые изменения только один сигнал: sChanged(), который не отражает характер изменений никак. Очевидно, что view при любом таком изменении (добавление или удаление элементов) остается два пути: 1) как-то самому хранить предыдущее состояние модели, которая у него была и сравнивать его с тем, что получилось после сигнала — что, конечно, полная дичь, но теоретически… и 2) сбрасывать полностью все делегаты и рисовать весь лист по новой (как минимум ту его часть, которая видна), что тоже не очень эффективно. При этом всем еще скорее всего будет сбрасываться позиция прокрутки…

Для задачи (де)сериализации объектов api у меня тоже есть достаточно простое и изящное решение, в том числе для листов ;) Если первая статья вкатит, то поделюсь опытом )
Делитесь) Чую, можно было бы всё сделать гораздо красивее, чем у меня
«С приходом в Qt языка QML создавать пользовательские интерфейсы стало проще и быстрее… пока не требуется тесное взаимодействие с C++ кодом»… и это оказалось одной из причин, по которой мой выбор был сделан в пользу QWidget, когда начал писать свое приложение. К тому же я считаю, что реализация интерфейсов на «стандартных» элементах все же удобнее на QWidget. Qml выглядит привлекательным для всяких модных приложений в не профессиональной сфере: медиаплееры, социальные сети и т.п. А за статью спасибо — интересное решение.
Большое спасибо, за статью. Есть, чем дополнить.
Рекомендую изучить презентацию: Efficient models for QML with QSyncable
Один из первых подобных проектов — QQmlObjectListModel — прошел лед и пламень, и остался на плаву. Ben Lau (о его проектах в презентации) развил идею чуть дальше.

Теперь к критике: IMHO, многие утверждения здесь носят спорный характер.
Экономия на QObject — экономия на спичках при условии, что само приложение или размер контейнера малы. Если Вам довелось писать что-то вроде email-клиента — отказ от QObject-а дает весомое снижение ресурсоемкости. У Дениса Кормалева есть об этом в одном из выступлений.
Ваша аргументация о том, что у Electron ситуация еще хуже — совсем не аргумент.
Модель нужна ListView для того, чтобы поддержать анимирование операций над элементами (transitions). А сама QAbstractListModel как раз позволяет экспортировать НЕ Qt-типы в QML без дополнительных регистраций.
Если у вас есть QList и QObject-ы, но не нужен визуальный обвес ввиде красивых исчезновений элемента при удалении, вы можете прокинуть сам QList. Да, с «приколами», но тем не менее — это штатное средство без макросов, без абстракций.
О качестве QList и его дальнейшем существовании в Qt 6 одно время велись споры среди самих разработчиков Qt. Кроме того, при условии работы с другой STL-библиотекой, генерирующей данные, на выходе у вас будет STL-ный же контейнер. QList хорош, когда не надо запариваться.
Для получения данных элемента в статье используется самописный метод ::item()(шаг третий), в то же самое время использование штатного QAbstractItemModel::data() c явным «преобразованием» QObject* в QVariant. На моей практике, штатный метод, используемый для формирования объектов model\modelData в делегате, бывает куууда полезней.

Сам по себе подход, описанный в этой статье — не панацея, а решение конкретных проблем, например, описанных в этой статье: много полей — грустно таскать каждое из модели — значения отдать QVariant-ом с Q_GADGET. Это проблема.
Тот факт, что приходится переписывать многа букав — проблема при условии, что вы прототипируете, или делаете MVP или тому подобное. Из невероятного: у вас много однотипных Qt-only моделек, которые использоваться будут также тривиально. Шаг влево — и вам придется написать костыль для того, чтобы сохранить использование вашей абстракции; шаг вправо — и вы сильно рискуете потерять контроль над жизнью объектов в QML (в качестве примера, советую поэкспериментировать с ListModel, QObject* в QML и gc() — все не так гладко).

Такие наработки хороши: они оптимизируют на 70% время работы с модельками. Одна беда: они применимы в 5% случаев, которые составляют 0,01% от числа всех проблем отдельно взятого приложения. (цифры условные)
Благодарю за дополнение! Презенташку пролистал — действительно очень похожее решение, почему-то не попалось мне раньше. На хабре так вообще голяк (а может я просто гуглить не умею? :)). На выходных гляну повнимательнее.
Только полноправные пользователи могут оставлять комментарии.
Войдите, пожалуйста.