typedef vs using en C++ : que choisir et quelles sont leurs réelles différences ?

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

typedef vs using en C++ : guide complet pour le développeur moderne

\n\n

Avez-vous déjà réfléchi à pourquoi, dans le code C++, certains développeurs écrivent typedef et d'autres using ? Il semble que les deux fassent la même chose — créer des alias pour les types. Mais est-ce vraiment le cas ? Si vous voulez écrire un code propre et moderne sans tomber dans les pièges des constructions obsolètes, cet article est pour vous.

\n\n

Nous allons voir en quoi typedef et using diffèrent en C++, quand utiliser quoi, et pourquoi la communauté C++ se tourne de plus en plus vers using. Prêt ? C'est parti !

\n\n

Bref historique : de C à C++11

\n\n

typedef vient du langage C. C'est la méthode classique pour déclarer un alias de type. Voici à quoi cela ressemble :

\n\n
typedef unsigned long long ULL;\ntypedef std::vector<std::string> StringVector;\ntypedef void (*FunctionPtr)(int, double);
\n\n

La syntaxe, pour le moins, n'est pas la plus intuitive. Cela est particulièrement visible avec les pointeurs de fonctions — même les développeurs expérimentés butent parfois en lisant de telles déclarations.

\n\n

En C++11, une nouvelle construction est apparue — using (ou déclaration d'alias). Elle est beaucoup plus naturelle :

\n\n
using ULL = unsigned long long;\nusing StringVector = std::vector<std::string>;\nusing FunctionPtr = void (*)(int, double);
\n\n

On voit immédiatement : à gauche le nom, à droite le type. Cela se lit comme une « affectation », ce qui est intuitif pour tout programmeur.

\n\n

La principale différence : le travail avec les templates

\n\n

C'est ici que se trouve la différence la plus importante entre typedef et using. using prend en charge les alias templates (alias template), contrairement à typedef.

\n\n

Regardons un exemple. Supposons que vous vouliez créer un alias pour std::unique_ptr avec un suppresseur personnalisé :

\n\n
// Avec using — simple et élégant\ntemplate <typename T>\nusing CustomPtr = std::unique_ptr<T, void(*)(T*)>;\n\n// Avec typedef — impossible directement !\n// Il faut construire des wrappers via des structures\ntemplate <typename T>\nstruct CustomPtrOld {\n    typedef std::unique_ptr<T, void(*)(T*)> type;\n};\n\n// Utilisation :\nCustomPtr<int> ptr1;                    // using — simple\nCustomPtrOld<int>::type ptr2;           // typedef — fastidieux
\n\n

Vous sentez la différence ? using rend le code plus propre et plus court. Et si vous devez utiliser un tel alias à l'intérieur d'une classe ou d'une fonction template, la différence devient encore plus marquée :

\n\n
template <typename T>\nclass Container {\npublic:\n    // Avec using\n    using Ptr = CustomPtr<T>;\n    \n    // Avec typedef — besoin de typename et ::type\n    typedef typename CustomPtrOld<T>::type OldPtr;\n    \nprivate:\n    Ptr data;\n    OldPtr oldData;\n};
\n\n

Lisibilité du code : un vainqueur évident

\n\n

Même pour les types simples, using gagne en lisibilité. Comparez :

\n\n
// Avec typedef — on ne sait pas où est le nom, où est le type\ntypedef std::map<std::string, std::vector<int>> StringToIntVectorMap;\n\n// Avec using — tout est évident\nusing StringToIntVectorMap = std::map<std::string, std::vector<int>>;
\n\n

Lorsque vous lisez du code, votre œil scanne naturellement la construction de gauche à droite. using suit ce principe : d'abord le nom, puis le type. typedef vous oblige à lire d'abord le type, puis le nom — cela va à l'encontre de l'intuition.

\n\n

Pointeurs de fonctions : le cauchemar de typedef

\n\n

Les pointeurs de fonctions sont sans doute la partie la moins appréciée du C++ pour de nombreux développeurs. Et typedef les rend encore plus confus :

\n\n
// typedef — lisez comme une incantation\ntypedef void (*Callback)(int, const std::string&);\n\n// using — comme une variable ordinaire\nusing Callback = void (*)(int, const std                

Blogs

Book Recommendations