bien, esta cuestión ha evolucionado un poco, y quiero tratar de empezar (más) con los objetivos básicos estoy tirando para:C++ Espacio de nombres dolores de cabeza
- Crear código de biblioteca que envolturas legado de lenguaje C las entidades en la adquisición de recursos de C++ son la inicialización y también proporcionan una garantía de excepción básica o mejor.
- Habilite a los clientes de este código para usarlo de forma C++ muy natural sin crear una sobrecarga al código existente para convertirlo en objetos de envoltura C++ (es decir, conversión automática a tipos heredados apropiados, constructores heredados tipos, etc.)
- Limite el impacto en el espacio de nombres del código de la biblioteca. Idealmente, la biblioteca tendría varios espacios de nombres que proporcionan funcionalidades relacionadas que limitan el volumen y el impacto del uso de declaraciones de tipo X de espacio de nombres, al igual que las bibliotecas de refuerzo (es decir, el uso de espacios de nombres de detalles para inyectar únicamente los símbolos que el usuario razonablemente desea utilizar y ocultar aquellos que son detalles de implementación; también limitar la extensión de posibles significados nuevos a símbolos existentes, para evitar conversiones implícitas sorprendentes dentro del código de usuario)
- Requerir que los clientes soliciten explícitamente aquellas partes de la biblioteca que realmente querer inyectar en su base de código. Esto va de la mano con la limitación del impacto de la inclusión de los encabezados de la biblioteca. El código del cliente debe tener un nivel razonable de control sobre qué partes de la biblioteca se usarán automáticamente para la resolución del nombre cuando compilan su código.
- Mi propio código de biblioteca no debería tener que estar plagado de construcciones de código frágil de refactor. Sería ideal si los encabezados de la biblioteca no tuvieran que declarar constantemente typedefs privados para tener acceso al resto de esa sección de la biblioteca. O en otras palabras: quiero que mi biblioteca pueda escribirse de manera tan intuitiva como mis clientes cuando utilizan dicha biblioteca. La resolución del nombre debe incluir el espacio de nombre en el que se define la biblioteca, además de cualquier otro que haya sido explícitamente "usado".
me encuentro con este escenario menudo, y estoy buscando una mejor manera ...
tengo una clase, C en espacio de nombres N. C tiene un miembro, gratuito. Libera algo que C maneja, y permite que C administre algo nuevo.
Existen varias funciones globales gratuitas. También hay algunas funciones auxiliares en el mismo espacio de nombres N como C, una de las cuales es una ayuda que libera la cosa administrada por C, denominada libre.
Así que tenemos algo así como:
namespace N {
void free(THING * thing);
class C
{
public:
... details omitted...
free()
{
free(m_thing); // <- how best to refer to N::free(THING&)
}
}
} // namespace N
que podría utilizar N :: libre (m_thing). Pero eso me parece desafortunado. ¿No hay forma de referirse a lo que está fuera del alcance de la clase, pero sin resolver el espacio de nombres absoluto (un relativo paso a paso del alcance)?
Me parece que tener que nombrar N :: free es desagradable, ya que no tendrías que hacerlo si se tratara de una función independiente. Tampoco lo necesitaría si el nombre del método de la clase fuera diferente (por ejemplo, disponer). Pero debido a que he usado el mismo nombre, no puedo acceder a él sin tener que especificar lo que equivale a una ruta absoluta, en lugar de una ruta relativa, si me permite la analogía.
Odio las rutas absolutas. Hacen que las cosas en movimiento en los espacios de nombres sean muy frágiles, por lo que la refactorización de códigos se vuelve mucho más fea. Además, las reglas de cómo nombrar las cosas en los cuerpos funcionales se vuelven más complejas con el conjunto de reglas actual (como yo las entiendo) - menos regular - induciendo un cisma entre lo que uno espera y lo que uno obtiene como programador.
¿Hay alguna manera mejor de acceder a las funciones autónomas en el mismo espacio de nombres que una clase sin tener que nombrar absolutamente absolutamente la función libre?
EDIT: Tal vez debería haber ido con un ejemplo menos abstracto:
namespace Toolbox {
namespace Windows {
// deallocates the given PIDL
void Free(ITEMIDLIST ** ppidl);
class Pidl
{
public:
// create empty
Pidl() : m_pidl(NULL) { }
// create a copy of a given PIDL
explicit Pidl(const ITEMIDLIST * pidl);
// create a PIDL from an IShellFolder
explicit Pidl(IShellFolder * folder);
...
// dispose of the underlying ITEMIDLIST* so we can be free to manage another...
void Free();
};
Así ITEMIDLIST * provienen de una variedad de lugares, y se destruyen con CoTaskMemFree(). Podría presentar a Pidl como un nombre global, así como a todas las funciones de ayuda en el encabezado "Windows Shell.h" que es parte de mi biblioteca de caja de herramientas.
Idealmente, segmentaría algunas de las herramientas en mi biblioteca por lo que se refieren a ellas, en este caso todo lo anterior se relaciona con la programación COM en Windows. He elegido Toolbox como el espacio de nombres base para mis cosas de bibliotecas, y estaba pensando que usaría Toolbox :: Windows para funciones, clases, etc. de Windows-y.
Pero las reglas de espacio de nombre y resolución de nombres C++ parecen para hacer esto muy difícil (de ahí esta pregunta). Resulta muy antinatural crear dicha segmentación de mi código, ya que falla la búsqueda koenig (ya que ITEMIDLIST no está en mi Toolbox :: espacio de nombres de Windows), ¡y no tengo la capacidad de moverlo allí! Tampoco debería I. El lenguaje debe ser lo suficientemente flexible, IMO, para permitir bibliotecas de extensión como mi biblioteca Toolbox para extender el código de otras personas sin tener que inyectar mis extensiones en su espacio de nombres (que, en el caso de Win32 y el vasto general La mayoría del código que existe hoy en día es GLOBAL NS, que es el objetivo principal de crear espacios de nombres en primer lugar: para evitar la saturación/contaminación/ambigüedad/sorpresas de programación globales de NS.
Por lo tanto, vuelvo a, ¿Hay una mejor manera de hacer esto: ampliar las bibliotecas existentes de código sin contaminar NS con mis extensiones pero aún así permitir una resolución de nombre intuitiva y útil como uno esperaría si mi El código estaba en su NS pero explícitamente introducido por el cliente de mi código (es decir, no quiero inyectar mi código de cualquier manera, pero solo a pedido explícito).
otro pensamiento: Quizá lo que satisfaría mi introduciendo criterios más arriba sería si tuviera el siguiente:
using namespace X {
code here...
}
donde podría colocar una construcción de este tipo en cualquier lugar, incluso en una cabecera, y yo no tendría que Preocuparse por arrastrar X al código de mi cliente, pero tendría la misma libertad para escribir mi código fuente como lo haría si estuviera en el espacio de nombres raíz.
Para jugar al abogado del diablo. N: free() significaría más para mí si comencé a leer tu código fuente en una ubicación aleatoria. Especialmente si vi X: libre usé un par de líneas después.Me facilita leer su código sin sus comentarios/documentación –
Para mí, eso parece contraproducente. En ese caso, uno debería simplemente poner todos los nombres en el espacio de nombres global, y asegurarse de que sean realmente explícitos: "free_a_thing()," create_a_thing() "etc., ya que eso parece lo que sucede cuando tiene que poner el De todos modos, la idea general de las funciones de sobrecarga es que el compilador resuelva el correcto en función del uso, una inferencia inteligente de lo que uno escribe. Tree t; Bear b; Can c; free (t) ; libre (b); libre (c); ¿Por qué es peor que free_a_tree (t), free_a_can (c), ... ???! – Mordachai
¿Por qué no 'borrar m_thing'? – GManNickG