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
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
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
est aussi, et decltype(qMetaTypeId
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 .