decltype
(C++)
El especificador de tipo decltype
produce el tipo de una expresión especificada. El especificador de tipo decltype
, junto con la palabra clave auto
, es útil sobre todo para los desarrolladores que crean bibliotecas de plantilla. Use auto
y decltype
para declarar una plantilla de función cuyo tipo de valor devuelto dependa de los tipos de sus argumentos de plantilla. O bien utilice auto
y decltype
para declarar una plantilla de función que contenga una llamada a otra función y devuelva el tipo de valor devuelto de la función contenida.
Sintaxis
decltype(
expression
)
Parámetros
expression
Expresión. Para más información, consulte Expresiones.
Valor devuelto
Tipo del parámetro expression
.
Comentarios
El especificador de tipo decltype
se admite en Visual Studio 2010 o versiones posteriores, y se puede usar con código nativo o administrado. decltype(auto)
(C++14) se admite en Visual Studio de 2015 y versiones posteriores.
El compilador usa las siguientes reglas para determinar el tipo del parámetro expression
.
Si el parámetro
expression
es un identificador o un acceso a miembros de clase,decltype(expression)
es el tipo de entidad designado porexpression
. Si no existe esa entidad o si el parámetroexpression
designa un conjunto de funciones sobrecargadas, el compilador produce un mensaje de error.Si el parámetro
expression
es una llamada a una función o una función de operador sobrecargada,decltype(expression)
es el tipo de valor devuelto de la función. Los paréntesis alrededor de un operador sobrecargado se omiten.Si el parámetro
expression
es un rvalue,decltype(expression)
es el tipo deexpression
. Si el parámetroexpression
es lvalue,decltype(expression)
es una referencia lvalue al tipo deexpression
.
En el ejemplo de código siguiente se muestran algunos usos del especificador de tipo decltype
. En primer lugar, suponga que ha incluido las siguientes instrucciones en el código.
int var;
const int&& fx();
struct A { double x; };
const A* a = new A();
A continuación, examine los tipos devueltos por las cuatro instrucciones decltype
de la tabla siguiente.
Instrucción | Tipo | Notas |
---|---|---|
decltype(fx()); |
const int&& |
Una referencia rvalue a const int . |
decltype(var); |
int |
El tipo de variable var . |
decltype(a->x); |
double |
El tipo del acceso a miembros. |
decltype((a->x)); |
const double& |
Los paréntesis internos hacen que la instrucción se evalúe como una expresión en lugar de como un acceso a miembros. Y como a se declara como un puntero const , el tipo es una referencia a const double . |
decltype
y auto
En C++14, puede usar decltype(auto)
sin tipo de valor devuelto final para declarar una plantilla de función, cuyo tipo de valor devuelto depende de los tipos de sus argumentos de plantilla.
En C++11, puede usar el especificador de tipo decltype
en un tipo de valor devuelto final junto con la palabra clave auto
para declarar una plantilla de función, cuyo tipo de valor devuelto depende de los tipos de sus argumentos de plantilla. Considere, por ejemplo el ejemplo de código siguiente en el que el tipo de valor devuelto de la plantilla de función depende de los tipos de los argumentos de plantilla. En el ejemplo de código, el marcador de posición UNKNOWN
indica que el tipo de valor devuelto no se puede especificar.
template<typename T, typename U>
UNKNOWN func(T&& t, U&& u){ return t + u; };
La introducción del especificador de tipo decltype
permite que el desarrollador obtenga el tipo de la expresión que devuelve la plantilla de función. Utilice la sintaxis de declaración de función alternativa que se muestra más adelante, la palabra clave auto
y el especificador de tipo decltype
para declarar un tipo de valor devuelto especificado en tiempo de compilación. El tipo de valor devuelto especificado en tiempo de compilación se determina cuando se compila la declaración, en lugar de cuando se codifica.
El prototipo siguiente muestra la sintaxis de una declaración de función alternativa. Los calificadores const
y volatile
y la throw
especificación de la excepción son opcionales. El marcador de posición function_body
representa una instrucción compuesta que especifica lo que hace la función. Como procedimiento recomendado de codificación, el marcador de posición expression
en la instrucción decltype
debe coincidir con la expresión especificada por la instrucción return
, si existe, en function_body
.
auto
function_name
(
parameters
opt )
const
opt volatile
opt ->
decltype(
expression
)
noexcept
opt {
function_body
};
En el ejemplo de código siguiente, el tipo de valor devuelto especificado en tiempo de compilación de la plantilla de función myFunc
viene determinado por los tipos de los argumentos de plantilla t
y u
. Como procedimiento de programación recomendado, en el ejemplo de código también se utilizan referencias rvalue y la plantilla de función forward
, que admiten el reenvío directo. Para más información, vea Declarador de referencia a un valor R: &&.
//C++11
template<typename T, typename U>
auto myFunc(T&& t, U&& u) -> decltype (forward<T>(t) + forward<U>(u))
{ return forward<T>(t) + forward<U>(u); };
//C++14
template<typename T, typename U>
decltype(auto) myFunc(T&& t, U&& u)
{ return forward<T>(t) + forward<U>(u); };
Funciones de reenvío y decltype
(C++11)
Las funciones de reenvío encapsulan llamadas a otras funciones. Considere una plantilla de función que reenvía sus argumentos, o los resultados de una expresión en la que participan estos argumentos, a otra función. Además, la función de reenvío devuelve el resultado de la llamada a otra función. En este escenario, el tipo de valor devuelto de la función de reenvío debe ser el mismo que el tipo de valor devuelto de la función encapsulada.
En este escenario, no puede escribir una expresión de tipo adecuada sin el especificador de tipo decltype
. El especificador de tipo decltype
permite usar funciones de reenvío genéricas porque no pierde la información necesaria sobre si una función devuelve o no un tipo de referencia. Para obtener un ejemplo de código de una función de reenvío, vea el ejemplo anterior de la plantilla de función myFunc
.
Ejemplos
En el ejemplo de código siguiente se declara el tipo de valor devuelto especificado en tiempo de compilación de la plantilla de función Plus()
. La función Plus
procesa sus operandos con la sobrecarga operator+
. Por lo tanto, la interpretación de operador más (+
) y el tipo de valor devuelto de la función Plus
depende de los tipos de los argumentos de la función.
// decltype_1.cpp
// compile with: cl /EHsc decltype_1.cpp
#include <iostream>
#include <string>
#include <utility>
#include <iomanip>
using namespace std;
template<typename T1, typename T2>
auto Plus(T1&& t1, T2&& t2) ->
decltype(forward<T1>(t1) + forward<T2>(t2))
{
return forward<T1>(t1) + forward<T2>(t2);
}
class X
{
friend X operator+(const X& x1, const X& x2)
{
return X(x1.m_data + x2.m_data);
}
public:
X(int data) : m_data(data) {}
int Dump() const { return m_data;}
private:
int m_data;
};
int main()
{
// Integer
int i = 4;
cout <<
"Plus(i, 9) = " <<
Plus(i, 9) << endl;
// Floating point
float dx = 4.0;
float dy = 9.5;
cout <<
setprecision(3) <<
"Plus(dx, dy) = " <<
Plus(dx, dy) << endl;
// String
string hello = "Hello, ";
string world = "world!";
cout << Plus(hello, world) << endl;
// Custom type
X x1(20);
X x2(22);
X x3 = Plus(x1, x2);
cout <<
"x3.Dump() = " <<
x3.Dump() << endl;
}
Plus(i, 9) = 13
Plus(dx, dy) = 13.5
Hello, world!
x3.Dump() = 42
Visual Studio 2017 y versiones posteriores: el compilador analiza los argumentos decltype
cuando se declaran las plantillas en lugar de crear instancias. Por lo tanto, si se detecta una especialización no dependiente en el argumento decltype
, no se aplazará hasta el momento de la creación de instancias, sino que se procesa inmediatamente y los errores resultantes se diagnostican en ese momento.
En el ejemplo siguiente se muestra este tipo de error del compilador que se genera en el punto de declaración:
#include <utility>
template <class T, class ReturnT, class... ArgsT> class IsCallable
{
public:
struct BadType {};
template <class U>
static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int); //C2064. Should be declval<U>
template <class U>
static BadType Test(...);
static constexpr bool value = std::is_convertible<decltype(Test<T>(0)), ReturnT>::value;
};
constexpr bool test1 = IsCallable<int(), int>::value;
static_assert(test1, "PASS1");
constexpr bool test2 = !IsCallable<int*, int>::value;
static_assert(test2, "PASS2");
Requisitos
Visual Studio 2010 o versiones posteriores.
decltype(auto)
requiere Visual Studio 2015 o una versión posterior.
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente las Cuestiones de GitHub como mecanismo de retroalimentación para el contenido y lo sustituiremos por un nuevo sistema de retroalimentación. Para más información, consulta:Enviar y ver comentarios de