En el lenguaje de programación C++ , es una palabra clave que se utiliza para consultar el tipo de una expresión . Introducida en C++11 , su principal uso previsto es en la programación genérica , donde suele ser difícil, o incluso imposible, expresar tipos que dependen de parámetros de plantilla .decltype
A medida que las técnicas de programación genérica se hicieron cada vez más populares a lo largo de la década de 1990, se reconoció la necesidad de un mecanismo de deducción de tipos. Muchos proveedores de compiladores implementaron sus propias versiones del operador, generalmente llamado typeof
, y se desarrollaron algunas implementaciones portátiles con funcionalidad limitada, basadas en características del lenguaje existentes. En 2002, Bjarne Stroustrup propuso que se agregara una versión estandarizada del operador al lenguaje C++ y sugirió el nombre "decltype", para reflejar que el operador produciría el "tipo declarado" de una expresión.
decltype
La semántica de 's fue diseñada para satisfacer las necesidades tanto de los programadores principiantes como de los escritores de bibliotecas genéricas. En general, el tipo deducido coincide con el tipo del objeto o función exactamente como se declara en el código fuente. Al igual que el operador sizeof
[1]decltype
, el operando de no se evalúa.
Con la introducción de plantillas en el lenguaje de programación C++ y la llegada de técnicas de programación genéricas iniciadas por la Biblioteca de Plantillas Estándar , se reconoció la necesidad de un mecanismo para obtener el tipo de una expresión , comúnmente denominada typeof
. En la programación genérica, a menudo es difícil o imposible expresar tipos que dependen de parámetros de plantilla, [2] [3] en particular el tipo de retorno de instancias de plantilla de función. [2]
Muchos proveedores proporcionan el typeof
operador como una extensión del compilador. [4] Ya en 1997, antes de que C++ estuviera completamente estandarizado, Brian Parker propuso una solución portátil basada en el sizeof
operador. [4] Su trabajo fue ampliado por Bill Gibbons, quien concluyó que la técnica tenía varias limitaciones y era generalmente menos poderosa que un typeof
mecanismo real. [4] En un artículo de octubre de 2000 del Dr. Dobb's Journal , Andrei Alexandrescu comentó que "tener un typeof haría que mucho código de plantilla fuera más fácil de escribir y entender". [5] También señaló que "typeof y sizeof comparten el mismo backend, porque sizeof tiene que calcular el tipo de todos modos". [5] Andrew Koenig y Barbara E. Moo también reconocieron la utilidad de una función incorporada typeof
, con la salvedad de que "usarla a menudo invita a errores de programación sutiles, y hay algunos problemas que no puede resolver". [6] Caracterizaron el uso de convenciones de tipos, como las typedefs proporcionadas por la Biblioteca de plantillas estándar , como una técnica más poderosa y general. [6] Sin embargo, Steve Dewhurst argumentó que tales convenciones son "costosas de diseñar y promulgar", y que sería "mucho más fácil... simplemente extraer el tipo de la expresión". [7] En un artículo de 2011 sobre C++0x , Koenig y Moo predijeron que "decltype se usará ampliamente para hacer que los programas cotidianos sean más fáciles de escribir". [8]
En 2002, Bjarne Stroustrup sugirió extender el lenguaje C++ con mecanismos para consultar el tipo de una expresión e inicializar objetos sin especificar el tipo. [2] Stroustrup observó que la semántica de eliminación de referencias ofrecida por el typeof
operador proporcionado por los compiladores GCC y EDG podría ser problemática. [2] Por el contrario, un operador que devolviera un tipo de referencia basado en la naturaleza lvalue de la expresión se consideró demasiado confuso. La propuesta inicial al comité de estándares de C++ describió una combinación de las dos variantes; el operador devolvería un tipo de referencia solo si el tipo declarado de la expresión incluía una referencia. Para enfatizar que el tipo deducido reflejaría el "tipo declarado" de la expresión, se propuso que el operador se llamara decltype
. [2]
Una de las principales motivaciones citadas para la decltype
propuesta fue la capacidad de escribir plantillas de funciones de reenvío perfectas . [9] A veces es deseable escribir una función de reenvío genérica que devuelva el mismo tipo que la función envuelta, independientemente del tipo con el que se instancia. Sin decltype
, generalmente no es posible lograr esto. [9] Un ejemplo, que también utiliza el tipo de retorno final : [9]
int & foo ( int & i ); flotador foo ( flotador & f ); plantilla < clase T > auto transparent_forwarder ( T & t ) − > decltype ( foo ( t )) { return foo ( t ); }
decltype
es esencial aquí porque preserva la información sobre si la función envuelta devuelve un tipo de referencia. [10]
De manera similar al sizeof
operador, el operando de decltype
no se evalúa, por lo que expresiones como decltype(i++)
no darán como resultado un incremento de la variable i. [11] De manera informal, el tipo devuelto por decltype(e)
se deduce de la siguiente manera: [2]
e
de esa variable o parámetro.e
es un lvalue , decltype(e)
es T&
, donde T
es el tipo de e; si e es un xvalue , el resultado es T&&
; de lo contrario, e es un prvalue y el resultado es T
.decltype(auto)
permite la deducción de tipo como , auto
pero conserva la categoría del valor del inicializador. Más específicamente, es equivalente a .decltype(initializer)
Estas semánticas fueron diseñadas para satisfacer las necesidades de los escritores de bibliotecas genéricas, mientras que al mismo tiempo son intuitivas para programadores novatos, porque el tipo de retorno de decltype
siempre coincide con el tipo del objeto o función exactamente como se declara en el código fuente. [2] Más formalmente, la Regla 1 se aplica a expresiones id sin paréntesis y expresiones de acceso a miembros de clase. [12] [13] Ejemplo: [12]
Nota para líneas agregadas para bar(). A continuación, el tipo deducido para "bar()" es int simple, no int constante, porque los prvalues de tipos que no son de clase siempre tienen tipos cv-no calificados, a pesar del tipo diferente declarado estáticamente.
const int && foo (); const int bar (); int i ; struct A { double x ; }; const A * a = new A (); decltype ( foo ()) x1 ; // el tipo es const int&& decltype ( bar ()) x2 ; // el tipo es int decltype ( i ) x3 ; // el tipo es int decltype ( a -> x ) x4 ; // el tipo es double decltype (( a -> x )) x5 ; // el tipo es const double&
La razón de la diferencia entre las dos últimas invocaciones de decltype
es que la expresión entre paréntesis (a->x)
no es ni una expresión id ni una expresión de acceso a miembros y, por lo tanto, no denota un objeto nombrado. [14] Debido a que la expresión es un valor l, su tipo deducido es "referencia al tipo de la expresión", o const double&
. [11] El hecho de que los paréntesis adicionales introduzcan un calificador de referencia al tipo puede ser una fuente de errores para los programadores que no comprenden completamente decltype
. [15]
En diciembre de 2008, Jaakko Järvi planteó al comité una inquietud sobre la imposibilidad de utilizar decltype
para formar un id calificado , [1] lo que es incompatible con la intención de que decltype(e)
se trate "como si fuera un nombre de definición de tipo ". [16] Al comentar el borrador formal del comité para C++0x , el organismo miembro japonés de ISO señaló que "un operador de ámbito (::) no se puede aplicar a decltype, pero debería serlo. Sería útil en el caso de obtener el tipo de miembro (tipo anidado) de una instancia de la siguiente manera: [17]
vector < int > v ; decltype ( v ) :: tipo_valor i = 0 ; // int i = 0;
David Vandevoorde abordó este y otros problemas similares relacionados con la redacción que inhibe el uso de decltype
en la declaración de una clase derivada y en una llamada al destructor y los votó para incluirlos en el documento de trabajo en marzo de 2010. [18] [19]
decltype
se incluye en el estándar del lenguaje C++ desde C++11 . [12] Es proporcionado por varios compiladores como una extensión. Los compiladores Visual C++ 2010 y posteriores de Microsoft proporcionan un especificador de tipo que imita de cerca la semántica descrita en la propuesta del comité de estándares. Se puede utilizar tanto con código administrado como nativo. [10] La documentación afirma que es "útil principalmente para desarrolladores que escriben bibliotecas de plantillas". [10] se agregó a la línea principal del compilador GCC C++ en la versión 4.3, [20] publicada el 5 de marzo de 2008. [21] también está presente en C++ Builder 2009 de Codegear , [22] el compilador Intel C++ , [23] y Clang . [24]decltype
decltype
decltype