Как и когда использовать Q_DECLARE_METATYPE

Мне нужно преобразовать QSqlRecord в QVariant и обратно по всему моему проекту. Для этого я добавил

Q_DECLARE_METATYPE(QSqlRecord);

в файлах .h классов, которые требуют приведения. У меня также есть базовый класс, от которого наследуют несколько детей, в этом случае я полагаю, что достаточно включить Q_DECLARE_METATYPE только один раз в базовый класс. Поэтому у меня есть, например:

  • widgetBaseClass: объявляет метатип
  • widgetChildClass1: наследует widgetBaseClass, не объявляет метатип
  • widgetChildClass2: наследует widgetBaseClass, не объявляет метатип
  • myTableModel: объявляет метатип

Когда я пытаюсь запустить такую ​​программу, я получаю

Redefinition of 'QMetaTypeId<QSqlRecord>

из widgetBaseClass, указывая на предыдущее объявление в myTableModel. Если, с другой стороны, я удаляю объявление, я получаю:

static_assert failed "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system");

Из того, как я понимаю работу Q_DECLARE_METATYPE, это означает, что если я объявлю его, это приведет к ошибке, потому что он уже был объявлен где-то еще, но если я его не объявлю, я не могу выполнить преобразование из QVariant, потому что он не распознает объект как действительный QVariant, что мне не хватает?


person Nicolo Castro    schedule 16.03.2017    source источник


Ответы (2)


Вы должны поместить Q_DECLARE_METATYPE(QSqlRecord) только в один заголовок, а затем просто включить его везде, где это необходимо. Q_DECLARE_METATYPE(QSqlRecord) должен находиться вне каких-либо классов и пространств имен. Из документации Qt:

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

person em2er    schedule 16.03.2017
comment
Спасибо за ответ, я поместил Q_DECLARE_METATYPE вне пространств имен, однако он находится в файле .h другого класса. Должен ли я вместо этого просто создать конкретный файл .h со всеми Q_DECLARE_METATYPE, которые мне нужны, и включать их всякий раз, когда мне это нужно? - person Nicolo Castro; 16.03.2017
comment
@NicoloCastro из документации Qt В идеале этот макрос следует разместить под объявлением класса или структуры. Если это невозможно, его можно поместить в частный заголовочный файл, который необходимо включать каждый раз, когда этот тип используется в QVariant. - person em2er; 16.03.2017
comment
Хорошо, спасибо, извините за то, что я просмотрел это и, видимо, не зарегистрировал абзац. - person Nicolo Castro; 16.03.2017

Вы используете Q_DECLARE_METATYPE в классах с общедоступным конструктором, деструктором, копирующим конструктором, поэтому подходит QSqlRecord. Просто убедитесь, что этот макрос используется только один раз для объявления класса. Возможно, вы что-то пропустили #pragma once?

Используйте его в своих классах после объявления класса вне фигурных скобок пространства имен:

//mystruct.h
namespace MyNamespace
{
struct MyStruct
{
    int i;
    ...
};
}

Q_DECLARE_METATYPE(MyNamespace::MyStruct)

См. документацию здесь: http://doc.qt.io/qt-5/qmetatype.html#Q_DECLARE_METATYPE

person MateuszL    schedule 16.03.2017
comment
Почему я не должен использовать метатип объявления для классов из Qt? Как я могу привести QVariant к классу Qt? или мне нельзя это делать? - person Nicolo Castro; 16.03.2017
comment
Извините, я обновил информацию из документации и быстро исправил ответ. - person MateuszL; 16.03.2017
comment
Ок, спасибо. Итак, в классах, которые я пишу, которые, как я знаю, я буду использовать, я могу поместить объявление непосредственно в тот же файл, за пределами пространства имен, для других я должен включить его, но вот моя проблема, прямо сейчас, если я включу его говорит мне, что он уже включен (переопределение 'QMetaTypeId‹QSqlRecord›), если я его удаляю, он говорит мне, что я его не объявлял. - person Nicolo Castro; 16.03.2017
comment
это действительно похоже на то, что ваш файл .h отсутствует, включая защиту (либо #pragma Once, либо #ifndef FILENAME #define FILENAME) - person MateuszL; 16.03.2017