Reenvío de tipo de reenvío en código genérico
Para el código no genérico, como el ejemplo inicial que proporcionó, puede seleccionar manualmente para obtener una referencia como tipo de retorno:
auto const& Example(int const& i)
{
return i;
}
pero en el código genérico desea poder reenviar perfectamente un tipo de retorno sin saber si se trata de una referencia o un valor. decltype(auto)
te da esa habilidad:
template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
Retraso en la deducción del tipo de devolución en plantillas recursivas
En estas preguntas y respuestas de hace unos días, se encontró una recursión infinita durante la creación de instancias de plantilla cuando se especificó el tipo de retorno de la plantilla en decltype(iter(Int<i-1>{}))
lugar de decltype(auto)
.
template<int i>
struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i>
constexpr auto iter(Int<i>) -> decltype(auto)
{ return iter(Int<i-1>{}); }
int main() { decltype(iter(Int<10>{})) a; }
decltype(auto)
se utiliza aquí para retrasar la deducción del tipo de devolución después de que se haya establecido el polvo de la creación de instancias de plantilla.
Otros usos
También puede usarlo decltype(auto)
en otros contextos, por ejemplo, el borrador del Estándar N3936 también establece
7.1.6.4 autoespecificador [dcl.spec.auto]
1 El auto
y decltype(auto)
tipo específico ERS designar un tipo de marcador de posición que será reemplazado más tarde, ya sea por deducción a partir de un inicializador o por explícita catiónico específico con una de tipo de retorno de arrastre. El auto
especificador de tipo también se usa para indicar que una lambda es una lambda genérica.
2 El tipo de marcador de posición puede aparecer con un declarador de función en decl-specifier-seq, type-specifier-seq, conversion-function-id o trailing-return-type, en cualquier contexto en el que dicho declarador sea válido . Si el declarador de función incluye un tipo de retorno de seguimiento (8.3.5), eso especifica el tipo de retorno declarado de la función. Si el tipo de retorno declarado de la función contiene un tipo de marcador de posición, el tipo de retorno de la función se deduce de las declaraciones de retorno en el cuerpo de la función, si corresponde.
El borrador también contiene este ejemplo de inicialización variable:
int i;
int&& f();
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int
auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&
auto x5a = f(); // decltype(x5a) is int
decltype(auto) x5d = f(); // decltype(x5d) is int&&
auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i; // decltype(x7a) is int*
decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)