Bonsoir à tous
Voici une question simple.
Soient 2 classes A et B que je ne peux modifier en rien.
Je souhaite savoir, à la compilation, s'il existe un lien d'heritage entre elles.
Merci
Bonsoir à tous
Voici une question simple.
Soient 2 classes A et B que je ne peux modifier en rien.
Je souhaite savoir, à la compilation, s'il existe un lien d'heritage entre elles.
Merci
Bonjour,
std::is_base_of du header <type_traits> si tu peux te permettre le C++11, sinon SFINAE mais ca ne te donnera que les héritages publiques.
Tu l'as aussi en TR1 (plus largement supporté que C++11).
Sinon, effectivement, ça se fait assez aisément avec SFINAE:
Si ta classe Derived dérive de Base, alors my_is_base_of<Base,Derived>::value == true ; sinon, il vaudra false. Et c'est une constante connue à la compilation (et c'est un code relativement abscons ; ben oui, mais faut ce qu'il faut).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 template <class A, class B> struct my_is_base_of { typedef char one[1]; typedef char two[2]; one check(A*); two check(...); static const bool value = (sizeof(check((B*)0)) == sizeof(one)); }
[FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.
Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.
@Emmanuel Deloget: "aisément " Pas exactement, ce que tu fais avec SFINAE donne les relations d'héritage publique, alors que is_base_of doit donner toutes les relations d'héritage.
Merci pour vos reponses
Je souhaiterai préciser que si B n'hérite pas de A alors il y echec de la compilation.
J'ai retenu une idée parmi vos réponses mais ca ne marche pas voici le code et le message d'erreur.
Si vous avez une alternative du meme genre, je suis preneur.
le message d'erreur précise qui ne compile pas "static int check(U*);" mais plutôt l'autre fonction.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 struct A{}; struct B:public A{}; template<bool> struct enable_if{}; template<> struct enable_if<true>{typedef int type; }; template < class U, class V> struct is_base_of { static int check(U*); static double check(...); // astuce typedef typename enable_if<sizeof (check((V*) (NULL)) )==sizeof(int)>::type check_derivation; }; int _tmain(int argc, _TCHAR* argv[]) { is_base_of<A,B> type;type; return 0; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1>------ Build started: Project: Stl, Configuration: Debug Win32 ------ 1>Compiling... 1>Stl.cpp 1>c:\tests\stl\stl\stl.cpp(28) : error C2039: 'type' : is not a member of 'enable_if<__formal>' 1> with 1> [ 1> __formal=false 1> ] 1> c:\tests\stl\stl\stl.cpp(29) : see reference to class template instantiation 'is_base_of<U,V>' being compiled 1>c:\tests\stl\stl\stl.cpp(28) : error C2146: syntax error : missing ';' before identifier 'check_derivation' 1>c:\tests\stl\stl\stl.cpp(28) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int 1>c:\tests\stl\stl\stl.cpp(28) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int 1>Build log was saved at "file://c:\Tests\Stl\Stl\Debug\BuildLog.htm" 1>Stl - 4 error(s), 0 warning(s)
Effectivement
Il manque une partie du message en fait. Je ne m'en suis pas rendu compte (mais en même temps, je faisais 36 choses différentes en même temps). Ca se trouve, je l'ai pensé et je ne l'ai pas écrit (c'est tout moi ça).
La partie qui manque était grosso-modo:
Pour déterminer si un héritage existe et est privé, il est nécessaire de passer par le support du compilateur : __is_base_of(Base,Derived) sur g++ et Visual C++ (notons la notation fonctionnelle : ce n'est pas un template, c'est une fonction du compilateur qui intervient sur des types ; cf http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html pour g++ et http://msdn.microsoft.com/fr-fr/library/ms177194 pour VC++ ; il est heureux que les deux vendeurs nous aient donné la même interface).Note que ça ne fonctionne que si tu peux écrire Base* p = (Derived*)0; puisque c'est la base du principe, ce qui veut dire que cette classe ne supporte pas les héritages protégés ou privés (qui sont rares, de toute manière).
Du coup, on peut écrire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #if defined(__GNUG__) || (defined(__MSVC__) && (_MSC_VER >= 1400)) template <class _Base, class _Derived, bool known_compiler> struct is_base_of<_Base, _Derived> { static const bool value = __is_base_of(_Base,_Derived); }; #else // cas général limité template <class _Base, class _Derived> struct is_base_of { typedef char one[1]; typedef char two[2]; one check(_Base*); two check(...); static const bool value = (sizeof(check((_Derived*)0)) == sizeof(one)); }; #endif
[FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.
Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.
Tu ne peux qu'avoir une erreur de compilation, puisque enable_if<false>::type n'est pas défini - seul enable_if<true>::type l'est. C'est d'ailleurs ce que te dis le compilateur.
Donc si A et B ne sont pas liés par une relation d'héritage, check_derivation ne peut pas exister.
Un type trait qui cherche à déterminer si quelque chose est vrai ne peut pas utiliser la technique que tu mets en oeuvre. Le fait d'avoir un type qui est un alias sur int si une condition est vérifiée ne peut d'ailleurs pas beaucoup t'aider par la suite. Le but est d'avoir une structure qui te dis si telle ou telle relation est vraie - un static const bool fera l'affaire.
Edit: juste un petit point : rien dans le standard ne te garanti que sizeof(int) != sizeof(double). Les tailles de sizeof(char[1]) et sizeof(char[2]), par contre, sont garanties par le standard et sont respectivement un byte et deux bytes - ce sont donc des tailles différentes.
[FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.
Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.
Bonjour.
J'ajouterai que, de mémoire, enable_if est plutôt défini de cette manière :
Ce qui permet d'évaluer une expression et de directement « retourner » un type si cette expression est vraie.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 template <bool, typename _Tp = void> struct enable_if {}; template <typename _Tp> struct enable_if<true, _Tp> { typedef _Tp type; };
Quant à is_base_of, ça correspond à l'expression à évaluer.
C'est pourquoi il y a une variable membre de type booléen et pas un typedef.
Donc ne modifie pas la structure proposée pas Emmanuel Deloget !
Ça s'utilise de cette manière (par exemple) :
Ainsi, la variable x est du type B si et seulement si B hérite (directement ou non) de A.
Code : Sélectionner tout - Visualiser dans une fenêtre à part typename enable_if< is_base_of<A, B>::value, B >::type x
Sinon, le compilateur n'est pas en mesure de déterminer un type pour x, et alors la compilation échoue.
Comme discuté plus haut, la détection des héritage protégé et privé dépend de l'implémentation de is_base_of.
merci pour vos réponses
En fait le code que j ai envoyé, devrait fonctionner car B hérite bien de A et donc la premiere implementation de check devrait etre utilisée ce qui donne enable_if<true>, or il ne voit que la seconde meme quand j instantie is_base_of<A,A>.
J ai décidé, pour le type de retour de check, double versus int plutôt que one versus two car sinon le compliateur me renvoie une erreur C2090; le compilateur veut un pointeur en type de retour pas un tableau.
Je continue à regarder vos réponses
et merci encore pour le temps consacré.
Mathieu
cette implementation simplifiée de enable_if empèche la compilation c 'est bien ce que je cherchais à faire.
Je propose
dans le configuration suivante:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 template<bool> struct enable_if{}; template<> struct enable_if<true>{typedef int type; }; template < class U, class V> struct is_derivated_impl { typedef int one[1]; typedef int two[2]; static one & check(U*); static two & check(...); // astuce static const bool value = sizeof (check( static_cast<V*> (NULL)) )==sizeof(one); //astuce }; template < class U, class V> struct is_derivated { typedef typename enable_if<is_derivated_impl<U,V>::value>::type check_derivation; };
une instance de is_derivated<A,C> provoque une erreur de compliation alors que is_derivated<A,A> ou is_derivated<A,B> non.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 struct A{}; struct B: public A{}; struct C{};
Juste par curiosité, tu peux mettre quelques exemples d'application de is_derivated, s'il-te-plaît ?
[FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.
Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.
Partager