Chapitre 1
SPECIALISATION STATIQUE
 
 
Précédent Suivant
 

Spécialisation statique
Métaprogrammation générique (1/2)
* Repose sur plusieurs mécanismes
* Généricité / patrons de composants
* En C++: les templates
* Instanciation des patrons sans surcoût
* Au plus proche d'un code dédié
* En C++: chaque instanciation d'un générique ==> code dédié
* En Java: mécanisme de "type erasure" ==> pas de code dédié
* Spécialisation "statique"
* Possibilité de spécialisation d'un composant générique
* Basée sur le type (ou la valeur statique) des paramètres génériques
Métaprogrammation générique (2/2)
* Objectifs
* Composants génériques (au sens large)
* Sans ou avec peu de baisse de performance
* Le génie logiciel nous apprend que généralement
* La généricité (au sens large) a un coût
* Recherche d'un compromis entre généricité et efficacité
* Mais avec la programmation générique
* Beaucoup de travail à la compilation ==> peu de pertes
Spécialisation statique
* Composant générique = modèle indépendant des types
* Mais cela peut être pénalisant
* Exemple: recherche d'un élément dans une structure
* Approches différentes suivant que la structure soit triée ou non
==> Mécanisme de spécialisation "statique"
* Spécialisation du modèle générique pour un jeu de paramètres
* Jeu de paramètres partiel ou complet
* On parle aussi d'"instanciation" partielle ou complète
* Associé au polymorphisme statique de l'instanciation
* "Meilleure" instanciation choisie en fonction du jeu de paramètres
Spécialisation d'une fonction générique
* Modèle générique d'une fonction de calcul de moyenne
template <int N> double moyenne(int * tab) {
double somme = 0;
for (int i = 0; i < N; ++i) somme += tab[i];
return (somme/N);
}
* Spécialisation du modèle pour N = 2 et N = 1
template <> double moyenne<2>(int * tab)
{ return (double(tab[0] + tab[1])/2); }
template <> double moyenne<1>(int * tab)
{ return double(tab[0]); }
* Attention à l'ordre
* Déclarer d'abord la version générique, puis les versions spécifiques
* En C++, spécialisation "partielle" d'une fonction (ou méthode) interdite
Spécialisation d'une classe générique
* Modèle générique d'un vecteur d'éléments
template <typename T> class Vecteur {
protected: T * elements;
protected: int taille;
...
public: T operator [] (int i)
{ return elements[i]; }
};
* Spécialisation du modèle pour T = bool
template <> class Vecteur<bool> {
protected: char * elements;
protected: int taille;
...
public: bool operator [] (int i)
{ return ((elements[i/8] >> (i%8)) & 1); }
};
Polymorphisme statique
* Mécanisme statique lors de l'instanciation d'un modèle
* Sélection de la version la plus spécialisée
* En fonction du jeu de paramètres
==> Génération du code le plus dédié possible
* Exemples d'instanciations
* moyenne<10>(tab); ==> version générique
* moyenne<2>(tab); ==> version spécialisée pour N = 2
* Vecteur<int> v; ==> version générique
* Vecteur<bool> v; ==> version spécialisée pour T = bool
Spécialisation partielle (1/2)
* Spécialisation partielle
= spécialisation avec un jeu de paramètres incomplet
* Retour sur l'exemple de calcul de moyenne
template <typename T,int N> class Moyenne {
public: static T calculer(T * tab) {
T somme = T();
for (int i = 0; i < N; ++i) somme += tab[i];
return (somme/T(N));
}
};
* Spécialisation pour N = 2 (T reste inconnu)
template <typename T> class Moyenne<T,2> {
public: static T calculer(T * tab)
{ return ((tab[0] + tab[1])/T(2)); }
};
Spécialisation partielle (2/2)
* Exemple de recherche d'un élément dans un conteneur
template <typename T,typename C>
class Recherche {
public:
static bool executer(const C & conteneur,
const T & element);
};
* Spécialisation pour C = vector<T> (T reste inconnu)
template <typename T>
class Recherche< T,vector<T> > {
public:
static bool executer(const vector<T> & conteneur,
const T & element);
};
Alternative à l'héritage (1/2)
* Polymorphisme dynamique ==> coût important à l'exécution
* Exemple: stratégie de recherche dans un conteneur
template <typename T> class Vecteur {
...
public: virtual bool rechercher(const T & x);
};
template <typename T> class VecteurTrie
: public Vecteur<T> {
...
public: bool rechercher(const T & x);
};
* Héritage des conteneurs vraiment nécessaire ?
* Aspect dynamique sans intérêt ==> spécialisation statique
Alternative à l'héritage (2/2)
* Version générique avec spécialisation statique
template <typename T,typename C> class Recherche {
public: static bool executer(const C & c,
const T & e);
};
template <typename T>
class Recherche< T,VecteurTrie<T> > {
public:
static bool executer(const VecteurTrie<T> & c,
const T & e);
};
* Astuce: utiliser la déduction automatique des paramètres
template <typename T,typename C>
int rechercher(const C & c,const T & e)
{ return Recherche<T,C>::executer(c,e); }