Bonsoir,
Voici d'abord le code (simplifié et regroupé en un seul fichier) :
L'objectif du code est de fournir une classe de politique basé sur le CRTP (et un autre TP), offrant un comportement avec un point de variation.
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
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 #include<algorithm> #include<cstdlib> #include<iostream> #include<utility> #include<vector> //Déclaration ancitipé template<class DrawerData> struct Drawer; //Première fonction template générique template<class T, class DrawerData> void accept(T& t, Drawer<DrawerData>& d) { t.accept(d); } //Doit être utilisé en tant que classe de base template<class Entity, class C> struct AcceptPolicy { C& c; AcceptPolicy(C& c) : c(c) {} //C'est une classe de politique qui offre ce comportement template<class DrawerData> void accept(Drawer<DrawerData>& d) { std::for_each(c.begin(),c.end(), [&d](typename C::value_type& t) { ::accept(t,d); //Permettre un point de variation en restant générique } ); } }; /*Pas de changement possible avant*/ //Une utilisation de cette classe de politique struct MyEntity : AcceptPolicy<MyEntity,std::vector<std::pair<MyEntity*,int> > > { typedef std::pair<MyEntity*,int> PairType; std::vector<PairType> v; MyEntity() : AcceptPolicy(v) { v.push_back(PairType(new MyEntity(0),0)); } MyEntity(int) : AcceptPolicy(v) {} }; //Une surcharge d'accept "meilleur choix" que la version générique template<class DrawerData> void accept(MyEntity::PairType& t, Drawer<DrawerData>& d) { std::cout << 0; t.first->accept(d); std::cout << 1; } //Une classe pour tester struct MyDrawerData {}; //Une spécialisation de la classe template déclaré template<> struct Drawer<MyDrawerData> { }; int main() { //De quoi testet Drawer<MyDrawerData> d; MyEntity e; e.accept(d); }
L'idée que j'ai eu est d'appeler la fonction ::accept(t,o); dans la fonction membre accept(o) sur l'ensemble des éléments d'un conteneur connu par la classe de politique grâce au constructeur de celui-ci.
La version générique de la fonction ::accept(t,o); se contente juste d'appeler t->accept(o); mais si le type des valeurs du conteneur sont plus complexe (comme dans ce code : une pair) il faut le redéfinir, pour ca je propose une surcharge (template pour conserver la généricité sur le second paramètre) de ::accept dans ce cas là.
Ce code fonctionne comme prévu sous VC++ mais pas sous gcc :
Je pense que l'erreur vient des points d'instanciation des templates à des endroits différents pour VC++ et GCC ainsi dans un cas pas de problème et dans l'autre les surcharges ne sont pas connues lors de l'utilisation : d'où l'erreur (NB: Je suis loin d'être convaincu de mon analyse ...)In function 'void accept(T&, Drawer<DrawerData>&) [with T = std::pair<MyEntity*, int>, DrawerData = MyDrawerData]':
30:4: instantiated from 'AcceptPolicy<Entity, C>::accept(Drawer<DrawerData>&) [with DrawerData = MyDrawerData, Entity = MyEntity, C = std::vector<std::pair<MyEntity*, int> >]::<lambda(std::vector<std::pair<MyEntity*, int> >::value_type&)>'
28:6: instantiated from 'AcceptPolicy<Entity, C>::accept(Drawer<DrawerData>&) [with DrawerData = MyDrawerData, Entity = MyEntity, C = std::vector<std::pair<MyEntity*, int> >]::<lambda(std::vector<std::pair<MyEntity*, int> >::value_type&)>'
27:3: instantiated from 'void AcceptPolicy<Entity, C>::accept(Drawer<DrawerData>&) [with DrawerData = MyDrawerData, Entity = MyEntity, C = std::vector<std::pair<MyEntity*, int> >]'
69:12: instantiated from here
14:3: error: 'struct std::pair<MyEntity*, int>' has no member named 'accept'
Ma question est donc comment faire ce que je veut (mettre en place un point de variation dans une fonction générique), sachant que ce qui est au dessus de :
Doit être générique, dans mon architecture (plus complète), le reste est amener à évoluer de manière significative : d'autre classes similaires à MyEntity, des possibilités d'utiliser d'autre classes que MyDrawerData (et donc des spécialisations qui en découle). Et que l'ordre de déclaration/définition des éléments est difficilement modifiable (j'ai tout regroupe en un seul fichier, mais il s'agit au départ d'include, ca impose "plus ou moins" l'ordre dans mon cas).
Code : Sélectionner tout - Visualiser dans une fenêtre à part /*Pas de changement possible avant*/
Merci d'avance pour les éventuelles idées/suggestions.
Partager