qMetaTypeID不评估为常量表达式?

时间:2018-06-05 15:08:16

标签: c++ qt qt5 compile-time constant-expression

我试图在编译时获取QMetaType的ID,但是当我尝试这个非常简单的基本情况时:

的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 :(得分:0)

这非常简单:元数据类型ID不是一般的 的常量表达式。除了一些基本类型之外的任何东西,分配的值都会有所不同 - 它们在运行时分配,并取决于各个Qt模块的使用的相对时间,Qt模块的变化,代码的变化等。您的设计不能假设那些是不变的值,甚至在运行之间是相同的,在机器之间不要介意。

id代码在运行时以线程安全的方式分配它们。

TL; DR

  • 如果您必须自己使用Q_DECLARE_METATYPE ,则ID为 constexpr

  • 在Qt内置类型的特殊情况下,ID constexpr

可以为自定义类型完成吗?

如果您真的需要qMetatypeId<Type>()成为constexpr,那么您必须负责通过专门​​化struct QMetaTypeId<Type>(或QMetaTypeId2)来实现这一目标。并且您必须确保动态注册的类型(因为是,动态注册是Qt捕获该类型的辅助函数所必需的)与静态分配的类型相同。

没有办法让Qt尝试在给定的ID上注册&#34;提示&#34;。它很好,但目前还没有办法(我知道,不需要使用私有标头等)。

// 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 :(");
}