Guru Of the Week n° 46 : typedef

Difficulté : 3 / 10
Pourquoi utiliser typedef ? à côté des nombreuses raisons traditionnelles, nous envisagerons des techniques de typedef qui rendent l'utilisation de la librairie standard C++ plus sûre et plus facile.

Retrouver l'ensemble des Guru of the Week sur la page d'index.

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (0)

Article lu   fois.

Les deux auteurs

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Problème

I-A. Question JG

1. Que fait typedef ?

I-B. Questions Guru

2. Pourquoi utiliser typedef ? Nommez autant de situations/raisons que vous pouvez.

3. Pourquoi typedef est-il une si bonne idée dans les codes qui utilisent des containers standards (STL) ?

II. Solution

II-A. 1. Que fait typedef ?

écrire un "typedef" vous permet d'assigner un autre nom équivalent pour un type. par exemple :

 
Sélectionnez
    typedef vector< vector<int> > IntArray;

vous permet d'écrire la formulation simple "IntArray" en lieu et place de la formulation verbeuse "vector< vector<int> >".

II-B. 2. Pourquoi utiliser typedef ? Nommez autant de situations/raisons que vous pouvez.

Plusieurs possibilités :

II-B-1. Frappe

Des noms plus courts sont plus faciles à entrer au clavier.

II-B-2. Lisibilité

Typedefs peut rendre les codes plus faciles à lire, en particulier les noms de types de templates particulièrement longs. Pour un exemple simple, considérez ce qui suit issu d'un message d'une messagerie publique demandant ce que ce code signifie :

 
Sélectionnez
    int ( *t(int) )( int* );

Si vous avez l'habitude de lire des déclarations C comme si c'était un roman victorien (une prose dense et verbeuse qui parfois semble donner pédaler dans la semoule), vous connaissez la réponse et c'est bien. Si ce n'est pas le cas, typedefs vous aidera, même avec un nom typedef aussi insignifiant que "Func" :

 
Sélectionnez
    typedef int (*Func)( int* );
    Func t( int );

à présent, il est clair que c'est une déclaration de fonction pour une fonction appelée "t" qui saisit un entier et retourne un pointeur sur une fonction qui saisit un entier* et retourne un entier (dites-le trois fois très vite). Dans ce cas, le typedef est plus facile à lire que le français.

Typedefs peut aussi ajouter une signification sémantique. Par exemple, "PhoneBook" est beaucoup plus facile à comprendre que "map< string, string>" (qui pourrait signifier n'importe quoi !)

II-B-3. Portabilité

Si vous utilisez des noms traités par typedefs pour des noms spécifiques d'une plateforme ou non portables autrement, il vous sera plus facile de passer à de nouvelles plateformes. Après tout, il est plus facile d'écrire ceci :

 
Sélectionnez
    #if defined USING_COMPILER_A
      typedef __int32 Int32;
      typedef __int64 Int64;
    #elif defined USING_COMPILER_B
      typedef int       Int32;
      typedef long long Int64;
    #endif

que de chercher et remplacer un des noms spécifiques du système dans tout votre code. Les noms typedef vous protègent des dépendances envers des plateformes uniques.

II-C. 3. Pourquoi typedef est-il une si bonne idée dans les codes qui utilisent des containers standards (STL) ?

II-C-1. Flexibilité

Changer un nom typedef à un endroit est plus facile que changer toutes ses utilisations dans tout le code. Par exemple, considérez le code suivant :

 
Sélectionnez
    void f( vector<Customer>& vc ) {
      vector<Customer>::iterator i = vc.begin();
      ...
    }

Que se passera-t-il si quelques mois plus tard, vous découvrez que le vecteur n'est pas le bon container ? Si vous conservez un grand nombre d'objets Clients, le fait que le stockage des vecteurs soit contigu[1] peut être un désavantage et peut-être préfèrerez-vous un deque à la place. Ou bien, si vous insérez/enlevez fréquemment des éléments au milieu, vous préfèrerez une liste.

Dans le code ci-dessus, vous auriez à opérer ce changement partout où apparaît "vector<Customer>". Ce serait tellement plus facile si vous aviez seulement écrit :

 
Sélectionnez
    typedef vector<Customer> Customers;

    ...

    void f( Customers& vc ) {
      Customers::iterator i = vc.begin();
      ...
    }

Vous n'auriez à changer que le typedef en list<Customer> ou deque<Customer> ! Ce n'est pas toujours aussi facile - par exemple, il se pourrait que votre code repose sur un Customers::iterator itérateur à accès libre, ce que n'est pas un list<Customer::iterator - mais cela vous protège d'un grand nombre de changements qui seraient ennuyeux autrement.

II-C-2. Traitabilité

Les traits sont une façon efficace d'associer les informations à un type, et si vous voulez personnaliser des containers ou des algorithmes standards, il vous faudra souvent fournir des traits. Considérez l'exemple de chaîne sensible à la casse dans GotW n°29, où nous avions défini notre propre remplacement char_traits.

La plupart des utilisations de typedef entrent dans l'une de ces catégories.

III. Notes

1. Oui, je suis conscient du débat, et oui, il devrait être contigu (note : cf. Librairie Standard, 1e Partie : Vectors et Deques).

IV. Remerciements

Cet article est une traduction en français par l'équipe de la rubrique C++ de l'article de Herb Sutter publié sur Guru of the Week. Vous pouvez retrouver cet article dans sa version originale sur le site de Guru of the Week : Typedefs.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2009 Herb Sutter. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.