Une grosse question aussi de conception que celle-ci.
On suppose qu'on veuille créer une bibliothèque dynamique/plugin qui puisse être utilisée dans un programme global dans lequel tout type ou presque est encapsulé dans un DataObject - typiquement ITK -. Le but est de permettre d'utiliser ce plugin dans le programme avec plusieurs types de données "standards", comme int, float, double, ...
L'appel au plugin de la bibliothèque se fait par qqch du genre :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
plugin = new MonPlugin();
plugin->setInput(dataObject1);
plugin->setOuput(dataObject2);
plugin->run()
Lors du run(), la fonction adéquate est appelée par le run.

Une solution que je n'aime pas trop est d'utiliser un void* avec un enum indiquant le type, et on fait un switch sur la bonne fonction à choisir. C'est pas top top au niveau maintenabilité, mais apparemment Sutter aurait proposé quelque part cette solution. Je n'ai pas réussi à retrouver cette proposition, donc si qqn peut me la donner, que je puisse l'observer...

Une autre solution est celle qui a un temps été utilisée chez nous dans le labo. Le switch est généré automatiquement dans un en-tête sous forme de macro qu'on réutilise, la génération étant basée sur un fichier xml, le choix se faisant sur une chaîne retournée par le dataObject permettant de connaître son type.

Maintenant, j'ai pensé à une solution plus méta-programmation. On crée un vecteur de types standards. Puis, lors du run, on fait qqch du style :
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
 
typedef boost::mpl::vector<int, float, double> monVecteur;
class monPlugin
{
//...
void run()
{
  process<monVecteur>();
}
 
template<class vecteur>
void process<vecteur>()
{
  if(traits<begin<v>::type>::type() == dataObject->type()) // type() est une fonction retournant une chaîne de caractère décrivant le type, basé sur la classe traits
  {
    execute<begin<v>::type>();
  }
  else
  {
    process<pop_front<v>::type>();
  }
}
 
template<>
void process<boost::mpl::vector<> >()
{
  throw; // Erreur, type non instanciable
}
 
template<class Type>
void execute<Type>()
{
  // Execution du code du plugin
}
//...
};
Pour chaque solution, j'ai des griefs :
- la première utilise des void* et nécessite d'utiliser des switchs à maintenir dans chaque plugin
- la deuxième est basée sur des macros générées automatiquement, mais utilise des traits spécifique à chaque type, mais les macros sont spécifiques à un groupe de plugins pouvant travailler sur des types de données "compatibles"
- la troisième solution nécessite d'ajouter du code dans chaque plugin - le run + les process -, mais a aussi le mécanisme commun à un groupe de plugin grâce au vecteur de types

Est-ce que vous avez d'autres solutions ou des critiques et des préférences sur ces possibilités d'instancier automatiquement du code et de l'utiliser dans un plugin sans que l'utilisateur du plugin doive recompiler le plugin ?