¿Cuál es la lógica detrás de la palabra clave “usar” en C ++?
Se usa en diferentes situaciones y estoy tratando de encontrar si todas tienen algo en común y hay una razón por la cual la palabra clave “usar” se usa como tal.
using namespace std; // to import namespace in the current namespace using T = int; // type alias using SuperClass::X; // using super class methods in derived class
En C ++ 11, la palabra clave using
cuando se utiliza para type alias
es idéntica a typedef
.
7.1.3.2
Un typedef-name también puede ser introducido por una statement de alias. El identificador que sigue a la palabra clave using se convierte en un typedef-name y el atributo-especificador-seq opcional que sigue al identificador pertenece a ese typedef-name. Tiene la misma semántica que si fuera introducida por el especificador typedef. En particular, no define un nuevo tipo y no aparecerá en el ID de tipo.
Bjarne Stroustrup proporciona un ejemplo práctico:
typedef void (*PFD)(double); // C style using PF = void (*)(double); // using plus C-style type using P = [](double)->void; // using plus suffix return type, syntax error using P = auto(double)->void // Fixed thanks to DyP
Pre-C ++ 11, la palabra clave using
puede llevar las funciones miembro al scope. En C ++ 11, ahora puede hacer esto para los constructores (otro ejemplo de Bjarne Stroustrup):
class Derived : public Base { public: using Base::f; // lift Base's f into Derived's scope -- works in C++98 void f(char); // provide a new f void f(int); // prefer this f to Base::f(int) using Base::Base; // lift Base constructors Derived's scope -- C++11 only Derived(char); // provide a new constructor Derived(int); // prefer this constructor to Base::Base(int) // ... };
Ben Voight proporciona una buena razón detrás de la lógica de no presentar una nueva palabra clave o una nueva syntax. La norma quiere evitar romper el código antiguo tanto como sea posible. Esta es la razón por la que en los documentos de propuesta verá secciones como Impact on the Standard
, Design decisions
y cómo podrían afectar el código anterior. Hay situaciones en las que una propuesta parece una buena idea, pero puede no tener tracción porque sería demasiado difícil de implementar, demasiado confusa o contradiría el código anterior.
Aquí hay un documento antiguo de 2003 n1449 . El razonamiento parece estar relacionado con las plantillas. Advertencia: puede haber errores tipográficos debido a la copia de PDF.
Primero consideremos un ejemplo de juguete:
template
class MyAlloc {/*...*/}; template class MyVector {/*...*/}; template struct Vec { typedef MyVector > type; }; Vec ::type p; // sample usage El problema fundamental con este modismo, y el hecho motivador principal para esta propuesta, es que el modismo hace que los parámetros de la plantilla aparezcan en un contexto no deducible. Es decir, no será posible llamar a la función foo a continuación sin especificar explícitamente los argumentos de la plantilla.
template
void foo (Vec ::type&); Entonces, la syntax es algo fea. Preferimos evitar el
::type
nested::type
Preferiríamos algo como lo siguiente:template
using Vec = MyVector >; //defined in section 2 below Vec p; // sample usage Tenga en cuenta que evitamos específicamente el término “plantilla typedef” e intr oduzca la nueva syntax que implica el par “using” y “=” para ayudar a evitar confusiones: no estamos definiendo ningún tipo aquí, estamos introduciendo un sinónimo (es decir, alias) para una abstracción de un id de tipo (es decir, expresión de tipo) que involucra parámetros de plantilla. Si los parámetros de la plantilla se utilizan en contextos deducibles en la expresión de tipo, cada vez que se use el alias de la plantilla para formar una plantilla-id, se pueden deducir los valores de los parámetros de la plantilla correspondientes, más sobre esto seguirá. En cualquier caso, ahora es posible escribir funciones genéricas que operan en
Vec
en contexto deducible, y la syntax también se mejora. Por ejemplo, podríamos reescribir foo como:template
void foo (Vec &); Subrayamos aquí que una de las principales razones para proponer alias de plantilla fue para que la deducción de argumento y la invocación a
foo(p)
tengan éxito.
El documento de seguimiento n1489 explica por qué using
lugar de usar typedef
:
Se ha sugerido (re) usar la palabra clave typedef, como se hizo en el artículo [4], para introducir alias de plantilla:
template
typedef std::vector > Vec; Esa notación tiene la ventaja de utilizar una palabra clave ya conocida para introducir un alias de tipo. Sin embargo, también muestra varias desventajas entre las cuales la confusión de usar una palabra clave conocida para introducir un alias para un nombre de tipo en un contexto donde el alias no designa un tipo, sino una plantilla;
Vec
no es un alias para un tipo, y no debe tomarse para un typedef-name. El nombreVec
es un nombre para la familiastd::vector< [bullet] , MyAllocator< [bullet] > >
– donde la viñeta es un marcador de posición para un nombre de tipo. En consecuencia, no proponemos la syntax “typedef”. Por otro lado, la oracióntemplate
using Vec = std::vector >; se puede leer / interpretar como: de ahora en
std::vector
> Vec
como sinónimo destd::vector
. Con esa lectura, la nueva syntax para aliasing parece razonablemente lógica.>
Creo que la distinción importante se hace aquí, alias es en lugar de tipo s. Otra cita del mismo documento:
Una statement de alias es una statement y no una definición. Una statement de alias introduce un nombre en una región declarativa como un alias para el tipo designado por el lado derecho de la statement. El núcleo de esta propuesta se refiere a los alias de nombre de tipo, pero la notación, obviamente, se puede generalizar para proporcionar deletreos alternativos de alias de espacio de nombres o nombrar un conjunto de funciones sobrecargadas (ver ✁ 2.3 para mayor discusión). [ Mi nota: esa sección discute cómo se ve esa syntax y por qué no es parte de la propuesta. ] Cabe señalar que la statement de alias de producción de gramática es aceptable en cualquier lugar en que sea aceptable una statement typedef o una definición de alias de espacio de nombres.
Resumen, para la función de using
:
namespace PO = boost::program_options
y using PO = ...
equivalente) A typedef declaration can be viewed as a special case of non-template alias-declaration
. Es un cambio estético, y se considera idéntico en este caso. namespace std
en el scope global), funciones de miembros, heredar constructores No puede usarse para:
int i; using r = i; // compile-error
En lugar de hacer:
using r = decltype(i);
Nombrando un conjunto de sobrecargas.
// bring cos into scope using std::cos; // invalid syntax using std::cos(double); // not allowed, instead use Bjarne Stroustrup function pointer alias example using test = std::cos(double);