Blog 3 min de lecture

5 raisons courantes d’utiliser les espaces de noms dans les projets C++

Share this article
5 raisons courantes d’utiliser les espaces de noms dans les projets C++

Les espaces de noms ont été introduits dans la norme C++ en 1995, et ils sont généralement définis comme ceci :

Un espace de noms définit une nouvelle portée et offre un moyen d'éviter les collisions de noms.

En C++, les espaces de noms servent le plus souvent à éviter les collisions de noms. Bien qu'ils soient largement utilisés dans le code C++ récent, la plupart du code plus ancien n'utilise pas cette fonctionnalité. 

Après avoir exploré le code source de nombreux projets C++, voici quelques raisons courantes d'utiliser les espaces de noms dans ces projets.

1. Éviter les collisions de noms.

Comme mentionné ci-dessus, c'est la raison la plus courante. Dans ce cas, leur utilisation profite surtout au compilateur ; elle ne rend pas nécessairement le code plus lisible ou plus maintenable pour les développeurs.

2. Modulariser l'application

Les bibliothèques C++ modernes utilisent massivement les espaces de noms pour modulariser leur base de code, selon l'approche « namespace-by-feature ». Cette approche utilise les espaces de noms pour refléter l'ensemble des fonctionnalités. Elle place tous les éléments liés à une seule fonctionnalité (et uniquement celle-ci) dans un même espace de noms. Il en résulte des espaces de noms à forte cohésion et à forte modularité, avec un couplage minimal entre eux. Les éléments qui collaborent étroitement sont placés côte à côte.

Boost est le meilleur exemple de regroupement par fonctionnalité ; il contient des milliers d'espaces de noms, chacun servant à regrouper une fonctionnalité spécifique.

3. L'espace de noms anonyme.

Un espace de noms sans nom offre une alternative aux variables globales statiques. L'espace de noms anonyme n'est accessible que dans le fichier où il est déclaré.

4. Un palliatif au problème des énumérations.

Les énumérations « traditionnelles » du C++ exportent leurs énumérateurs dans la portée environnante, ce qui peut entraîner des collisions de noms si deux énumérations différentes dans la même portée définissent des énumérateurs portant le même nom.

Dans un grand projet, rien ne garantit que deux énumérations distinctes n'utiliseront pas le même nom d'énumérateur. Ce problème a été résolu dans C++11 à l'aide de enum class, qui limite implicitement la portée des valeurs de l'énumération au nom de celle-ci.

Avant C++11, un palliatif courant consistait à déclarer une énumération à l'intérieur d'un espace de noms. Par exemple, au lieu de déclarer une énumération comme ceci :

enum status{
  status_ok,
  status_error
};

on pouvait la déclarer à l'intérieur d'un espace de noms :

namespace status{
       enum status{
         ok,
          error
  };
}

De nombreux projets C++ utilisent cette astuce ; par exemple, le code source d'Unreal Engine utilise largement cette technique.

5. Masquer les détails par convention

Pour les bibliothèques de templates dont le code est implémenté dans des fichiers d'en-tête, il est utile d'indiquer aux utilisateurs de la bibliothèque que certains types sont des détails d'implémentation et ne doivent pas être utilisés directement. En C#, le mot-clé « internal » remplit cette fonction, mais en C++, il n'existe pas d'équivalent pour masquer les types publics aux utilisateurs de la bibliothèque.

Un idiome courant en C++ moderne, lancé par les développeurs des bibliothèques Boost, consiste à séparer dans un sous-espace de noms distinct — par convention nommé detail — les symboles qui font partie de l'implémentation de votre module (c'est-à-dire ceux qui ne font pas partie de l'API publique) mais qui doivent néanmoins être accessibles publiquement.

Par exemple, la documentation de Boost.Math indique que :

Les fonctions non destinées à être utilisées par les applications se trouvent dans boost::math::detail.
Share this article