Namespaces
Variants

decltype specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const / volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Inspecciona el tipo declarado de una entidad o el tipo y categoría de valor de una expresión.

Contenidos

Sintaxis

decltype ( entidad ) (1)
decltype ( expresión ) (2)

Explicación

1) Si el argumento es una id-expression sin paréntesis o una expresión de class member access sin paréntesis, entonces decltype produce el tipo de la entidad nombrada por esta expresión. Si no existe tal entidad, o si el argumento nombra un conjunto de funciones sobrecargadas, el programa está mal formado.

Si el argumento es una id-expression sin paréntesis que nombra un structured binding , entonces decltype produce el tipo referenciado (descrito en la especificación de la declaración de enlace estructurado).

(desde C++17)

Si el argumento es una id-expression sin paréntesis que nombra un constant template parameter , entonces decltype produce el tipo del parámetro de plantilla (después de realizar cualquier deducción de tipo necesaria si el parámetro de plantilla se declara con un tipo de marcador de posición). El tipo es no-const incluso si la entidad es un objeto de parámetro de plantilla (que es un objeto const).

(desde C++20)
2) Si el argumento es cualquier otra expresión de tipo T , y
a) si la categoría de valor de expresión es xvalue , entonces decltype produce T && ;
b) si la categoría de valor de expression es lvalue , entonces decltype produce T & ;
c) si la categoría de valor de expresión es prvalue , entonces decltype produce T .

Si expresión es una llamada a función que retorna un prvalue de tipo clase o es una expresión coma cuyo operando derecho es dicha llamada a función, no se introduce un objeto temporal para ese prvalue.

(hasta C++17)

Si expresión es un prvalue distinto de una invocación inmediata (posiblemente entre paréntesis) (desde C++20) , no se materializa un objeto temporal a partir de ese prvalue: dicho prvalue no tiene objeto resultado.

(desde C++17)
Dado que no se crea un objeto temporal, el tipo no necesita ser completo o tener un destructor disponible, y puede ser abstracto . Esta regla no aplica a subexpresiones: en decltype ( f ( g ( ) ) ) , g ( ) debe tener un tipo completo, pero f ( ) no necesita.

Tenga en cuenta que si el nombre de un objeto está entre paréntesis, se trata como una expresión lvalue ordinaria, por lo que decltype ( x ) y decltype ( ( x ) ) suelen ser tipos diferentes.

decltype es útil al declarar tipos que son difíciles o imposibles de declarar usando notación estándar, como tipos relacionados con lambdas o tipos que dependen de parámetros de plantilla.

Notas

Macro de prueba de características Valor Std Característica
__cpp_decltype 200707L (C++11) decltype

Palabras clave

decltype

Ejemplo

#include <cassert>
#include <iostream>
#include <type_traits>
struct A { double x; };
const A* a;
decltype(a->x) y;       // tipo de y es double (tipo declarado)
decltype((a->x)) z = y; // tipo de z es const double& (expresión lvalue)
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // el tipo de retorno depende de los parámetros de plantilla
                                      // el tipo de retorno puede deducirse desde C++14
{
    return t + u;
}
const int& getRef(const int* p) { return *p; }
static_assert(std::is_same_v<decltype(getRef), const int&(const int*)>);
auto getRefFwdBad(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdBad), int(const int*)>,
    "Solo retornar auto no es un reenvío perfecto.");
decltype(auto) getRefFwdGood(const int* p) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood), const int&(const int*)>,
    "Retornar decltype(auto) reenvía perfectamente el tipo de retorno.");
// Alternativamente:
auto getRefFwdGood1(const int* p) -> decltype(getRef(p)) { return getRef(p); }
static_assert(std::is_same_v<decltype(getRefFwdGood1), const int&(const int*)>,
    "Retornar decltype(expresión de retorno) también reenvía perfectamente el tipo de retorno.");
int main()
{
    int i = 33;
    decltype(i) j = i * 2;
    static_assert(std::is_same_v<decltype(i), decltype(j)>);
    assert(i == 33 && 66 == j);
    auto f = [i](int av, int bv) -> int { return av * bv + i; };
    auto h = [i](int av, int bv) -> int { return av * bv + i; };
    static_assert(!std::is_same_v<decltype(f), decltype(h)>,
        "El tipo de una función lambda es único y sin nombre");
    decltype(f) g = f;
    std::cout << f(3, 3) << ' ' << g(3, 3) << '\n';
}

Salida:

42 42

Referencias

Contenido extendido
  • Estándar C++23 (ISO/IEC 14882:2024):
  • 9.2.9.5 Especificadores Decltype [dcl.type.decltype]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 9.2.8.4 Especificadores Decltype [dcl.type.decltype]
  • Estándar C++17 (ISO/IEC 14882:2017):
  • TBD Especificadores Decltype [dcl.type.decltype]
  • Estándar C++14 (ISO/IEC 14882:2014):
  • TBD Especificadores Decltype [dcl.type.decltype]
  • Estándar C++11 (ISO/IEC 14882:2011):
  • TBD Especificadores Decltype [dcl.type.decltype]

Véase también

auto especificador (C++11) especifica un tipo deducido a partir de una expresión
(C++11)
obtiene una referencia a un objeto del argumento de tipo de plantilla para usar en un contexto no evaluado
(plantilla de función)
(C++11)
verifica si dos tipos son iguales
(plantilla de clase)