una resueltos resolucion programacion orientada operador objetos miembros ejercicios ejemplos codigo clases clase ambito c++ class namespaces

c++ - resueltos - ¿Por qué no podemos declarar un espacio de nombres dentro de una clase?



operador de resolucion de ambito c++ (5)

Como usted preguntó qué partes de la ubicación del espacio de nombres del mandato estándar, primero lo abordamos:

C ++ 11 7.3-p4: Toda definición de espacio de nombres debe aparecer en el ámbito global o en un ámbito de espacio de nombres (3.3.6).

En cuanto a las definiciones de clase y la proposición de declarar un espacio de nombres dentro, te traigo a ...

C ++ 11 9.2-p2: una clase se considera un tipo de objeto completamente definido (3.9) (o tipo completo) al cierre} del especificador de clase. Dentro de la especificación de miembro de la clase, la clase se considera completa dentro de los cuerpos de funciones, los argumentos predeterminados, las especificaciones de excepciones y los inicializadores de llaves o iguales para los miembros de datos no estáticos (incluidos dichos elementos en las clases anidadas). De lo contrario, se considera como incompleto dentro de su propia especificación de miembro de clase.

Ergo, una definición de clase es finita una vez que se alcanza el cierre rizado. No se puede abrir de nuevo y extender (la derivación es algo diferente, pero NO amplía la clase que se acaba de definir ).

Pero acechar al principio de la definición estándar de un espacio de nombres es la capacidad de ampliarlo; expandirlo por falta de un término mejor:

C ++ 7.3-p1: Un espacio de nombres es una región declarativa opcionalmente nombrada. El nombre de un espacio de nombres se puede usar para acceder a entidades declaradas en ese espacio de nombres; es decir, los miembros del espacio de nombres. A diferencia de otras regiones declarativas, la definición de un espacio de nombre se puede dividir en varias partes de una o más unidades de traducción. (énfasis añadido).

Por lo tanto, un espacio de nombres dentro de una clase violaría la definición en 7.3-p4. Suponiendo que no estaba presente, sería posible declarar un espacio de nombre en cualquier lugar, incluso en una clase, pero dado que la definición de una clase se formaliza una vez que se cierra, se quedaría con la capacidad de hacer lo siguiente si mantuviera cumplimiento con 7.3-p1:

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

La utilidad de esta característica probablemente se debatió durante aproximadamente 3 segundos completos antes de que se estableciera 7.3-p4 para resolverlo.

Declarar una clase dentro de una clase es válido. (Clases anidadas)

Declarar un espacio de nombre dentro de una clase no es válido.

La pregunta es: ¿hay alguna buena razón (aparte de los problemas de gramática / sintaxis de c ++) para prohibir la declaración de un espacio de nombres dentro de una clase?

En cuanto a por qué querría hacer eso, aquí hay un ejemplo:

Tengamos un delcaration básico de un contenedor de árbol binario

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; };

Ahora me doy cuenta de que hay muchos iteradores en mi clase, por lo que me gustaría reagruparlos dentro del mismo espacio de nombres así:

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; };

Esto permitiría un uso simple:

void function() { binary_tree::iterator::left_depth it; ...stuff... }

Esto funciona si utilizo una clase en lugar de un espacio de nombres, pero luego me veo obligado a declarar una clase que nunca se creará una instancia, que es todo un espacio de nombres.

¿Por qué permitir clases anidadas y prohibir espacios de nombres anidados dentro de las clases? es histórico?

Las respuestas con razones semánticas que no solo citan parte del estándar (especialmente las partes de sintaxis) serán apreciadas :)


Este no es el punto de los espacios de nombres. Los espacios de nombres están destinados a existir más cerca del nivel superior del código, de modo que si dos compañías diferentes (o bases de código) pueden mezclar el código entre sí. En un nivel más micro, código con IMAP para acceso de correo electrónico y SMTP para envío de correo electrónico y (podría, me estoy simplificando mucho) tener clases en cualquier módulo llamado Email que son bastante diferentes, pero podría tener una aplicación, por ejemplo, un correo cliente, que quiere usar ambos de la misma clase, por ejemplo, tal vez reenvía correos de una cuenta a otra. Los espacios de nombres / nombres de paquetes / etc. lo permiten.

