Qt/C++: есть ли способ автоматически регистрировать метатипы?

Чтобы получить всю функциональность системы метатипов Qt, мне нужно вызвать qRegisterMetaType во время выполнения во время инициализации моего приложения. В частности, мне нужно зарегистрироваться:

  • тип указателя для каждого из моих классов, производных от QObject, то есть qRegisterMetaType<MyClass *>(), и
  • каждый тип, который я объявил как метатип, используя Q_DECLARE_METATYPE.

В настоящее время я делаю это с помощью функции, которая просто вызывает qRegisterMetaType для каждого из них, которые я вручную поддерживаю и обновляю по мере необходимости.

Это, однако, довольно неудобно и подвержено ошибкам для меня. Я часто забывчив, и если я забуду зарегистрировать метатип, это не приведет к ошибкам компиляции, но вызовет ошибки времени выполнения, когда мой код попытается использовать систему метатипов и потерпит неудачу, потому что я забыл зарегистрировать один из них. Иногда ошибку бывает трудно отследить.

Итак, есть ли способ, которым я могу автоматически зарегистрировать все мои классы, производные от QObject, и объявленные метатипы?

Некоторые вещи, которые могут повлиять на решение:

  • Все мои классы, производные от QObject, которые мне нужно зарегистрировать, также являются производными от моего собственного единственного базового класса, поэтому я могу использовать его для реализации функций, которые унаследует любой другой класс.
  • Я готов использовать тайные методы перкомпилятора, если это необходимо!

person GuyGizmo    schedule 29.03.2018    source источник
comment
Это то же самое, что и с неподключенными сигналами/слотами. Вы получите предупреждение, когда qRegisterMetaType не объявлен, но требуется. Перед отправкой приложения вы захотите проверить свои журналы/выводы отладки. Я не думаю, что есть отличный способ сделать это автоматически.   -  person user3606329    schedule 29.03.2018
comment
В отладочных сборках я фильтрую сообщения Qt и ставлю точку останова на предупреждения. Таким образом, если у Qt есть предупреждение, я знаю.   -  person drescherjm    schedule 29.03.2018
comment
проверьте, помогает ли это Q_DECLARE_METATYPE для класса шаблона   -  person Mohammad Kanan    schedule 29.03.2018
comment
Это немного сложная вещь. Вам нужно создать свою собственную фабрику, которая будет регистрировать функторы, которые будут вызывать qRegisterMetaType во время выполнения. И это следует использовать для каждого экземпляра exe/dll. Это можно сделать с помощью какого-то глобального контейнера, но поскольку в C++ порядок инициализации переменных не определен, это может быть нетривиально. Возможно, я скоро предоставлю вам пример   -  person Dmitry Sazonov    schedule 30.03.2018


Ответы (1)


Я не могу придумать способ автоматического объявления метатипа, то есть без предоставления макроса Q_DECLARE_METATYPE в заголовке класса, но можно было бы предоставить макрос, в котором регистрация выполняется автоматически (более или менее вместе с объявление метатипа). Этот пример предназначен для объявления и регистрации только типа указателя данного класса:

#include <QMetaType>

#define METAID(CLASS)                \
    Q_DECLARE_METATYPE(CLASS*)       \
    static struct CLASS##Metaid      \
    {                                \
      CLASS##Metaid()                \
      {                              \
        qRegisterMetaType<CLASS*>(); \
      }                              \
    } _CLASS##metaid;

Макрос выше можно использовать вместо Q_DECLARE_METATYPE:

class MyClass : public QObject
{
Q_OBJECT
};

METAID(MyClass)
person p-a-o-l-o    schedule 30.03.2018
comment
Нет причин регистрировать классы на основе OObject в качестве метатипов. Это может быть полезно только для указателей. - person Dmitry Sazonov; 30.03.2018
comment
Еще одна проблема: copy ctor является приватным в QObject, поэтому создавать ctor в дочерних классах не имеет смысла. - person Dmitry Sazonov; 30.03.2018
comment
Да, @DmitrySazonov, но ОП говорит, что они должны зарегистрировать классы, производные от QObject ... или я неправильно понял? - person p-a-o-l-o; 30.03.2018
comment
Это хороший вопрос к ОП. Только один случай, который я могу себе представить, - это сохранить указатель на экземпляр на основе QObject в QVariant. Насколько я понял, OP должен автоматически вызывать qRegisterMetaType для каждого использования Q_DECLARE_METATYPE. - person Dmitry Sazonov; 30.03.2018
comment
Это очень неправильно, если CLASS является некопируемым типом. Я не уверен, компилируется ли он вообще, а если нет, то связывается ли он. Если да, то это ожидаемая ошибка времени выполнения. Я также не уверен, допустимо ли вызывать qRegisterMetaType до создания экземпляра QCoreApplication. Это как минимум нужно проверить. Наконец, в каждой единице перевода, содержащей этот заголовок, будет создано CLASSMetaid экземпляров — в конце концов, они static. Это немного расточительно. - person Kuba hasn't forgotten Monica; 30.03.2018
comment
@KubaOber Некопируемые классы не будут компилироваться, Q_DECLARE_METATYPE, как обычно, завершится ошибкой. Кажется, что объявление метатипов и регистрация проходят успешно даже без экземпляра QCoreApplication. Наконец, да: будет экземпляр CLASSMetaid размером в один байт для каждой единицы компиляции, включая заголовок CLASS. - person p-a-o-l-o; 30.03.2018
comment
@ p-a-o-l-o Я только хочу зарегистрировать тип указателя всех моих классов. Другие участники этого потока правы в том, что не регистрируют тип класса без указателя. - person GuyGizmo; 30.03.2018
comment
@p-a-o-l-o Я не думал об использовании статической структуры для этого, и я думаю, что это подходящее решение для меня. Прежде чем я приму его, вы должны внести несколько изменений: а) изменить его так, чтобы он не регистрировал тип класса без указателя, б) изменить экземпляры CLASSMetaid на CLASS ## Metaid, чтобы токены правильно объединялись, и в) изменить его на используйте qRegisterMetaType() вместо qMetaTypeId<T>(), поскольку, несмотря на то, что в настоящее время он эквивалентен, это не гарантирует работу в будущих версиях Qt - лучше использовать функцию API, явно предназначенную для регистрации метатипов. - person GuyGizmo; 30.03.2018
comment
@p-a-o-l-o, а как насчет классов с пространствами имен? Это была моя проблема некоторое время назад. - person Dmitry Sazonov; 02.04.2018