Encaminhamento de tipo de retorno em código genérico
Para código não genérico, como o exemplo inicial que você deu, você pode selecionar manualmente para obter uma referência como um tipo de retorno:
auto const& Example(int const& i)
{
return i;
}
mas no código genérico você deseja encaminhar perfeitamente um tipo de retorno sem saber se está lidando com uma referência ou um valor. decltype(auto)
lhe dá essa capacidade:
template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
Atraso na dedução do tipo de retorno em modelos recursivos
Nestas perguntas e respostas , há alguns dias, uma recursão infinita durante a instanciação do modelo foi encontrada quando o tipo de retorno do modelo foi especificado como em decltype(iter(Int<i-1>{}))
vez 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)
é usado aqui para atrasar a dedução do tipo de retorno após a poeira da instanciação do modelo.
Outros usos
Você também pode usar decltype(auto)
em outros contextos, por exemplo, o rascunho da norma N3936 também declara
7.1.6.4 especificador automático [dcl.spec.auto]
1 Os especificadores de tipo auto
e decltype(auto)
designam um tipo de espaço reservado que será substituído posteriormente, por dedução de um inicializador ou por especificação explícita com um tipo de retorno à direita. O auto
especificador de tipo também é usado para significar que um lambda é um lambda genérico.
2 O tipo de espaço reservado pode aparecer com um declarador de função no decl-specifier-seq, type-specifier-seq, conversion-id da função ou tipo de retorno à direita, em qualquer contexto em que esse declarador seja válido . Se o declarador da função incluir um tipo de retorno à direita (8.3.5), isso especifica o tipo de retorno declarado da função. Se o tipo de retorno declarado da função contiver um tipo de espaço reservado, o tipo de retorno da função será deduzido das instruções de retorno no corpo da função, se houver.
O rascunho também contém este exemplo de inicialização de variável:
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)