Bonsoir,

Voici d'abord le code (simplifié et regroupé en un seul fichier) :
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'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.

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 :
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'
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 ...)

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 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
/*Pas de changement possible avant*/
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).

Merci d'avance pour les éventuelles idées/suggestions.