c++ - smart - ¿Una directiva de uso dentro de una declaración de estructura/clase?
smart contracts ethereum (5)
A veces hago esto para lograr casi el mismo efecto:
namespace detail {
using namespace System;
using namespace System::Network;
using namespace System::Network::Win32::Sockets;
class Foo : public Bar
{
void FooBar(Handle handle, Error& error);
};
}
using detail::Foo;
Esta pregunta ya tiene una respuesta aquí:
Encuentro que mis archivos de encabezado de C ++ son bastante difíciles de leer (y realmente tediosos de escribir) con todos los tipos completamente calificados (que van hasta 4 espacios de nombres anidados). Esta es la pregunta (todas las respuestas ofrecen alternativas desordenadas para implementarla, pero esa no es la pregunta): ¿existe alguna razón en contra de la introducción de una directiva de uso en las estructuras y clases en el lenguaje C ++ (aunque es admisible tener un uso de la regla) declaración en funciones)?
p.ej
class Foo : public Bar
{
using namespace System;
using namespace System::Network;
using namespace System::Network::Win32::Sockets;
using Bar::MemberFunc; // no conflict with this
// e.g. of how messy my header files are without scoped using-directive
void FooBar(System::Network::Win32::Sockets::Handle handle, System::Network::Win32::Sockets::Error& error /*, more fully-qualified param declarations... */);
};
Dado que namespace
es una palabra clave, habría pensado que es lo suficientemente distinto como para no causar conflicto con el alcance usando una declaración como Bar::MemberFunc
.
EDITAR: Lea la pregunta cuidadosamente ---> Lo he negado. Recordatorio: no estamos discutiendo cómo mejorar la legibilidad del ejemplo aquí. Sugerir el uso de una directiva de uso en el ámbito (es decir, mediante la adición de palabras clave / construcciones, etc.) en el lenguaje C ++ NO es una respuesta (si pudiera encontrar una manera elegante de implementar esto utilizando los estándares existentes del lenguaje C ++, entonces sería de gran ayuda). Por supuesto ser una respuesta)!
Dado que el using
declaraciones en el alcance de la clase no se hereda, esto podría funcionar. El nombre solo sería válido dentro de esa declaración de clase o dentro de las declaraciones de clases anidadas. Pero creo que está sobrecargando el concepto de clase con una idea que debería ser más amplia.
En Java y Python, los archivos individuales se tratan de una manera especial. Puede tener declaraciones de import
que inyectan nombres de otros espacios de nombres en el archivo. Estos nombres (bueno, no exactamente con Python, pero es demasiado complicado de explicar aquí) solo serán visibles dentro de ese archivo.
Para mí, que defiende este tipo de habilidad no está ligado a una declaración de clase, sino que tiene un alcance propio. Esto permitiría usar nombres inyectados en varias declaraciones de clase si tuviera sentido, o incluso en definiciones de funciones.
Esta es una idea que prefiero porque permite estas cosas y, al mismo tiempo, le brinda los beneficios de un nivel de clase utilizando la declaración:
using {
// A ''using'' block is a sort of way to fence names in. The only names
// that escape the confines of a using block are names that are not
// aliases for other things, not even for things that don''t have names
// of their own. These are things like the declarations for new
// classes, enums, structs, global functions or global variables.
// New, non-alias names will be treated as if they were declared in
// the scope in which the ''using'' block appeared.
using namespace ::std;
using ::mynamespace::mytype_t;
namespace mn = ::mynamespace;
using ::mynamespace::myfunc;
class AClass {
public:
AClass(const string &st, mytype_t me) : st_(st), me_(me) {
myfunc(&me_);
}
private:
const string st_;
mn::mytype_t me_;
};
// The effects of all typedefs, using declarations, and namespace
// aliases that were introduced at the level of this block go away
// here. typedefs and using declarations inside of nested classes
// or namespace declarations do not go away.
} // end using.
// Legal because AClass is treated as having been declared in this
// scope.
AClass a("Fred", ::mynamespace::mytype_t(5));
// Not legal, alias mn no longer exists.
AClass b("Fred", mn::mytype_t);
// Not legal, the unqualified name myfunc no longer exists.
AClass c("Fred", myfunc(::mynamespace::mytype_t(5));
Esto es análogo a declarar un bloque para variables locales en una función. Pero en este caso, está declarando un ámbito muy limitado en el que cambiará las reglas de búsqueda de nombres.
El beneficio obvio de los espacios de nombres es que le permiten evitar conflictos de nombres. Sin embargo, al introducir un espacio de nombres completo en una declaración de clase, este beneficio se anula. Es totalmente posible que una función en el espacio de nombres del Sistema pueda entrar en conflicto con su propia función Bar :: MemberFunc. Incluso se nota esto en su código de muestra cuando agrega el comentario "no hay conflicto con esto".
Obviamente, no quieres introducir espacios de nombres completos en tu clase de esta manera:
using namespace System;
using namespace System::Network;
using namespace System::Network::Win32::Sockets;
Y no puede agregar un ámbito más estrecho utilizando declaraciones como esta en una declaración de clase. Poner esto directamente en una declaración de clase es ilegal.
using System::Network::Win32::Sockets::Handle;
using System::Network::Win32::Sockets::Error;
Lo que puedes hacer es usar el espacio de nombres sin nombre. Por lo tanto, su archivo de encabezado se vería algo así:
namespace {
using System::Network::Win32::Sockets::Handle;
using System::Network::Win32::Sockets::Error;
}
class Foo : public Bar
{
using Bar::MemberFunc;
// clean!
void FooBar(Handle handle, Error& error /*, more declarations*/);
};
Esto tiene tres ventajas distintas.
- No se introducen los contenidos de espacios de nombres completos. Esto ayuda a evitar más fácilmente conflictos de nombres.
- Tiene una lista, antes de su declaración de clase, de lo que depende su clase para funcionar correctamente.
- Sus declaraciones de función están limpias.
Por favor corrígeme si estoy equivocado; Sólo probé brevemente esto. Rápidamente escribí un ejemplo, y lo compilé.
Puede utilizar un typedef dentro de la declaración de clase para lograr el mismo
class Foo : public Bar
{
typedef System::Network::Win32::Sockets::Handle Handle;
typedef System::Network::Win32::Sockets::Error Error;
void FooBar(Handle handle, Error& error);
};
Tal vez alias espacio de nombres?
namespace MyScope = System::Network::Win32::Sockets;