Lo que ha propuesto simplemente no es para qué sirven los espacios de nombres: dentro de un archivo puede asignar diferentes nombres a las cosas, ya que el autor tiene conocimiento global del archivo, aunque esto no es cierto cuando dos compañías desean compartir código o dos aplicaciones. que no sabían que estarían colisionando en cualquier punto.


No hay una ventaja real al agregar tal característica al lenguaje. Las características generalmente no se agregan a menos que haya demanda.

¿Qué comprarían los espacios de nombres dentro de las clases? ¿Preferirías decir binary_tree::iterator::left_depth lugar de simplemente binary_tree::left_depth ? Quizás si tuviera varios espacios de nombres dentro, los usaría para distinguir say binary_tree::depth_iterator::left y binary_tree::breadth_iterator::right .

En cualquier caso, puede lograr el resultado deseado utilizando clases internas como espacio de nombres de un programador deficiente, lo cual es una razón más por la cual no hay demanda de espacios de nombres verdaderos dentro de las clases.


Solo una pequeña idea que sentí que valía la pena mencionar. Un uso de espacios de nombres dentro de las clases sería un equivalente funcional a espacios de nombres con plantillas.

template<class...types> struct Namespace { namespace Implementation { ... } }; // somewhere else using namespace Namespace<types...>::Implementation; // use templated stuff.

Personalmente, disfrutaría de esta característica, pero parece que la demanda no es lo suficientemente alta como para implementarla.


Voy a estar en desacuerdo con los demás aquí. No diría que no hay una ventaja real. A veces me gustaría segregar el código sin implicaciones adicionales. Como ejemplo, estaba trabajando en un módulo ringbuffer multiproceso y quería dividir los miembros del estado, algunos de los cuales son atómicos y / o alineados a la memoria, en espacios de nombres para el productor y el consumidor.

Simplemente nombrando todo con prefijos de producer o consumer (que es mi actual implementación molesta), estoy agregando contaminación que hace que el código sea más difícil de leer. Por ejemplo, cuando todo lo que pertenece al productor comienza con producer , es más fácil para su cerebro leerlo para autocorregir accidentalmente producerProducerTimer (productor de temporizador) como producerConsumerTimer (productor sombra de un consumidor) o consumerProducerTimer (consumidor sombra de productor cronómetro) ) La depuración lleva mucho más tiempo de lo necesario porque el código ya no es skimmable.

Al crear una clase / estructura anidada:

  • Podría estar dando al siguiente desarrollador que mantiene este código la idea de que más de uno podría / debería ser instanciado, copiado y asignado el uno al otro dentro de un contexto, así que ahora en vez de solo preocuparme por nombrarlo, también tengo que = delete estas cosas.
  • Podría agregar huella de memoria al contexto con relleno de alineación estructural que de otro modo no sería necesario.
  • Hacer que todos los miembros estén estáticos no es una opción, ya que se puede instanciar más de un contexto que necesitará sus propias variables de estado productor / consumidor.
  • Las funciones de tal estructura ya no tienen acceso a otros datos o funciones de miembros, tales como constantes o funciones que son compartidas por ambas partes, sino que deben tomar estas cosas como argumentos.

Idealmente, me gustaría poder cambiar cosas como esta:

rbptr producerPosition; rbptr consumerPosition;

a esto:

namespace producer { rbptr position; } namespace consumer { rbptr position; }

Luego, las funciones que solo deben tocar a los miembros consumidores pueden usar el espacio de nombres del consumidor, las funciones que solo deben tocar, los miembros productores pueden usar el espacio de nombres del productor, y las funciones que necesitan tocar ambas tienen que calificarlas explícitamente. No habría forma de tocar accidentalmente una variable de consumidor en una función que solo utiliza el espacio de nombres de productor.

En este caso, el deseo es simplemente reducir las colisiones de nombres entre las copias de cosas de productores y consumidores, y reducir las colisiones de nombres es para lo que existen los espacios de nombres. Por esa razón, apoyo la propuesta para poder declarar espacios de nombres dentro de las clases.