qMetaTypeID не соответствует константному выражению? - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь получить идентификатор QMetaType во время компиляции, однако, когда я пробую этот очень простой базовый случай:

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(helloqt)

set(CMAKE_CXX_STANDARD 14)

find_package(Qt5Widgets REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(helloqt Qt5::Widgets)

main.cpp

#include <QApplication>
#include <QDebug>
struct Test{

};

Q_DECLARE_METATYPE (Test)
constexpr int test_enum = qMetaTypeId<Test>();
int main() {
    qDebug() << test_enum;
    return 0;
}

Я получаю следующую ошибку:

In file included from C:/msys64/mingw64/include/QtCore/qobject.h:54:0,
                 from C:/msys64/mingw64/include/QtCore/qcoreapplication.h:46,
                 from C:/msys64/mingw64/include/QtWidgets/qapplication.h:44,
                 from C:/msys64/mingw64/include/QtWidgets/QApplication:1,
                 from ...\main.cpp:1:
...\main.cpp:8:51:   in constexpr expansion of 'qMetaTypeId<Test>()'
C:/msys64/mingw64/include/QtCore/qmetatype.h:1754:43: error: 'static constexpr int QMetaTypeId2<T>::qt_metatype_id() [with T = Test]' called in a constant expression
     return QMetaTypeId2<T>::qt_metatype_id();
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
C:/msys64/mingw64/include/QtCore/qmetatype.h:1618:40: note: 'static constexpr int QMetaTypeId2<T>::qt_metatype_id() [with T = Test]' is not usable as a constexpr function because:
     static inline Q_DECL_CONSTEXPR int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
                                        ^~~~~~~~~~~~~~
C:/msys64/mingw64/include/QtCore/qmetatype.h:1618:96: error: call to non-constexpr function 'static int QMetaTypeId<Test>::qt_metatype_id()'
     static inline Q_DECL_CONSTEXPR int qt_metatype_id() { return QMetaTypeId<T>::qt_metatype_id(); }
                                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
mingw32-make.exe[3]: *** [CMakeFiles\helloqt.dir\build.make:63: CMakeFiles/helloqt.dir/main.cpp.obj] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:67: CMakeFiles/helloqt.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:79: CMakeFiles/helloqt.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:117: helloqt] Error 2

Похоже, что qMetaTypeID не является константным выражением, но это то, что я вижу в моем редакторе.

enter image description here

, и этот код прекрасно компилируется:

#include <QApplication>
#include <QDebug>

Q_DECL_CONSTEXPR int x = 3;
int main() {
    static_assert(x == 3);
    return 0;
}

(я протестировал без использования constexpr, и он не работает, чтокак и ожидалось).

Мой компилятор - Mingw-64 с версией QT 5.10.1.

1 Ответ

0 голосов
/ 05 июня 2018

Это действительно просто: идентификатор метатипа не предназначен для постоянного выражения в общем .Для чего-либо, кроме некоторых базовых типов, назначенные значения будут различаться - они назначаются во время выполнения и зависят от относительного времени использования отдельных модулей Qt, изменений в модулях Qt, изменений в вашем коде и т. Д. Ваш проект не должен предполагать, что этиявляются постоянными значениями или даже одинаковыми между запусками, не говоря уже о машинах.

Идентификационный код присваивает их во время выполнения поточно-ориентированным способом.

TL; DR

  • Если вам нужно использовать Q_DECLARE_METATYPE для себя , идентификатор будет , а не constexpr.

  • id равен constexpr в особом случае встроенных типов Qt * только 1024 * .

Можно ли это сделать для пользовательского типа?

Если вам действительно нужен qMetatypeId<Type>(), чтобы быть constexpr, вы должны взять на себя ответственность за это, специализируясь на struct QMetaTypeId<Type> (или QMetaTypeId2).И вы должны убедиться, что динамически зарегистрированный тип (потому что да, динамическая регистрация необходима для того, чтобы Qt захватила вспомогательные функции для типа) была такой же, как статически назначенная.

Нет способа получить Qtпопытаться зарегистрироваться по заданному идентификатору "подсказка".Было бы неплохо, но в настоящее время нет способа сделать это (насколько я знаю, для этого не потребуется использовать частные заголовки и т. Д.).

// https://github.com/KubaO/stackoverflown/tree/master/questions/static-metatype-50703377
#include <QtCore>

// Interface

#if defined(QT_WIDGETS_LIB) && defined(Q_OS_MAC)
constexpr int StaticMetatypeId = QMetaType::User + 1;
#else
constexpr int StaticMetatypeId = QMetaType::User + 0;
#endif

#define MY_DECLARE_STATIC_METATYPE(TYPE, METATYPEID) \
   MY_DECLARE_STATIC_METATYPE_IMPL(TYPE, METATYPEID)

#define MY_DECLARE_STATIC_METATYPE_IMPL(TYPE, METATYPEID) \
    QT_BEGIN_NAMESPACE \
    template<> struct QMetaTypeId2<TYPE> \
    { \
        enum { Defined = 1, IsBuiltIn = false, MetaType = METATYPEID };   \
        static inline constexpr int qt_metatype_id() { return METATYPEID; } \
        static inline constexpr const char *static_name() { return #TYPE; } \
    }; \
    QT_END_NAMESPACE

template <typename T>
int registerStaticMetaType() {
   auto id = qRegisterMetaType<T>(QMetaTypeId2<T>::static_name(),
                                  reinterpret_cast<T*>(quintptr(-1)));
   Q_ASSERT(id == qMetaTypeId<T>());
   return id;
}

// Use

struct Foo {};
MY_DECLARE_STATIC_METATYPE(Foo, StaticMetatypeId + 0)

int main() {
   registerStaticMetaType<Foo>(); // StaticMetatypeId + 0
                                  // other registrations must follow in ascending order
   static_assert(qMetaTypeId<Foo>() == StaticMetatypeId+0, "try again :(");
}
...