web-dev-qa-db-fra.com

Pourquoi ne pouvons-nous pas déclarer un espace de noms dans une classe?

La déclaration d'une classe dans une classe est valide. (Classes imbriquées)

Déclarer un espace de noms dans une classe n'est pas valide.

La question qui se pose est la suivante: existe-t-il une bonne raison (autre que les problèmes de grammaire/syntaxe c ++) d'interdire la déclaration d'un espace de noms au sein d'une classe?


Pourquoi voudrais-je faire cela? Voici un exemple:

Ayons une description basique d'un conteneur d'arborescence binaire

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  typedef left_depth_iterator_impl     left_depth_iterator;
  typedef right_depth_iterator_impl    right_depth_iterator;
  typedef left_breadth_iterator_impl   left_breadth_iterator;
  typedef right_breadth_iterator_impl  right_breadth_iterator;

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

Maintenant, je remarque qu'il y a beaucoup d'itérateurs dans ma classe, donc j'aimerais les regrouper dans le même espace de noms, comme ceci:

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  namespace iterator
  {
    typedef left_depth_iterator_impl     left_depth;
    typedef right_depth_iterator_impl    right_depth;
    typedef left_breadth_iterator_impl   left_breadth;
    typedef right_breadth_iterator_impl  right_breadth;
  }

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

Cela permettrait une utilisation simple:

void  function()
{
  binary_tree::iterator::left_depth   it;

  ...stuff...
}

Cela fonctionne si j'utilise une classe au lieu d'un espace de noms, mais je suis alors obligé de déclarer une classe qui ne sera jamais instanciée, ce qui est tout à fait un espace de noms.

Pourquoi autoriser les classes imbriquées et interdire les espaces de noms imbriqués dans les classes? est-ce un fardeau hérité?


Les réponses avec des raisons sémantiques qui ne citent pas seulement une partie de la norme (en particulier des parties de syntaxe) seront appréciées :)

40
Drax

Il n’ya aucun avantage réel à ajouter une telle fonctionnalité à la langue. Généralement, les fonctionnalités ne sont pas ajoutées à moins d'une demande.

Qu'est-ce que les espaces de noms dans les classes vous achèteraient? Préféreriez-vous vraiment dire binary_tree::iterator::left_depth au lieu de simplement binary_tree::left_depth? Peut-être que si vous avez plusieurs espaces de noms à l'intérieur, vous les utilisez pour distinguer, par exemple, binary_tree::depth_iterator::left et binary_tree::breadth_iterator::right.

Dans tous les cas, vous pouvez obtenir le résultat souhaité en utilisant des classes internes comme espace de noms pour les programmeurs médiocres, ce qui est une raison supplémentaire pour laquelle il n'y a pas de demande de vrais espaces de noms dans les classes.

8
Adrian McCarthy

Puisque vous avez demandé quelles parties de l'emplacement de l'espace de nommage du mandat standard, nous en avons parlé en premier:

C++ 11 7.3-p4: Chaque définition d'espace de nom doit apparaître dans la portée globale ou dans une portée d'espace de nom (3.3.6).

En ce qui concerne les définitions de classe et la proposition de déclarer un espace de noms à l'intérieur, je vous amène à ...

C++ 11 9.2-p2: Une classe est considérée comme un type d'objet complètement défini (3.9) (ou type complet) à la fermeture} du spécificateur de classe. Dans la spécification de membre de classe, la classe est considérée comme complète dans les corps de fonction, les arguments par défaut, les spécifications d'exception et les initialiseurs d'accolade ou d'égalité pour les membres de données non statiques (y compris de telles choses dans des classes imbriquées). Sinon, il est considéré comme incomplet dans sa propre spécification de membre de classe.

Ainsi, une définition de classe est finie une fois que le bouclé de fermeture est atteint. Il ne peut pas être ouvert et étendu (la dérivation est quelque chose de différent, mais elle ne s'étend PAS la classe que nous venons de définir).

Mais au tout début de la définition standard d'un espace de nommage se trouve la possibilité de l'étendre. l'élargir faute d'un meilleur terme:

C++ 7.3-p1: Un espace de noms est une région déclarative nommée en option. Le nom d'un espace de noms peut être utilisé pour accéder aux entités déclarées dans cet espace de noms. c'est-à-dire les membres de l'espace de noms. Contrairement aux autres régions déclaratives, la définition d'un espace de noms peut être divisée en plusieurs parties d'une ou plusieurs unités de traduction. (italiques ajoutés).

Par conséquent, un espace de noms au sein d'une classe enfreindrait la définition de 7.3-p4. En supposant que ce ne soit pas présent, il serait possible de déclarer un espace de noms n'importe où, y compris dans une classe, mais étant donné que la définition d'une classe est formalisée une fois qu'elle est fermée, procédez comme suit si vous maintenez la conformité à 7.3-p1:

class Foo
{
   namespace bar
   {
       ..stuff..
   }

   .. more stuff ..

   namespace bar
   {
       ..still more stuff..
   }
};

L'utilité de cette fonctionnalité a probablement été débattue pendant environ 3 secondes complètes avant que la version 7.3-p4 ne soit établie pour la régler.

42
WhozCraig

Ce n'est tout simplement pas le but des espaces de noms. Les espaces de noms sont censés exister au plus haut niveau du code, de sorte que deux sociétés (ou bases de code) différentes puissent mélanger du code l'une avec l'autre. À un niveau plus micro, je code à la fois avec IMAP pour l’accès au courrier électronique et SMTP pour l’envoi de courrier électronique et (je pourrais grandement simplifier) ​​des classes dans les deux modules appelés Email qui sont très différentes, mais je pourrais avoir une application, disons un courrier électronique. client, qui veut utiliser les deux de la même classe, par exemple peut-être qu'il transfère des mails d'un compte à un autre. Les espaces de noms/noms de paquets/etc. le permettent.

Ce que vous avez proposé ne correspond tout simplement pas aux espaces de noms. Dans un fichier, vous pouvez attribuer des noms différents, car l'auteur possède une connaissance globale du fichier, bien que ce ne soit pas le cas lorsque deux entreprises souhaitent partager du code ou deux applications. cela ne savait pas qu'ils seraient en collision à tout moment.

4
djechlin

Juste une petite pensée qui, à mon avis, méritait d'être mentionnée. Une utilisation des espaces de noms à l'intérieur des classes serait un équivalent fonctionnel des espaces de noms basés sur des modèles.

template<class...types>
struct Namespace {
    namespace Implementation {
        ...
    }
};

// somewhere else

using namespace Namespace<types...>::Implementation;

// use templated stuff.

Personnellement, j'apprécierais cette fonctionnalité, mais il semble que la demande ne soit pas assez forte pour être mise en œuvre.

0
Anthony Monterrosa