Vérifiez si le type est déclaré en tant que système de méta-type (pour SFINAE)

Pour faire la distinction entre un cas et un paramètre t de type T utilisant SFINAE, je veux savoir si l’instruction

 QVariant::fromValue(t); 

et / ou

 QVariant::value(); 

comstack. Si l’un comstack, l’autre aussi, sauf si vous piratez le système de méta-types. Ils comstacknt si et seulement si T a été déclaré avec Q_DECLARE_METATYPE(T) .

Exemple d’utilisation très simple, où l’on veut imprimer le type d’une valeur simplement en q Débogant un équivalent enveloppé de variantes, si et seulement si pris en charge par le système de méta-types (je n’en ai pas besoin, mais cela montre le problème de manière minimale. Exemple):

 template // enable if T NOT registered in the Qt meta type system void print(const T &t) { qDebug() << t; } template // enable if T registered in the Qt meta type system void print(const T &t) { qDebug() << QVariant::fromValue(); } 

Je connais plusieurs possibilités (similaires) pour le faire, mais toutes introduisent des structures d’aide, un enable_if compliqué, etc. Maintenant, je sais qu’il existe QTypeInfo qui, je suppose, fournit déjà quelque chose comme un “est déclaré dans le méta type Qt système “trait de type. Cependant, cette classe n’est pas documentée et il n’est donc pas suggéré de l’utiliser dans le code à long terme et productif, car cela pourrait changer d’une version à l’autre.

Existe-t-il un moyen très simple (plus simple qu’avec un “vérificateur” + enable_if) d’inscrire une spécialisation SFINAE si un type T est pris en charge par QVariant?

Veuillez noter que la solution doit toujours être portable entre différentes versions de Qt (Qt4 et Qt5 peuvent utiliser une définition QTypeInfo différente). Cependant, j’utilise C ++ 11, j’ai donc access à std::enable_if par exemple.

La méthode “non-portable” consiste à utiliser la définition interne de QMetaTypeId2::Defined dans un enable_if (c’est une valeur enum définie par 0 ou 1). Ainsi, une solution de travail serait:

 template typename std::enable_if<!QMetaTypeId2::Defined>::type print(const T &t) { qDebug() << t; } template typename std::enable_if<QMetaTypeId2::Defined>::type print(const T &t) { qDebug() << QVariant::fromValue(); } 

Cependant, étant donné que QMetaTypeId2 n’est pas documenté et ne contient que des éléments internes, il ne doit pas apparaître dans le code client.

Vous devriez déclarer un emballage qui vous aidera. Le mieux que je puisse penser est d’avoir plusieurs définitions, basées sur la version de Qt:

 template struct is_registered { enum { value = #if QT_VERSION >= 0x050000 // Qt 5.0.0 QMetaTypeId2::Defined #elif QT_VERSION >= 0x040000 // Qt 4.0.0 QMetaTypeId2::Defined #endif }; }; 

Ce n’est pas esthétique, mais c’est fonctionnel, et dans votre code, vous pouvez utiliser is_registered::value sans avoir à vous soucier de la version de Qt. De plus, je n’ai pas Qt5 pour le moment, donc je ne peux pas vous dire si QMetaTypeId2::Defined est correct pour cela (bien que je le pense bien).


Il est impossible d’utiliser qMetaTypeId() pour vérifier si un type a été enregistré. En fait, l’expression qMetaTypeId() est toujours valide, quel que soit le type. S’il n’est pas enregistré, le corps de la fonction ne sera pas compilé (pour être plus précis: en Qt 4 et 5 (pour le moment), qMetaTypeId() appelle uniquement une autre fonction qui ne comstack pas si le type n’est pas Ainsi, vous ne pouvez pas utiliser SFINAE pour le tester, de sorte que le code que le code donné dans sa réponse (maintenant supprimée) ne fonctionnera pas comme prévu .

Le code était:

 struct _test_is_declared_metatype { template static auto test(T* t) -> decltype(qMetaTypeId(), std::true_type()); static std::false_type test(...); }; template struct is_declared_metatype : decltype(_test_is_declared_metatype::test(0)) { }; 

Pourquoi ça ne marche pas? L’intention était que, parce que l’appel de qMetaTypeId() sur un type non enregistré entraîne une erreur de compilation, “SFINAE exclurait la première fonction lorsque le type n’est pas enregistré” . Le problème ici est que qMetaTypeId() est toujours une expression valide, donc qMetaTypeId(), std::true_type() est aussi, et decltype(qMetaTypeId(), std::true_type()) est parfaitement défini (avec la valeur std::true_type ).
Ceci parce que l’erreur de compilation de qMetaTypeId() provient du corps de la fonction, pas de son prototype (en fait, le code ne sera compilé que si la fonction dans le decltype est déclarée et correctement appelée, c’est-à-dire qu’aucun argument de modèle pour une fonction non-template par exemple).
Ainsi, comme cette surcharge de test() est plus spécifique que la variable, elle sera toujours choisie, donc elle «retournera» toujours que le type est enregistré; vous pouvez le voir dans le code de test suivant:

 // ---------------------------------------------------------- // qmetatype.h simplification ------------------------------- // ---------------------------------------------------------- template struct metatype { enum { defined = 0 }; }; template struct metatype2 { enum { defined = metatype::defined }; static inline int id() { return metatype::id(); } }; template  inline int metatypeId( T * /* dummy */ = 0 ) { return metatype2::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  struct _test_is_declared_metatype { /* metatypeId() is always a valid expression. So this overload is always taken */ template static auto test(T* t) -> decltype(metatypeId(), std::true_type()); static std::false_type test(...); }; template struct is_declared_metatype : decltype(_test_is_declared_metatype::test(0)) { }; #include  #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); } 

Vous voudrez peut-être en savoir plus sur SFINAE . Aussi, vous pouvez lire qmetatype.h ici .