您应该声明一个可以帮助您的包装器。我能想到的最好的方法是根据Qt的版本有几个定义:
template<typename T>
struct is_registered
{
enum
{
value =
#if QT_VERSION >= 0x050000 // Qt 5.0.0
QMetaTypeId2<T>::Defined
#elif QT_VERSION >= 0x040000 // Qt 4.0.0
QMetaTypeId2<T>::Defined
#endif
};
};
这不是美学,但这是功能性的,在您的代码中您可以使用is_registered<T>::value
而不必担心 Qt 的版本。另外,我目前没有 Qt5,所以我不能告诉你QMetaTypeId2<T>::Defined
它是否正确(尽管我认为它是正确的)。
无法用于qMetaTypeId<T>()
检查类型是否已注册。事实上,表达式qMetaTypeId<T>()
总是有效的,不管是什么类型。如果未注册,则函数的主体将无法编译(更准确地说:在 Qt 4 和 5(目前)中,qMetaTypeId<T>()
仅在未注册类型时调用另一个无法编译的函数。因此,您不能使用 SFINAE 对其进行测试。结果,leemes 在他(现已删除)答案中给出的代码将无法按预期工作。
代码是:
struct _test_is_declared_metatype
{
template<class T>
static auto test(T* t) -> decltype(qMetaTypeId<T>(), std::true_type());
static std::false_type test(...);
};
template<class T>
struct is_declared_metatype : decltype(_test_is_declared_metatype::test<T>(0))
{
};
为什么这行不通?其目的是因为调用qMetaTypeId<T>()
未注册的类型会导致编译错误,“SFINAE 将在未注册类型时排除第一个函数”。这里的问题是它qMetaTypeId<T>()
始终是一个有效的表达式,qMetaTypeId<T>(), std::true_type()
也是如此,并且decltype(qMetaTypeId<T>(), std::true_type())
是完美定义的(使用 value std::true_type
)。
这是因为 stem 的编译错误qMetaTypeId<T>()
源于函数的主体,而不是其原型(顺便说一下,只有在声明并正确调用了函数中的函数时,代码才会编译decltype
,例如,非模板函数没有模板参数)。
因此,因为这种过载test()
比可变参数更具体,它总是被选中,因此它总是“返回”类型已注册;您可以在以下测试代码中看到它:
// ----------------------------------------------------------
// qmetatype.h simplification -------------------------------
// ----------------------------------------------------------
template<typename T>
struct metatype
{
enum { defined = 0 };
};
template<typename T>
struct metatype2
{
enum { defined = metatype<T>::defined };
static inline int id() { return metatype<T>::id(); }
};
template <typename T>
inline int metatypeId(
T * /* dummy */ = 0
)
{
return metatype2<T>::id();
}
#define register_meta_type( _type_ ) \
template<> \
struct metatype< _type_ > \
{ \
enum { defined = 1 }; \
static int id() \
{ \
/* Run-time registration in Qt */ \
return __COUNTER__; \
}; \
};
// ----------------------------------------------------------
// ----------------------------------------------------------
// ----------------------------------------------------------
class TestA {};
register_meta_type(TestA)
class TestB {};
class TestC {};
register_meta_type(TestC)
class TestD {};
#include <type_traits>
struct _test_is_declared_metatype
{
/*
metatypeId<T>() is always a valid expression. So this overload is
always taken
*/
template<class T>
static auto test(T* t) -> decltype(metatypeId<T>(), std::true_type());
static std::false_type test(...);
};
template<class T>
struct is_declared_metatype : decltype(_test_is_declared_metatype::test<T>(0))
{
};
#include <iostream>
#define PRINT_DEF( _type_ ) std::cout << #_type_ << " registered ? " << is_declared_metatype< _type_ >::value << "\n";
int main()
{
std::cout << std::boolalpha;
PRINT_DEF(TestA);
PRINT_DEF(TestB);
PRINT_DEF(TestC);
PRINT_DEF(TestD);
}
您可能想了解更多关于 SFINAE的信息。此外,您可以在此处阅读qmetatype.h
。